Skip to main content
Version: 1.5

Xlang Serialization

Fory Swift can exchange payloads with other Fory implementations using the xlang protocol.

let fory = Fory()

Register Types with Shared Identity​

ID-based registration​

@ForyStruct
struct Order {
var id: Int64 = 0
var amount: Double = 0
}

let fory = Fory()
try fory.register(Order.self, id: 100)

Name-based registration​

try fory.register(Order.self, name: "com.example.Order")

Xlang Rules​

  • Keep type registration mapping consistent across languages
  • Keep compatible mode enabled when independently evolving schemas. Swift enables it by default.
  • Register all user-defined concrete targets used by dynamic fields and application protocol values
  • Use an external structural serializer, a separate custom serializer, or one intentional retroactive self-target conformance for a type owned by another module

Lists and Dense Arrays​

Swift Array<T> fields map to Fory list<T> unless field metadata explicitly requests dense array<T>. Use array<T> only for one-dimensional bool or numeric data.

Fory schemaSwift field metadata sketch
list<int32>@ListField(element: .int32()) var ids: [Int32]
array<bool>@ArrayField(element: .bool) var flags: [Bool]
array<int8>@ArrayField(element: .int8) var values: [Int8]
array<int16>@ArrayField(element: .int16) var values: [Int16]
array<int32>@ArrayField(element: .int32()) var values: [Int32]
array<int64>@ArrayField(element: .int64()) var values: [Int64]
array<uint8>@ArrayField(element: .uint8) var values: [UInt8]
array<uint16>@ArrayField(element: .uint16) var values: [UInt16]
array<uint32>@ArrayField(element: .uint32()) var values: [UInt32]
array<uint64>@ArrayField(element: .uint64()) var values: [UInt64]
array<float16>@ArrayField(element: .float16) var values: [Float16]
array<bfloat16>@ArrayField(element: .bfloat16) var values: [BFloat16]
array<float32>@ArrayField(element: .float32) var values: [Float]
array<float64>@ArrayField(element: .float64) var values: [Double]

An array that uses a separate element serializer still uses normal list encoding. Use @ArrayField only for supported dense bool or numeric arrays.

External Targets​

External structural serializers produce the same xlang STRUCT, ENUM, or UNION schema and value bytes as an equivalent ordinary Swift model:

@ForyStruct(target: ThirdParty.Order.self)
struct OrderSerializer {
var id: Int64
var amount: Double
}

try fory.register(OrderSerializer.self, id: 100)

Use .with(...) in field metadata and with: at a root. See External-Type Serialization.

That explicit selection is required because the structural serializer is a separate declaration. An external type with one intentional retroactive Target == Self conformance instead uses ordinary roots, fields, and carriers.

Swift has no native serialization mode. A known @ForyUnion case has zero or one associated value. Use a struct payload for a union alternative with multiple logical fields.

Swift IDL Workflow​

Generate Swift models directly from Fory IDL/Proto/FBS inputs:

foryc schema.fdl --swift_out ./Sources/Generated

Generated Swift code includes:

  • @ForyStruct, @ForyEnum, @ForyUnion, and field/case metadata
  • Tagged union enums (associated-value enum cases)
  • ForyModule.install(_:) helpers with transitive import installation
  • toBytes / fromBytes helpers on generated types

Install the generated module before xlang serialization:

let fory = Fory(ref: true)
try Addressbook.ForyModule.install(fory)

let payload = try fory.serialize(book)
let decoded: Addressbook.AddressBook = try fory.deserialize(payload)

Run Swift IDL Integration Tests​

cd integration_tests/idl_tests
./run_swift_tests.sh

This runs Swift roundtrip matrix tests and Java peer roundtrip checks (IDL_PEER_LANG=swift).

Debugging Xlang Tests​

Enable debug output when running xlang tests:

ENABLE_FORY_DEBUG_OUTPUT=1 FORY_SWIFT_JAVA_CI=1 mvn -T16 test -Dtest=org.apache.fory.xlang.SwiftXlangTest