@@ -183,21 +183,25 @@ open class OcaRoot: CustomStringConvertible, Codable, Sendable, _OcaObjectKeyPat
183183 _ command: Ocp1Command ,
184184 from controller: any OcaController
185185 ) async throws -> Ocp1Response {
186- for (_, propertyKeyPath) in allDevicePropertyKeyPaths {
187- let property = self [ keyPath: propertyKeyPath] as! ( any OcaDevicePropertyRepresentable )
186+ guard let method = OcaDevicePropertyKeyPathCache . shared
187+ . lookupMethod ( command. methodID, for: self )
188+ else {
189+ await deviceDelegate? . logger. info ( " unknown property accessor method \( command) " )
190+ throw Ocp1Error . status ( . notImplemented)
191+ }
188192
189- if command. methodID == property. getMethodID {
190- try decodeNullCommand ( command)
191- try await ensureReadable ( by: controller, command: command)
192- return try await property. getOcp1Response ( )
193- } else if command. methodID == property. setMethodID {
194- try await ensureWritable ( by: controller, command: command)
195- try await property. set ( object: self , command: command)
196- return Ocp1Response ( )
197- }
193+ let property = self [ keyPath: method. 1 ] as! ( any OcaDevicePropertyRepresentable )
194+
195+ switch method. 0 {
196+ case . getter:
197+ try decodeNullCommand ( command)
198+ try await ensureReadable ( by: controller, command: command)
199+ return try await property. getOcp1Response ( )
200+ case . setter:
201+ try await ensureWritable ( by: controller, command: command)
202+ try await property. set ( object: self , command: command)
203+ return Ocp1Response ( )
198204 }
199- await deviceDelegate? . logger. info ( " unknown property accessor method \( command) " )
200- throw Ocp1Error . status ( . notImplemented)
201205 }
202206
203207 open func handleCommand(
@@ -482,7 +486,7 @@ extension _OcaObjectKeyPathRepresentable {
482486
483487 @OcaDevice
484488 var allDevicePropertyKeyPaths : [ String : AnyKeyPath ] {
485- OcaDeviceProperyKeyPathCache . shared. keyPaths ( for: self )
489+ OcaDevicePropertyKeyPathCache . shared. keyPaths ( for: self )
486490 }
487491
488492 var allDevicePropertyKeyPathsUncached : [ String : AnyKeyPath ] {
@@ -497,21 +501,66 @@ extension _OcaObjectKeyPathRepresentable {
497501}
498502
499503@OcaDevice
500- private final class OcaDeviceProperyKeyPathCache {
501- fileprivate static let shared = OcaDeviceProperyKeyPathCache ( )
504+ private final class OcaDevicePropertyKeyPathCache {
505+ fileprivate static let shared = OcaDevicePropertyKeyPathCache ( )
506+
507+ enum AccessorType {
508+ case getter
509+ case setter
510+ }
511+
512+ private struct CacheEntry {
513+ let keyPaths : [ String : AnyKeyPath ]
514+ let methods : [ OcaMethodID : ( AccessorType , AnyKeyPath ) ]
515+
516+ private init ( keyPaths: [ String : AnyKeyPath ] , object: some OcaRoot ) {
517+ self . keyPaths = keyPaths
518+ methods = keyPaths. reduce ( into: [ : ] ) {
519+ guard let value = object [ keyPath: $1. value] as? any OcaDevicePropertyRepresentable else {
520+ return
521+ }
522+ if let getMethodID = value. getMethodID {
523+ $0 [ getMethodID] = ( . getter, $1. value)
524+ }
525+ if let setMethodID = value. setMethodID {
526+ $0 [ setMethodID] = ( . setter, $1. value)
527+ }
528+ }
529+ }
502530
503- private var _cache = [ ObjectIdentifier: [ String: AnyKeyPath] ] ( )
531+ fileprivate init ( object: some OcaRoot ) {
532+ let keyPaths = object. allDevicePropertyKeyPathsUncached
533+ self . init ( keyPaths: keyPaths, object: object)
534+ }
535+ }
536+
537+ private var _cache = [ ObjectIdentifier: CacheEntry] ( )
538+
539+ private func addCacheEntry( for object: some OcaRoot ) -> CacheEntry {
540+ let cacheEntry = CacheEntry ( object: object)
541+ _cache [ object. _metaTypeObjectIdentifier] = cacheEntry
542+ return cacheEntry
543+ }
504544
505545 @OcaDevice
506546 fileprivate func keyPaths( for object: some OcaRoot ) -> [ String : AnyKeyPath ] {
507- let objectIdentifier = object. _metaTypeObjectIdentifier
508- if let keyPaths = _cache [ objectIdentifier] {
509- return keyPaths
547+ if let cacheEntry = _cache [ object. _metaTypeObjectIdentifier] {
548+ return cacheEntry. keyPaths
549+ }
550+
551+ return addCacheEntry ( for: object) . keyPaths
552+ }
553+
554+ @OcaDevice
555+ fileprivate func lookupMethod(
556+ _ methodID: OcaMethodID ,
557+ for object: some OcaRoot
558+ ) -> ( AccessorType , AnyKeyPath ) ? {
559+ if let cacheEntry = _cache [ object. _metaTypeObjectIdentifier] {
560+ return cacheEntry. methods [ methodID]
510561 }
511562
512- let keyPaths = object. allDevicePropertyKeyPathsUncached
513- _cache [ objectIdentifier] = keyPaths
514- return keyPaths
563+ return addCacheEntry ( for: object) . methods [ methodID]
515564 }
516565}
517566
0 commit comments