@@ -110,57 +110,15 @@ internal final class InternalDefaultLiveMap: Sendable {
110110
111111 /// Returns the value associated with a given key, following RTLM5d specification.
112112 internal func get( key: String , coreSDK: CoreSDK , delegate: LiveMapObjectPoolDelegate ) throws ( ARTErrorInfo) -> InternalLiveMapValue ? {
113- // RTLM5c: If the channel is in the DETACHED or FAILED state, the library should indicate an error with code 90001
114- try coreSDK. validateChannelState ( notIn: [ . detached, . failed] , operationDescription: " LiveMap.get " )
115-
116- // RTLM5e - Return nil if self is tombstone
117- if isTombstone {
118- return nil
119- }
120-
121- let entry = mutex. withLock {
122- mutableState. data [ key]
123- }
124-
125- // RTLM5d1: If no ObjectsMapEntry exists at the key, return undefined/null
126- guard let entry else {
127- return nil
128- }
129-
130- // RTLM5d2: If a ObjectsMapEntry exists at the key, convert it using the shared logic
131- return convertEntryToLiveMapValue ( entry, delegate: delegate)
113+ try mutableState. get ( key: key, coreSDK: coreSDK, delegate: delegate)
132114 }
133115
134116 internal func size( coreSDK: CoreSDK , delegate: LiveMapObjectPoolDelegate ) throws ( ARTErrorInfo) -> Int {
135- // RTLM10c: If the channel is in the DETACHED or FAILED state, the library should throw an ErrorInfo error with statusCode 400 and code 90001
136- try coreSDK. validateChannelState ( notIn: [ . detached, . failed] , operationDescription: " LiveMap.size " )
137-
138- return mutex. withLock {
139- // RTLM10d: Returns the number of non-tombstoned entries (per RTLM14) in the internal data map
140- mutableState. data. values. count { entry in
141- !Self. isEntryTombstoned ( entry, delegate: delegate)
142- }
143- }
117+ try mutableState. size ( coreSDK: coreSDK, delegate: delegate)
144118 }
145119
146120 internal func entries( coreSDK: CoreSDK , delegate: LiveMapObjectPoolDelegate ) throws ( ARTErrorInfo) -> [ ( key: String , value: InternalLiveMapValue ) ] {
147- // RTLM11c: If the channel is in the DETACHED or FAILED state, the library should throw an ErrorInfo error with statusCode 400 and code 90001
148- try coreSDK. validateChannelState ( notIn: [ . detached, . failed] , operationDescription: " LiveMap.entries " )
149-
150- return mutex. withLock {
151- // RTLM11d: Returns key-value pairs from the internal data map
152- // RTLM11d1: Pairs with tombstoned entries (per RTLM14) are not returned
153- var result : [ ( key: String , value: InternalLiveMapValue ) ] = [ ]
154-
155- for (key, entry) in mutableState. data where !Self. isEntryTombstoned ( entry, delegate: delegate) {
156- // Convert entry to LiveMapValue using the same logic as get(key:)
157- if let value = convertEntryToLiveMapValue ( entry, delegate: delegate) {
158- result. append ( ( key: key, value: value) )
159- }
160- }
161-
162- return result
163- }
121+ try mutableState. entries ( coreSDK: coreSDK, delegate: delegate)
164122 }
165123
166124 internal func keys( coreSDK: CoreSDK , delegate: LiveMapObjectPoolDelegate ) throws ( ARTErrorInfo) -> [ String ] {
@@ -843,90 +801,137 @@ internal final class InternalDefaultLiveMap: Sendable {
843801 return !shouldRelease
844802 }
845803 }
846- }
847804
848- // MARK: - Helper Methods
805+ /// Returns the value associated with a given key, following RTLM5d specification.
806+ internal func get( key: String , coreSDK: CoreSDK , delegate: LiveMapObjectPoolDelegate ) throws ( ARTErrorInfo) -> InternalLiveMapValue ? {
807+ // RTLM5c: If the channel is in the DETACHED or FAILED state, the library should indicate an error with code 90001
808+ try coreSDK. validateChannelState ( notIn: [ . detached, . failed] , operationDescription: " LiveMap.get " )
849809
850- /// Returns whether a map entry should be considered tombstoned, per the check described in RTLM14.
851- private static func isEntryTombstoned( _ entry: InternalObjectsMapEntry , delegate: LiveMapObjectPoolDelegate ) -> Bool {
852- // RTLM14a
853- if entry. tombstone {
854- return true
855- }
810+ // RTLM5e - Return nil if self is tombstone
811+ if liveObjectMutableState. isTombstone {
812+ return nil
813+ }
856814
857- // RTLM14c
858- if let objectId = entry. data? . objectId {
859- if let poolEntry = delegate. getObjectFromPool ( id: objectId) , poolEntry. isTombstone {
860- return true
815+ // RTLM5d1: If no ObjectsMapEntry exists at the key, return undefined/null
816+ guard let entry = data [ key] else {
817+ return nil
861818 }
819+
820+ // RTLM5d2: If a ObjectsMapEntry exists at the key, convert it using the shared logic
821+ return convertEntryToLiveMapValue ( entry, delegate: delegate)
862822 }
863823
864- // RTLM14b
865- return false
866- }
824+ internal func size ( coreSDK : CoreSDK , delegate : LiveMapObjectPoolDelegate ) throws ( ARTErrorInfo ) -> Int {
825+ // RTLM10c: If the channel is in the DETACHED or FAILED state, the library should throw an ErrorInfo error with statusCode 400 and code 90001
826+ try coreSDK . validateChannelState ( notIn : [ . detached , . failed ] , operationDescription : " LiveMap.size " )
867827
868- /// Converts an InternalObjectsMapEntry to LiveMapValue using the same logic as get(key:)
869- /// This is used by entries to ensure consistent value conversion
870- private func convertEntryToLiveMapValue( _ entry: InternalObjectsMapEntry , delegate: LiveMapObjectPoolDelegate ) -> InternalLiveMapValue ? {
871- // RTLM5d2a: If ObjectsMapEntry.tombstone is true, return undefined/null
872- if entry. tombstone == true {
873- return nil
828+ // RTLM10d: Returns the number of non-tombstoned entries (per RTLM14) in the internal data map
829+ return data. values. count { entry in
830+ !Self. isEntryTombstoned ( entry, delegate: delegate)
831+ }
874832 }
875833
876- // Handle primitive values in the order specified by RTLM5d2b through RTLM5d2e
834+ internal func entries( coreSDK: CoreSDK , delegate: LiveMapObjectPoolDelegate ) throws ( ARTErrorInfo) -> [ ( key: String , value: InternalLiveMapValue ) ] {
835+ // RTLM11c: If the channel is in the DETACHED or FAILED state, the library should throw an ErrorInfo error with statusCode 400 and code 90001
836+ try coreSDK. validateChannelState ( notIn: [ . detached, . failed] , operationDescription: " LiveMap.entries " )
877837
878- // RTLM5d2b: If ObjectsMapEntry.data.boolean exists, return it
879- if let boolean = entry. data? . boolean {
880- return . primitive( . bool( boolean) )
881- }
838+ // RTLM11d: Returns key-value pairs from the internal data map
839+ // RTLM11d1: Pairs with tombstoned entries (per RTLM14) are not returned
840+ var result : [ ( key: String , value: InternalLiveMapValue ) ] = [ ]
882841
883- // RTLM5d2c: If ObjectsMapEntry.data.bytes exists, return it
884- if let bytes = entry. data? . bytes {
885- return . primitive( . data( bytes) )
886- }
842+ for (key, entry) in data where !Self. isEntryTombstoned ( entry, delegate: delegate) {
843+ // Convert entry to LiveMapValue using the same logic as get(key:)
844+ if let value = convertEntryToLiveMapValue ( entry, delegate: delegate) {
845+ result. append ( ( key: key, value: value) )
846+ }
847+ }
887848
888- // RTLM5d2d: If ObjectsMapEntry.data.number exists, return it
889- if let number = entry. data? . number {
890- return . primitive( . number( number. doubleValue) )
849+ return result
891850 }
892851
893- // RTLM5d2e: If ObjectsMapEntry.data.string exists, return it
894- if let string = entry. data? . string {
895- return . primitive( . string( string) )
896- }
852+ // MARK: - Helper Methods
897853
898- // TODO: Needs specification (see https://github.com/ably/ably-cocoa-liveobjects-plugin/issues/46)
899- if let json = entry. data? . json {
900- switch json {
901- case let . array( array) :
902- return . primitive( . jsonArray( array) )
903- case let . object( object) :
904- return . primitive( . jsonObject( object) )
854+ /// Returns whether a map entry should be considered tombstoned, per the check described in RTLM14.
855+ private static func isEntryTombstoned( _ entry: InternalObjectsMapEntry , delegate: LiveMapObjectPoolDelegate ) -> Bool {
856+ // RTLM14a
857+ if entry. tombstone {
858+ return true
905859 }
860+
861+ // RTLM14c
862+ if let objectId = entry. data? . objectId {
863+ if let poolEntry = delegate. getObjectFromPool ( id: objectId) , poolEntry. isTombstone {
864+ return true
865+ }
866+ }
867+
868+ // RTLM14b
869+ return false
906870 }
907871
908- // RTLM5d2f: If ObjectsMapEntry.data.objectId exists, get the object stored at that objectId from the internal ObjectsPool
909- if let objectId = entry. data? . objectId {
910- // RTLM5d2f1: If an object with id objectId does not exist, return undefined/null
911- guard let poolEntry = delegate. getObjectFromPool ( id: objectId) else {
872+ /// Converts an InternalObjectsMapEntry to LiveMapValue using the same logic as get(key:)
873+ /// This is used by entries to ensure consistent value conversion
874+ private func convertEntryToLiveMapValue( _ entry: InternalObjectsMapEntry , delegate: LiveMapObjectPoolDelegate ) -> InternalLiveMapValue ? {
875+ // RTLM5d2a: If ObjectsMapEntry.tombstone is true, return undefined/null
876+ if entry. tombstone == true {
912877 return nil
913878 }
914879
915- // RTLM5d2f3: If referenced object is tombstoned, return nil
916- if poolEntry. isTombstone {
917- return nil
880+ // Handle primitive values in the order specified by RTLM5d2b through RTLM5d2e
881+
882+ // RTLM5d2b: If ObjectsMapEntry.data.boolean exists, return it
883+ if let boolean = entry. data? . boolean {
884+ return . primitive( . bool( boolean) )
918885 }
919886
920- // RTLM5d2f2: Return referenced object
921- switch poolEntry {
922- case let . map( map) :
923- return . liveMap( map)
924- case let . counter( counter) :
925- return . liveCounter( counter)
887+ // RTLM5d2c: If ObjectsMapEntry.data.bytes exists, return it
888+ if let bytes = entry. data? . bytes {
889+ return . primitive( . data( bytes) )
890+ }
891+
892+ // RTLM5d2d: If ObjectsMapEntry.data.number exists, return it
893+ if let number = entry. data? . number {
894+ return . primitive( . number( number. doubleValue) )
895+ }
896+
897+ // RTLM5d2e: If ObjectsMapEntry.data.string exists, return it
898+ if let string = entry. data? . string {
899+ return . primitive( . string( string) )
900+ }
901+
902+ // TODO: Needs specification (see https://github.com/ably/ably-cocoa-liveobjects-plugin/issues/46)
903+ if let json = entry. data? . json {
904+ switch json {
905+ case let . array( array) :
906+ return . primitive( . jsonArray( array) )
907+ case let . object( object) :
908+ return . primitive( . jsonObject( object) )
909+ }
926910 }
927- }
928911
929- // RTLM5d2g: Otherwise, return undefined/null
930- return nil
912+ // RTLM5d2f: If ObjectsMapEntry.data.objectId exists, get the object stored at that objectId from the internal ObjectsPool
913+ if let objectId = entry. data? . objectId {
914+ // RTLM5d2f1: If an object with id objectId does not exist, return undefined/null
915+ guard let poolEntry = delegate. getObjectFromPool ( id: objectId) else {
916+ return nil
917+ }
918+
919+ // RTLM5d2f3: If referenced object is tombstoned, return nil
920+ if poolEntry. isTombstone {
921+ return nil
922+ }
923+
924+ // RTLM5d2f2: Return referenced object
925+ switch poolEntry {
926+ case let . map( map) :
927+ return . liveMap( map)
928+ case let . counter( counter) :
929+ return . liveCounter( counter)
930+ }
931+ }
932+
933+ // RTLM5d2g: Otherwise, return undefined/null
934+ return nil
935+ }
931936 }
932937}
0 commit comments