77
88import Logging
99import PotentCodables
10- import PotentCBOR
1110
1211extension PlaceContents : Equatable
1312{
@@ -27,7 +26,7 @@ extension PlaceContents: Equatable
2726
2827 // Compare each component using the helper method.
2928 for (l, r) in zip ( lhsComponents, rhsComponents) {
30- if ! l. value. isEqualTo ( r. value) {
29+ if l. value != r. value {
3130 return false
3231 }
3332 }
@@ -63,9 +62,11 @@ public final class ComponentRegistry
6362
6463/// `AnyComponent` lets AlloPlace only store and forward type-erased value trees of Components, while client code can use `decoded()` to receive the real concrete Component type.
6564@MainActor
66- public struct AnyComponent : Component {
67- public static func == ( lhs: AnyComponent , rhs: AnyComponent ) -> Bool {
68- return lhs. treeValue == rhs. treeValue
65+ public struct AnyComponent : Codable , Equatable
66+ {
67+ public static func == ( lhs: AnyComponent , rhs: AnyComponent ) -> Bool
68+ {
69+ return lhs. anyValue == rhs. anyValue
6970 }
7071
7172 // The concrete Component type we use
@@ -76,47 +77,47 @@ public struct AnyComponent: Component {
7677 // ... or nil, if the type is not compiled into this binary and registered with the ComponentRegistry.
7778 public func decodedIfAvailable( ) -> ( any Component ) ?
7879 {
79- guard
80- let type = ComponentRegistry . shared. component ( for: componentTypeId) ,
81- let base = try ? CBORDecoder ( ) . decodeTree ( type. self, from: treeValue)
80+ guard let type = ComponentRegistry . shared. component ( for: componentTypeId)
8281 else { return nil }
83- return base
82+ return try ! AnyValueDecoder . default . decode ( type , from : anyValue ) // if the type is registered, it should decode
8483 }
85- /* public func decodeCustom() -> CustomComponent
84+ public func decodeCustom( ) -> CustomComponent
8685 {
87- return CustomComponent(typeId: componentTypeId, fields: treeValue. anyValue)
88- }*/
86+ return CustomComponent ( typeId: componentTypeId, fields: anyValue)
87+ }
8988
9089 // The type-erased content, available whether the concrete type is available or not
91- public var treeValue : CBOR
90+ public var anyValue : AnyValue
9291 public var componentTypeId : String
9392
94- public init ( _ base : some Component )
93+ func indentedDescription ( _ prefix : String ) -> String
9594 {
96- componentTypeId = type ( of: base) . componentTypeId
97- treeValue = try ! CBOREncoder ( ) . encodeTree ( base)
95+ return decodedIfAvailable ( ) ? . indentedDescription ( prefix) ?? " \( prefix) AnyComponent< \( componentTypeId) >: \( anyValue. description) "
9896 }
9997
100- public init ( from decoder: Decoder ) throws
98+ // MARK: Codable
99+ public init ( _ base: some Component )
101100 {
102- let treeContainer = try decoder. singleValueContainer ( ) as! TreeValueDecodingContainer
103- guard
104- let cbor = treeContainer. decodeTreeValue ( ) as? CBOR ,
105- let map = cbor. mapValue,
106- let ctypeId = cbor. componentTypeId? . utf8StringValue
107- else
108- {
109- throw DecodingError . dataCorruptedError ( in: treeContainer,
110- debugDescription: " Invalid Component CBOR " )
111- }
112- treeValue = cbor
113- componentTypeId = ctypeId
101+ componentTypeId = type ( of: base) . componentTypeId
102+ anyValue = try ! AnyValueEncoder ( ) . encode ( base)
114103 }
115104
116- public func encode( to encoder: Encoder ) throws
105+ // optimization idea: store CBOR treeValue instead of AnyValue to avoid two tree walks
106+ private enum CodingKeys : String , CodingKey
117107 {
118- var treeContainer = try encoder. singleValueContainer ( )
119- try treeContainer. encode ( treeValue)
108+ case componentTypeId
109+ case value
110+ }
111+ public init ( from decoder: Decoder ) throws {
112+ let container = try decoder. container ( keyedBy: CodingKeys . self)
113+ componentTypeId = try container. decode ( String . self, forKey: . componentTypeId)
114+ anyValue = try container. decode ( AnyValue . self, forKey: . value)
115+ }
116+
117+ public func encode( to encoder: Encoder ) throws {
118+ var container = encoder. container ( keyedBy: CodingKeys . self)
119+ try container. encode ( componentTypeId, forKey: . componentTypeId)
120+ try container. encode ( anyValue, forKey: . value)
120121 }
121122}
122123
@@ -148,15 +149,15 @@ extension PlaceChange: Codable
148149 try container. encode ( ChangeKind . componentAdded, forKey: . kind)
149150 try container. encode ( eid, forKey: . entityID)
150151 // Wrap the component so we can encode it generically.
151- try container. encode ( AnyComponent ( component) , forKey: . component)
152+ try container. encode ( component, forKey: . component)
152153 case . componentUpdated( let eid, let component) :
153154 try container. encode ( ChangeKind . componentUpdated, forKey: . kind)
154155 try container. encode ( eid, forKey: . entityID)
155- try container. encode ( AnyComponent ( component) , forKey: . component)
156+ try container. encode ( component, forKey: . component)
156157 case . componentRemoved( let edata, let component) :
157158 try container. encode ( ChangeKind . componentRemoved, forKey: . kind)
158159 try container. encode ( edata, forKey: . entity)
159- try container. encode ( AnyComponent ( component) , forKey: . component)
160+ try container. encode ( component, forKey: . component)
160161 }
161162 }
162163
0 commit comments