Custom Serializers
For types that cannot or should not use @ForyObject, implement Serializer manually.
When to Use Custom Serializers
- External types with strict wire compatibility requirements
- Specialized compact encodings
- Legacy payload migration paths
- Highly tuned hot-path serialization
Implementing Serializer
import Foundation
import Fory
struct UUIDBox: Serializer, Equatable {
var value: UUID = UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
static func foryDefault() -> UUIDBox {
UUIDBox()
}
static var staticTypeId: ForyTypeId {
.ext
}
func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
_ = hasGenerics
try value.uuidString.foryWriteData(context, hasGenerics: false)
}
static func foryReadData(_ context: ReadContext) throws -> UUIDBox {
let raw = try String.foryReadData(context)
guard let uuid = UUID(uuidString: raw) else {
throw ForyError.invalidData("invalid UUID string: \(raw)")
}
return UUIDBox(value: uuid)
}
}
Register and Use
let fory = Fory()
fory.register(UUIDBox.self, id: 300)
let input = UUIDBox(value: UUID())
let data = try fory.serialize(input)
let output: UUIDBox = try fory.deserialize(data)
assert(input == output)
Choosing staticTypeId
For manually implemented custom types, use staticTypeId that matches the wire kind you are implementing.
Typical choices:
.structType: regular structured object.enumType/.typedUnion: enum-like values.ext: extension/custom kind