Hi Tera,
I more or less fine-tuned the identity of value types by defining this protocol in my library:
public protocol GIdentifiable<GID> {
associatedtype GID : Hashable
var gID: Self.GID? { get }
}
extension GIdentifiable where Self:Identifiable {
public var gID: Self.ID? { id }
}
Here's how the code from your first example can be implemented in GraphCodable:
protocol Node: Identifiable, GIdentifiable, GCodable {
var name: String { get }
var code: [Int]? { get }
var children: [Self] { get }
init(name: String, code:[Int]?, children: [Self])
}
fileprivate enum Key : String { case name, code, children }
extension Node {
init(name: String, code:[Int] ) {
self.init(name: name, code:code, children: [])
}
init(name: String ) {
self.init(name: name, code:nil, children: [])
}
init(from decoder: GDecoder) throws {
self.init(
name: try decoder.decode(for: Key.name),
code: try decoder.decode(for: Key.code),
children: try decoder.decode(for: Key.children)
)
}
func encode(to encoder: GEncoder) throws {
try encoder.encode( name, for: Key.name )
try encoder.encode( code, for: Key.code )
try encoder.encode( children, for: Key.children )
}
}
struct NodeS : Node {
private (set) var id = UUID()
var name : String { willSet { id = UUID() } }
var code : [Int]? { willSet { id = UUID() } }
var children : [NodeS] { willSet { id = UUID() } }
init(name: String, code:[Int]?, children: [NodeS] ) {
self.name = name
self.code = code
self.children = children
}
}
final class NodeC : Node {
var name : String
var code : [Int]?
var children : [NodeC]
init(name: String, code:[Int]?, children: [NodeC] ) {
self.name = name
self.code = code
self.children = children
}
}
func nodeTest<NodeType: Node>(_ nodeType: NodeType.Type) throws {
print(type(of: nodeType))
let code = [1,2,3]
let a = NodeType(name: "a", code:code)
let b = NodeType(name: "b", code:code)
let c = NodeType(name: "c", code:code, children: [a, b])
let d = NodeType(name: "d", code:code, children: [c, a])
let inRoot = [a,b,c,d]
let data = try GraphEncoder().encode( inRoot )
let outRoot = try GraphDecoder().decode( type( of:inRoot ), from: data )
print("• Decoded Root Dump ••••••••••••")
print( try GraphEncoder().dump( outRoot ) )
}
try nodeTest( NodeS.self )
try nodeTest( NodeC.self )
And this is the output after archiving and dearchiving:
NodeS.Type
• Decoded Root Dump ••••••••••••
== BODY ==========================================================
- VAL1000
- VAL1001
+ "name": "a"
+ "code": VAL1002
- 1
- 2
- 3
.
+ "children": VAL1003
.
.
- VAL1004
+ "name": "b"
+ "code": PTR1002
+ "children": PTR1003
.
- VAL1005
+ "name": "c"
+ "code": PTR1002
+ "children": VAL1006
- PTR1001
- PTR1004
.
.
- VAL1007
+ "name": "d"
+ "code": PTR1002
+ "children": VAL1008
- PTR1005
- PTR1001
.
.
.
==================================================================
NodeC.Type
• Decoded Root Dump ••••••••••••
== BODY ==========================================================
- VAL1000
- REF1001 MyGraphCodableApp.NodeC
+ "name": "a"
+ "code": VAL1002
- 1
- 2
- 3
.
+ "children": VAL1003
.
.
- REF1004 MyGraphCodableApp.NodeC
+ "name": "b"
+ "code": PTR1002
+ "children": PTR1003
.
- REF1005 MyGraphCodableApp.NodeC
+ "name": "c"
+ "code": PTR1002
+ "children": VAL1006
- PTR1001
- PTR1004
.
.
- REF1007 MyGraphCodableApp.NodeC
+ "name": "d"
+ "code": PTR1002
+ "children": VAL1008
- PTR1005
- PTR1001
.
.
.
==================================================================
Now, as was already the case for reference types, there is no duplication of data even with value types, provided they implement the GIdentifiable
protocol.