Skip to content

Commit 98b9b5d

Browse files
committed
encode OcaRoot references as object numbers in dataset serialization
OcaRoot.encode(to:) now always encodes just the objectNumber, for all encoder types. Deep serialization of object state is already handled by OcaBlock.serialize() which calls serialize() on each action object directly. This means any @OcaDeviceProperty that holds OcaRoot references (e.g. OcaGroup.members) will automatically serialize as OcaONos rather than attempting to encode full object state. On the deserialization side, OcaDeviceProperty.set(object:jsonValue:) now resolves [OcaONo] and OcaONo values back to objects via the device object registry. Note: deserialization assumes that the referenced objects have already been instantiated (i.e. the containing block's action objects are deserialized before any property referencing them). This ordering is currently guaranteed by the block deserialization traversal but may need explicit handling if that assumption changes.
1 parent 222f109 commit 98b9b5d

File tree

2 files changed

+24
-27
lines changed

2 files changed

+24
-27
lines changed

Sources/SwiftOCADevice/OCC/ControlClasses/Root.swift

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -142,36 +142,15 @@ open class OcaRoot: CustomStringConvertible, Codable, Sendable, _OcaObjectKeyPat
142142
}
143143

144144
public nonisolated func encode(to encoder: Encoder) throws {
145-
if encoder._isOcp1Encoder {
146-
var container = encoder.unkeyedContainer()
147-
try container.encode(objectNumber)
148-
} else {
149-
var container = encoder.container(keyedBy: CodingKeys.self)
150-
try container.encode(Self.classID.description, forKey: .classIdentification)
151-
try container.encode(objectNumber, forKey: .objectNumber)
152-
try container.encode(lockable, forKey: .lockable)
153-
try container.encode(role, forKey: .role)
154-
}
145+
// Always encode as just the object number. Deep serialization of object
146+
// state is handled by OcaBlock.serialize() which calls serialize() on
147+
// each action object directly, not through Codable.
148+
var container = encoder.unkeyedContainer()
149+
try container.encode(objectNumber)
155150
}
156151

157152
public required nonisolated init(from decoder: Decoder) throws {
158-
if decoder._isOcp1Decoder {
159-
throw Ocp1Error.notImplemented
160-
} else {
161-
let container = try decoder.container(keyedBy: CodingKeys.self)
162-
let classID = try OcaClassID(
163-
container
164-
.decode(String.self, forKey: .classIdentification)
165-
)
166-
guard classID == Self.classID else {
167-
throw Ocp1Error.objectClassMismatch
168-
}
169-
170-
objectNumber = try container.decode(OcaONo.self, forKey: .objectNumber)
171-
lockable = try container.decode(OcaBoolean.self, forKey: .lockable)
172-
role = try container.decode(OcaString.self, forKey: .role)
173-
Task { @OcaDevice in deviceDelegate = OcaDevice.shared }
174-
}
153+
throw Ocp1Error.notImplemented
175154
}
176155

177156
public nonisolated var description: String {

Sources/SwiftOCADevice/OCC/PropertyTypes/DeviceProperty.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,24 @@ public struct OcaDeviceProperty<Value: Codable & Sendable>: OcaDevicePropertyRep
191191
throw Ocp1Error.status(.badFormat)
192192
}
193193
await setAndNotifySubscribers(object: object, objects)
194+
} else if let objectNumbers = jsonValue as? [OcaONo] {
195+
// resolve an array of object numbers to objects
196+
var objects = [OcaRoot]()
197+
for oNo in objectNumbers {
198+
if let resolved = await device.objects[oNo] {
199+
objects.append(resolved)
200+
}
201+
}
202+
guard let objects = objects as? Value else {
203+
throw Ocp1Error.status(.badFormat)
204+
}
205+
await setAndNotifySubscribers(object: object, objects)
206+
} else if let objectNumber = jsonValue as? OcaONo {
207+
// resolve a single object number to an object
208+
guard let resolved = await device.objects[objectNumber] as? Value else {
209+
throw Ocp1Error.status(.badFormat)
210+
}
211+
await setAndNotifySubscribers(object: object, resolved)
194212
} else {
195213
if JSONSerialization.isValidJSONObject(subject.value) {
196214
// Value is a JSON-native type (e.g. dictionary, array) — direct cast

0 commit comments

Comments
 (0)