Skip to content

Commit afb3f66

Browse files
committed
cache device property method IDs
1 parent 743038a commit afb3f66

File tree

1 file changed

+72
-23
lines changed
  • Sources/SwiftOCADevice/OCC/ControlClasses

1 file changed

+72
-23
lines changed

Sources/SwiftOCADevice/OCC/ControlClasses/Root.swift

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)