This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new f9faf8eae refactor(swift): refine swift api (#3554)
f9faf8eae is described below
commit f9faf8eae6feb15f4e4e858d725007e558faeebf
Author: Shawn Yang <[email protected]>
AuthorDate: Sat Apr 11 00:42:03 2026 +0800
refactor(swift): refine swift api (#3554)
## Why?
## What does this PR do?
## Related issues
## AI Contribution Checklist
- [ ] Substantial AI assistance was used in this PR: `yes` / `no`
- [ ] If `yes`, I included a completed [AI Contribution
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
in this PR description and the required `AI Usage Disclosure`.
- [ ] If `yes`, my PR description includes the required `ai_review`
summary and screenshot evidence of the final clean AI review results
from both fresh reviewers on the current PR diff or current HEAD after
the latest code changes.
## Does this PR introduce any user-facing change?
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
---
swift/Sources/Fory/AnySerializer.swift | 74 +++++++--------
swift/Sources/Fory/Fory.swift | 124 +++++++++-----------------
swift/Sources/Fory/ReadContext.swift | 20 ++---
swift/Sources/Fory/TypeResolver.swift | 17 +++-
swift/Sources/Fory/WriteContext.swift | 24 ++---
swift/Sources/ForyMacro/ForyObjectMacro.swift | 16 ++--
swift/Tests/ForyTests/ForySwiftTests.swift | 21 +++++
7 files changed, 144 insertions(+), 152 deletions(-)
diff --git a/swift/Sources/Fory/AnySerializer.swift
b/swift/Sources/Fory/AnySerializer.swift
index d47e2c6de..cd2fda808 100644
--- a/swift/Sources/Fory/AnySerializer.swift
+++ b/swift/Sources/Fory/AnySerializer.swift
@@ -117,15 +117,15 @@ extension Optional: OptionalTypeMarker {
static var noneValue: Wrapped? { nil }
}
-struct DynamicAnyValue: Serializer {
+struct SerializableAny: Serializer {
var value: Any = ForyAnyNullValue()
init(_ value: Any) {
self.value = value
}
- static func foryDefault() -> DynamicAnyValue {
- DynamicAnyValue(ForyAnyNullValue())
+ static func foryDefault() -> SerializableAny {
+ SerializableAny(ForyAnyNullValue())
}
static var staticTypeId: TypeId {
@@ -144,7 +144,7 @@ struct DynamicAnyValue: Serializer {
value is ForyAnyNullValue
}
- static func wrapped(_ value: Any?) -> DynamicAnyValue {
+ static func wrapped(_ value: Any?) -> SerializableAny {
guard let value else {
return .foryDefault()
}
@@ -154,7 +154,7 @@ struct DynamicAnyValue: Serializer {
if unwrapped is NSNull {
return .foryDefault()
}
- return DynamicAnyValue(unwrapped)
+ return SerializableAny(unwrapped)
}
func anyValue() -> Any? {
@@ -172,19 +172,19 @@ struct DynamicAnyValue: Serializer {
try writeAnyPayload(value, context: context, hasGenerics: hasGenerics)
}
- static func foryReadData(_ context: ReadContext) throws -> DynamicAnyValue
{
+ static func foryReadData(_ context: ReadContext) throws -> SerializableAny
{
_ = context
throw ForyError.invalidData(
"dynamic Any read requires type info; foryReadData should not be
called directly"
)
}
- static func foryReadCompatibleData(_ context: ReadContext, remoteTypeInfo:
TypeInfo) throws -> DynamicAnyValue {
+ static func foryReadCompatibleData(_ context: ReadContext, remoteTypeInfo:
TypeInfo) throws -> SerializableAny {
let typeInfo = remoteTypeInfo
if typeInfo.typeID == .none {
return .foryDefault()
}
- return DynamicAnyValue(try context.readAnyValue(typeInfo: typeInfo))
+ return SerializableAny(try context.readAnyValue(typeInfo: typeInfo))
}
static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
@@ -234,7 +234,7 @@ struct DynamicAnyValue: Serializer {
_ context: ReadContext,
refMode: RefMode,
readTypeInfo: Bool
- ) throws -> DynamicAnyValue {
+ ) throws -> SerializableAny {
@inline(__always)
func requireDynamicTypeInfo() throws -> TypeInfo {
if readTypeInfo {
@@ -261,13 +261,13 @@ struct DynamicAnyValue: Serializer {
case .ref:
let refID = try context.buffer.readVarUInt32()
let referenced = try context.refReader.readRefValue(refID)
- if let value = referenced as? DynamicAnyValue {
+ if let value = referenced as? SerializableAny {
return value
}
if referenced is NSNull {
return .foryDefault()
}
- return DynamicAnyValue(referenced)
+ return SerializableAny(referenced)
case .refValue:
let reservedRefID = context.trackRef ?
context.refReader.reserveRefID() : nil
let remoteTypeInfo = try requireDynamicTypeInfo()
@@ -343,22 +343,22 @@ private func writeAnyPayload(_ value: Any, context:
WriteContext, hasGenerics: B
return
}
if let list = value as? [Any] {
- try writeAnyList(list, context: context, refMode: .none, hasGenerics:
hasGenerics)
+ try writeListOfAny(list, context: context, refMode: .none,
hasGenerics: hasGenerics)
return
}
if let map = value as? [String: Any] {
// Always include key type info for dynamic map payload.
- try writeStringAnyMap(map, context: context, refMode: .none,
hasGenerics: false)
+ try writeMapStringToAny(map, context: context, refMode: .none,
hasGenerics: false)
return
}
if let map = value as? [Int32: Any] {
// Always include key type info for dynamic map payload.
- try writeInt32AnyMap(map, context: context, refMode: .none,
hasGenerics: false)
+ try writeMapInt32ToAny(map, context: context, refMode: .none,
hasGenerics: false)
return
}
if let map = value as? [AnyHashable: Any] {
// Always include key type info for dynamic map payload.
- try writeAnyHashableAnyMap(map, context: context, refMode: .none,
hasGenerics: false)
+ try writeMapAnyHashableToAny(map, context: context, refMode: .none,
hasGenerics: false)
return
}
throw ForyError.invalidData("unsupported dynamic Any runtime type
\(type(of: value))")
@@ -401,7 +401,7 @@ public func writeAny(
writeTypeInfo: Bool = true,
hasGenerics: Bool = false
) throws {
- try DynamicAnyValue.wrapped(value).foryWrite(
+ try SerializableAny.wrapped(value).foryWrite(
context,
refMode: refMode,
writeTypeInfo: writeTypeInfo,
@@ -414,17 +414,17 @@ public func readAny(
refMode: RefMode,
readTypeInfo: Bool = true
) throws -> Any? {
- try DynamicAnyValue.foryRead(context, refMode: refMode, readTypeInfo:
readTypeInfo).anyValue()
+ try SerializableAny.foryRead(context, refMode: refMode, readTypeInfo:
readTypeInfo).anyValue()
}
-public func writeAnyList(
+public func writeListOfAny(
_ value: [Any]?,
context: WriteContext,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.map { DynamicAnyValue.wrapped($0) }
+ let wrapped = value?.map { SerializableAny.wrapped($0) }
try wrapped.foryWrite(
context,
refMode: refMode,
@@ -433,12 +433,12 @@ public func writeAnyList(
)
}
-public func readAnyList(
+public func readListOfAny(
context: ReadContext,
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [Any]? {
- let wrapped: [DynamicAnyValue]? = try [DynamicAnyValue]?.foryRead(
+ let wrapped: [SerializableAny]? = try [SerializableAny]?.foryRead(
context,
refMode: refMode,
readTypeInfo: readTypeInfo
@@ -446,15 +446,15 @@ public func readAnyList(
return wrapped?.map { $0.anyValueForCollection() }
}
-public func writeStringAnyMap(
+public func writeMapStringToAny(
_ value: [String: Any]?,
context: WriteContext,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.reduce(into: [String: DynamicAnyValue]()) { result,
pair in
- result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+ let wrapped = value?.reduce(into: [String: SerializableAny]()) { result,
pair in
+ result[pair.key] = SerializableAny.wrapped(pair.value)
}
try wrapped.foryWrite(
context,
@@ -464,12 +464,12 @@ public func writeStringAnyMap(
)
}
-public func readStringAnyMap(
+public func readMapStringToAny(
context: ReadContext,
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [String: Any]? {
- let wrapped: [String: DynamicAnyValue]? = try [String:
DynamicAnyValue]?.foryRead(
+ let wrapped: [String: SerializableAny]? = try [String:
SerializableAny]?.foryRead(
context,
refMode: refMode,
readTypeInfo: readTypeInfo
@@ -485,15 +485,15 @@ public func readStringAnyMap(
return map
}
-public func writeInt32AnyMap(
+public func writeMapInt32ToAny(
_ value: [Int32: Any]?,
context: WriteContext,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.reduce(into: [Int32: DynamicAnyValue]()) { result,
pair in
- result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+ let wrapped = value?.reduce(into: [Int32: SerializableAny]()) { result,
pair in
+ result[pair.key] = SerializableAny.wrapped(pair.value)
}
try wrapped.foryWrite(
context,
@@ -503,12 +503,12 @@ public func writeInt32AnyMap(
)
}
-public func readInt32AnyMap(
+public func readMapInt32ToAny(
context: ReadContext,
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [Int32: Any]? {
- let wrapped: [Int32: DynamicAnyValue]? = try [Int32:
DynamicAnyValue]?.foryRead(
+ let wrapped: [Int32: SerializableAny]? = try [Int32:
SerializableAny]?.foryRead(
context,
refMode: refMode,
readTypeInfo: readTypeInfo
@@ -524,15 +524,15 @@ public func readInt32AnyMap(
return map
}
-public func writeAnyHashableAnyMap(
+public func writeMapAnyHashableToAny(
_ value: [AnyHashable: Any]?,
context: WriteContext,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.reduce(into: [AnyHashable: DynamicAnyValue]()) {
result, pair in
- result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+ let wrapped = value?.reduce(into: [AnyHashable: SerializableAny]()) {
result, pair in
+ result[pair.key] = SerializableAny.wrapped(pair.value)
}
try wrapped.foryWrite(
context,
@@ -542,12 +542,12 @@ public func writeAnyHashableAnyMap(
)
}
-public func readAnyHashableAnyMap(
+public func readMapAnyHashableToAny(
context: ReadContext,
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [AnyHashable: Any]? {
- let wrapped: [AnyHashable: DynamicAnyValue]? = try [AnyHashable:
DynamicAnyValue]?.foryRead(
+ let wrapped: [AnyHashable: SerializableAny]? = try [AnyHashable:
SerializableAny]?.foryRead(
context,
refMode: refMode,
readTypeInfo: readTypeInfo
@@ -564,7 +564,7 @@ public func readAnyHashableAnyMap(
}
func readDynamicAnyMapValue(context: ReadContext) throws -> Any {
- let map = try readAnyHashableAnyMap(context: context, refMode: .none) ??
[:]
+ let map = try readMapAnyHashableToAny(context: context, refMode: .none) ??
[:]
if map.isEmpty {
return [String: Any]()
}
diff --git a/swift/Sources/Fory/Fory.swift b/swift/Sources/Fory/Fory.swift
index 6f7a7b6b8..e560c04e4 100644
--- a/swift/Sources/Fory/Fory.swift
+++ b/swift/Sources/Fory/Fory.swift
@@ -17,7 +17,7 @@
import Foundation
-public struct ForyConfig {
+public struct Config {
public var xlang: Bool
public var trackRef: Bool
public var compatible: Bool
@@ -30,40 +30,20 @@ public struct ForyConfig {
xlang: Bool = true,
trackRef: Bool = false,
compatible: Bool = false,
- checkClassVersion: Bool = true,
+ checkClassVersion: Bool? = nil,
maxCollectionSize: Int = 1_000_000,
maxBinarySize: Int = 64 * 1024 * 1024,
maxDepth: Int = 5
) {
+ let effectiveCheckClassVersion = checkClassVersion ?? (xlang &&
!compatible)
self.xlang = xlang
self.trackRef = trackRef
self.compatible = compatible
- self.checkClassVersion = checkClassVersion
+ self.checkClassVersion = effectiveCheckClassVersion
self.maxCollectionSize = maxCollectionSize
self.maxBinarySize = maxBinarySize
self.maxDepth = maxDepth
}
-
- static func resolved(
- xlang: Bool = true,
- trackRef: Bool = false,
- compatible: Bool = false,
- checkClassVersion: Bool? = nil,
- maxCollectionSize: Int = 1_000_000,
- maxBinarySize: Int = 64 * 1024 * 1024,
- maxDepth: Int = 5
- ) -> ForyConfig {
- let effectiveCheckClassVersion = checkClassVersion ?? (xlang &&
!compatible)
- return ForyConfig(
- xlang: xlang,
- trackRef: trackRef,
- compatible: compatible,
- checkClassVersion: effectiveCheckClassVersion,
- maxCollectionSize: maxCollectionSize,
- maxBinarySize: maxBinarySize,
- maxDepth: maxDepth
- )
- }
}
/// Single-threaded Fory runtime.
@@ -72,12 +52,12 @@ public struct ForyConfig {
/// reusable read/write context pair and must not be used concurrently from
/// multiple threads.
public final class Fory {
- public let config: ForyConfig
+ public let config: Config
let typeResolver: TypeResolver
private let writeContext: WriteContext
private let readContext: ReadContext
- public init(
+ public convenience init(
xlang: Bool = true,
trackRef: Bool = false,
compatible: Bool = false,
@@ -86,7 +66,7 @@ public final class Fory {
maxBinarySize: Int = 64 * 1024 * 1024,
maxDepth: Int = 5
) {
- self.config = ForyConfig.resolved(
+ self.init(config: Config(
xlang: xlang,
trackRef: trackRef,
compatible: compatible,
@@ -94,7 +74,11 @@ public final class Fory {
maxCollectionSize: maxCollectionSize,
maxBinarySize: maxBinarySize,
maxDepth: maxDepth
- )
+ ))
+ }
+
+ public init(config: Config) {
+ self.config = config
self.typeResolver = TypeResolver(trackRef: self.config.trackRef)
self.writeContext = WriteContext(
buffer: ByteBuffer(),
@@ -117,18 +101,6 @@ public final class Fory {
)
}
- public convenience init(config: ForyConfig) {
- self.init(
- xlang: config.xlang,
- trackRef: config.trackRef,
- compatible: config.compatible,
- checkClassVersion: config.checkClassVersion,
- maxCollectionSize: config.maxCollectionSize,
- maxBinarySize: config.maxBinarySize,
- maxDepth: config.maxDepth
- )
- }
-
public func register<T: Serializer>(_ type: T.Type, id: UInt32) {
typeResolver.register(type, id: id)
}
@@ -142,44 +114,24 @@ public final class Fory {
}
public func serialize<T: Serializer>(_ value: T) throws -> Data {
- let context = writeContext
- context.buffer.clear()
- defer {
- context.reset()
- }
-
- writeHead(buffer: context.buffer, isNone: value.foryIsNone)
- if !value.foryIsNone {
+ try serializeRoot(isNone: value.foryIsNone) { context in
try writeRootTypedValue(value, context: context)
}
- return context.buffer.copyToData()
}
public func deserialize<T: Serializer>(_ data: Data, as _: T.Type =
T.self) throws -> T {
- try withReusableReadContext(data: data) { context in
- if try readHead(buffer: context.buffer) {
- return T.foryDefault()
- }
- let value: T = try readRootTypedValue(context: context)
- if context.buffer.remaining != 0 {
- throw ForyError.invalidData("unexpected trailing bytes at
root: \(context.buffer.remaining)")
- }
- return value
+ try deserializeRoot(
+ data: data,
+ nilValue: T.foryDefault()
+ ) { context in
+ try readRootTypedValue(context: context)
}
}
public func serialize<T: Serializer>(_ value: T, to buffer: inout Data)
throws {
- let context = writeContext
- context.buffer.clear()
- defer {
- context.reset()
- }
-
- writeHead(buffer: context.buffer, isNone: value.foryIsNone)
- if !value.foryIsNone {
+ try appendSerializedRoot(to: &buffer, isNone: value.foryIsNone) {
context in
try writeRootTypedValue(value, context: context)
}
- buffer.append(contentsOf:
context.buffer.storage.prefix(context.buffer.count))
}
public func deserialize<T: Serializer>(from buffer: ByteBuffer, as _:
T.Type = T.self) throws -> T {
@@ -254,7 +206,7 @@ public final class Fory {
@_disfavoredOverload
public func serialize(_ value: [Any]) throws -> Data {
try serializeRoot(isNone: false) { context in
- try context.writeAnyList(value, refMode: refMode, writeTypeInfo:
true, hasGenerics: false)
+ try context.writeListOfAny(value, refMode: refMode, writeTypeInfo:
true, hasGenerics: false)
}
}
@@ -264,14 +216,14 @@ public final class Fory {
data: data,
nilValue: []
) { context in
- try context.readAnyList(refMode: refMode, readTypeInfo: true) ?? []
+ try context.readListOfAny(refMode: refMode, readTypeInfo: true) ??
[]
}
}
@_disfavoredOverload
public func serialize(_ value: [String: Any]) throws -> Data {
try serializeRoot(isNone: false) { context in
- try context.writeStringAnyMap(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
+ try context.writeMapStringToAny(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
}
}
@@ -281,14 +233,14 @@ public final class Fory {
data: data,
nilValue: [:]
) { context in
- try context.readStringAnyMap(refMode: refMode, readTypeInfo: true)
?? [:]
+ try context.readMapStringToAny(refMode: refMode, readTypeInfo:
true) ?? [:]
}
}
@_disfavoredOverload
public func serialize(_ value: [Int32: Any]) throws -> Data {
try serializeRoot(isNone: false) { context in
- try context.writeInt32AnyMap(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
+ try context.writeMapInt32ToAny(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
}
}
@@ -298,14 +250,14 @@ public final class Fory {
data: data,
nilValue: [:]
) { context in
- try context.readInt32AnyMap(refMode: refMode, readTypeInfo: true)
?? [:]
+ try context.readMapInt32ToAny(refMode: refMode, readTypeInfo:
true) ?? [:]
}
}
@_disfavoredOverload
public func serialize(_ value: [AnyHashable: Any]) throws -> Data {
try serializeRoot(isNone: false) { context in
- try context.writeAnyHashableAnyMap(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
+ try context.writeMapAnyHashableToAny(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
}
}
@@ -315,14 +267,14 @@ public final class Fory {
data: data,
nilValue: [:]
) { context in
- try context.readAnyHashableAnyMap(refMode: refMode, readTypeInfo:
true) ?? [:]
+ try context.readMapAnyHashableToAny(refMode: refMode,
readTypeInfo: true) ?? [:]
}
}
@_disfavoredOverload
public func serialize(_ value: [Any], to buffer: inout Data) throws {
try appendSerializedRoot(to: &buffer, isNone: false) { context in
- try context.writeAnyList(value, refMode: refMode, writeTypeInfo:
true, hasGenerics: false)
+ try context.writeListOfAny(value, refMode: refMode, writeTypeInfo:
true, hasGenerics: false)
}
}
@@ -395,14 +347,14 @@ public final class Fory {
from: buffer,
nilValue: []
) { context in
- try context.readAnyList(refMode: refMode, readTypeInfo: true) ?? []
+ try context.readListOfAny(refMode: refMode, readTypeInfo: true) ??
[]
}
}
@_disfavoredOverload
public func serialize(_ value: [String: Any], to buffer: inout Data)
throws {
try appendSerializedRoot(to: &buffer, isNone: false) { context in
- try context.writeStringAnyMap(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
+ try context.writeMapStringToAny(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
}
}
@@ -412,21 +364,21 @@ public final class Fory {
from: buffer,
nilValue: [:]
) { context in
- try context.readStringAnyMap(refMode: refMode, readTypeInfo: true)
?? [:]
+ try context.readMapStringToAny(refMode: refMode, readTypeInfo:
true) ?? [:]
}
}
@_disfavoredOverload
public func serialize(_ value: [Int32: Any], to buffer: inout Data) throws
{
try appendSerializedRoot(to: &buffer, isNone: false) { context in
- try context.writeInt32AnyMap(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
+ try context.writeMapInt32ToAny(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
}
}
@_disfavoredOverload
public func serialize(_ value: [AnyHashable: Any], to buffer: inout Data)
throws {
try appendSerializedRoot(to: &buffer, isNone: false) { context in
- try context.writeAnyHashableAnyMap(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
+ try context.writeMapAnyHashableToAny(value, refMode: refMode,
writeTypeInfo: true, hasGenerics: false)
}
}
@@ -436,7 +388,7 @@ public final class Fory {
from: buffer,
nilValue: [:]
) { context in
- try context.readInt32AnyMap(refMode: refMode, readTypeInfo: true)
?? [:]
+ try context.readMapInt32ToAny(refMode: refMode, readTypeInfo:
true) ?? [:]
}
}
@@ -446,7 +398,7 @@ public final class Fory {
from: buffer,
nilValue: [:]
) { context in
- try context.readAnyHashableAnyMap(refMode: refMode, readTypeInfo:
true) ?? [:]
+ try context.readMapAnyHashableToAny(refMode: refMode,
readTypeInfo: true) ?? [:]
}
}
@@ -521,6 +473,7 @@ public final class Fory {
isNone: Bool,
_ body: (WriteContext) throws -> Void
) throws -> Data {
+ typeResolver.finishRegistration()
let context = writeContext
context.buffer.clear()
defer {
@@ -539,6 +492,7 @@ public final class Fory {
isNone: Bool,
_ body: (WriteContext) throws -> Void
) throws {
+ typeResolver.finishRegistration()
let context = writeContext
context.buffer.clear()
defer {
@@ -557,7 +511,8 @@ public final class Fory {
nilValue: @autoclosure () -> R,
_ body: (ReadContext) throws -> R
) throws -> R {
- try withReusableReadContext(data: data) { context in
+ typeResolver.finishRegistration()
+ return try withReusableReadContext(data: data) { context in
if try readHead(buffer: context.buffer) {
return nilValue()
}
@@ -575,6 +530,7 @@ public final class Fory {
nilValue: @autoclosure () -> R,
_ body: (ReadContext) throws -> R
) throws -> R {
+ typeResolver.finishRegistration()
readContext.buffer.swapState(with: buffer)
defer {
readContext.buffer.swapState(with: buffer)
diff --git a/swift/Sources/Fory/ReadContext.swift
b/swift/Sources/Fory/ReadContext.swift
index a394b4d10..d0e3e46e8 100644
--- a/swift/Sources/Fory/ReadContext.swift
+++ b/swift/Sources/Fory/ReadContext.swift
@@ -473,7 +473,7 @@ public final class ReadContext {
case .float64Array:
value = try [Double].foryRead(self, refMode: .none, readTypeInfo:
false)
case .array, .list:
- value = try readAnyList(refMode: .none) ?? []
+ value = try readListOfAny(refMode: .none) ?? []
case .set:
value = try Set<AnyHashable>.foryRead(self, refMode: .none,
readTypeInfo: false)
case .map:
@@ -555,14 +555,14 @@ public extension ReadContext {
refMode: RefMode,
readTypeInfo: Bool = true
) throws -> Any? {
- try DynamicAnyValue.foryRead(self, refMode: refMode, readTypeInfo:
readTypeInfo).anyValue()
+ try SerializableAny.foryRead(self, refMode: refMode, readTypeInfo:
readTypeInfo).anyValue()
}
- func readAnyList(
+ func readListOfAny(
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [Any]? {
- let wrapped: [DynamicAnyValue]? = try [DynamicAnyValue]?.foryRead(
+ let wrapped: [SerializableAny]? = try [SerializableAny]?.foryRead(
self,
refMode: refMode,
readTypeInfo: readTypeInfo
@@ -570,11 +570,11 @@ public extension ReadContext {
return wrapped?.map { $0.anyValueForCollection() }
}
- func readStringAnyMap(
+ func readMapStringToAny(
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [String: Any]? {
- let wrapped: [String: DynamicAnyValue]? = try [String:
DynamicAnyValue]?.foryRead(
+ let wrapped: [String: SerializableAny]? = try [String:
SerializableAny]?.foryRead(
self,
refMode: refMode,
readTypeInfo: readTypeInfo
@@ -590,11 +590,11 @@ public extension ReadContext {
return map
}
- func readInt32AnyMap(
+ func readMapInt32ToAny(
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [Int32: Any]? {
- let wrapped: [Int32: DynamicAnyValue]? = try [Int32:
DynamicAnyValue]?.foryRead(
+ let wrapped: [Int32: SerializableAny]? = try [Int32:
SerializableAny]?.foryRead(
self,
refMode: refMode,
readTypeInfo: readTypeInfo
@@ -610,11 +610,11 @@ public extension ReadContext {
return map
}
- func readAnyHashableAnyMap(
+ func readMapAnyHashableToAny(
refMode: RefMode,
readTypeInfo: Bool = false
) throws -> [AnyHashable: Any]? {
- let wrapped: [AnyHashable: DynamicAnyValue]? = try [AnyHashable:
DynamicAnyValue]?.foryRead(
+ let wrapped: [AnyHashable: SerializableAny]? = try [AnyHashable:
SerializableAny]?.foryRead(
self,
refMode: refMode,
readTypeInfo: readTypeInfo
diff --git a/swift/Sources/Fory/TypeResolver.swift
b/swift/Sources/Fory/TypeResolver.swift
index 88a1beeb3..e0f49ab50 100644
--- a/swift/Sources/Fory/TypeResolver.swift
+++ b/swift/Sources/Fory/TypeResolver.swift
@@ -363,6 +363,7 @@ private struct TypeNameKey: Hashable {
final class TypeResolver {
private let trackRef: Bool
+ private var registrationFinished = false
private var bySwiftType = UInt64Map<TypeInfo>(initialCapacity: 64)
private var byUserTypeID = UInt64Map<TypeInfo>(initialCapacity: 64)
@@ -374,11 +375,15 @@ final class TypeResolver {
self.trackRef = trackRef
}
+ func finishRegistration() {
+ registrationFinished = true
+ }
+
func register<T: Serializer>(_ type: T.Type, id: UInt32) {
do {
try registerByID(type, id: id)
} catch {
- preconditionFailure("conflicting registration for \(type):
\(error)")
+ preconditionFailure("registration failed for \(type): \(error)")
}
}
@@ -391,6 +396,7 @@ final class TypeResolver {
}
private func registerByID<T: Serializer>(_ type: T.Type, id: UInt32)
throws {
+ try ensureRegistrationAllowed()
let swiftTypeID = ObjectIdentifier(type)
try validateIDRegistration(key: swiftTypeID, type: type, id: id)
let evolving = evolving(for: type)
@@ -428,6 +434,7 @@ final class TypeResolver {
}
func register<T: Serializer>(_ type: T.Type, namespace: String, typeName:
String) throws {
+ try ensureRegistrationAllowed()
let namespaceMeta = try MetaStringEncoder.namespace.encode(
namespace,
allowedEncodings: namespaceMetaStringEncodings
@@ -652,4 +659,12 @@ final class TypeResolver {
throw ForyError.invalidData("missing user type id in compatible
dynamic type meta")
}
+ private func ensureRegistrationAllowed() throws {
+ guard !registrationFinished else {
+ throw ForyError.invalidData(
+ "cannot register more types after top-level
serialize/deserialize has frozen registration"
+ )
+ }
+ }
+
}
diff --git a/swift/Sources/Fory/WriteContext.swift
b/swift/Sources/Fory/WriteContext.swift
index 9d10aa10e..1fcf8ae7f 100644
--- a/swift/Sources/Fory/WriteContext.swift
+++ b/swift/Sources/Fory/WriteContext.swift
@@ -212,7 +212,7 @@ public extension WriteContext {
writeTypeInfo: Bool = true,
hasGenerics: Bool = false
) throws {
- try DynamicAnyValue.wrapped(value).foryWrite(
+ try SerializableAny.wrapped(value).foryWrite(
self,
refMode: refMode,
writeTypeInfo: writeTypeInfo,
@@ -220,13 +220,13 @@ public extension WriteContext {
)
}
- func writeAnyList(
+ func writeListOfAny(
_ value: [Any]?,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.map { DynamicAnyValue.wrapped($0) }
+ let wrapped = value?.map { SerializableAny.wrapped($0) }
try wrapped.foryWrite(
self,
refMode: refMode,
@@ -235,14 +235,14 @@ public extension WriteContext {
)
}
- func writeStringAnyMap(
+ func writeMapStringToAny(
_ value: [String: Any]?,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.reduce(into: [String: DynamicAnyValue]()) {
result, pair in
- result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+ let wrapped = value?.reduce(into: [String: SerializableAny]()) {
result, pair in
+ result[pair.key] = SerializableAny.wrapped(pair.value)
}
try wrapped.foryWrite(
self,
@@ -252,14 +252,14 @@ public extension WriteContext {
)
}
- func writeInt32AnyMap(
+ func writeMapInt32ToAny(
_ value: [Int32: Any]?,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.reduce(into: [Int32: DynamicAnyValue]()) {
result, pair in
- result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+ let wrapped = value?.reduce(into: [Int32: SerializableAny]()) {
result, pair in
+ result[pair.key] = SerializableAny.wrapped(pair.value)
}
try wrapped.foryWrite(
self,
@@ -269,14 +269,14 @@ public extension WriteContext {
)
}
- func writeAnyHashableAnyMap(
+ func writeMapAnyHashableToAny(
_ value: [AnyHashable: Any]?,
refMode: RefMode,
writeTypeInfo: Bool = false,
hasGenerics: Bool = true
) throws {
- let wrapped = value?.reduce(into: [AnyHashable: DynamicAnyValue]()) {
result, pair in
- result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+ let wrapped = value?.reduce(into: [AnyHashable: SerializableAny]()) {
result, pair in
+ result[pair.key] = SerializableAny.wrapped(pair.value)
}
try wrapped.foryWrite(
self,
diff --git a/swift/Sources/ForyMacro/ForyObjectMacro.swift
b/swift/Sources/ForyMacro/ForyObjectMacro.swift
index b8e7a0ffd..63948c23a 100644
--- a/swift/Sources/ForyMacro/ForyObjectMacro.swift
+++ b/swift/Sources/ForyMacro/ForyObjectMacro.swift
@@ -1341,13 +1341,13 @@ func dynamicAnyWriteMethodName(_ codec:
DynamicAnyCodecKind) -> String {
case .anyValue, .anyHashableValue:
return "writeAny"
case .anyList:
- return "writeAnyList"
+ return "writeListOfAny"
case .stringAnyMap:
- return "writeStringAnyMap"
+ return "writeMapStringToAny"
case .int32AnyMap:
- return "writeInt32AnyMap"
+ return "writeMapInt32ToAny"
case .anyHashableAnyMap:
- return "writeAnyHashableAnyMap"
+ return "writeMapAnyHashableToAny"
}
}
@@ -1356,13 +1356,13 @@ func dynamicAnyReadMethodName(_ codec:
DynamicAnyCodecKind) -> String {
case .anyValue, .anyHashableValue:
return "readAny"
case .anyList:
- return "readAnyList"
+ return "readListOfAny"
case .stringAnyMap:
- return "readStringAnyMap"
+ return "readMapStringToAny"
case .int32AnyMap:
- return "readInt32AnyMap"
+ return "readMapInt32ToAny"
case .anyHashableAnyMap:
- return "readAnyHashableAnyMap"
+ return "readMapAnyHashableToAny"
}
}
diff --git a/swift/Tests/ForyTests/ForySwiftTests.swift
b/swift/Tests/ForyTests/ForySwiftTests.swift
index 5eecbb8bf..e7e347311 100644
--- a/swift/Tests/ForyTests/ForySwiftTests.swift
+++ b/swift/Tests/ForyTests/ForySwiftTests.swift
@@ -251,19 +251,27 @@ func namedInitializerBuildsConfig() {
#expect(defaultConfig.config.xlang == true)
#expect(defaultConfig.config.trackRef == false)
#expect(defaultConfig.config.compatible == false)
+ #expect(defaultConfig.config.checkClassVersion == true)
#expect(defaultConfig.config.maxDepth == 5)
let explicitConfig = Fory(xlang: false, trackRef: true, compatible: true,
maxDepth: 7)
#expect(explicitConfig.config.xlang == false)
#expect(explicitConfig.config.trackRef == true)
#expect(explicitConfig.config.compatible == true)
+ #expect(explicitConfig.config.checkClassVersion == false)
#expect(explicitConfig.config.maxDepth == 7)
let configInit = Fory(config: .init(xlang: false, trackRef: false,
compatible: true, maxDepth: 9))
#expect(configInit.config.xlang == false)
#expect(configInit.config.trackRef == false)
#expect(configInit.config.compatible == true)
+ #expect(configInit.config.checkClassVersion == false)
#expect(configInit.config.maxDepth == 9)
+
+ let nativeDirect = Fory(xlang: false, trackRef: true, compatible: false)
+ let nativeViaConfig = Fory(config: Config(xlang: false, trackRef: true,
compatible: false))
+ #expect(nativeDirect.config.checkClassVersion == false)
+ #expect(nativeViaConfig.config.checkClassVersion == false)
}
@Test
@@ -491,6 +499,19 @@ func duplicateNameRegistrationIsRejected() throws {
} catch {}
}
+@Test
+func registrationIsRejectedAfterFirstTopLevelUse() throws {
+ let fory = Fory()
+ _ = try fory.serialize(Int32(7))
+
+ do {
+ try fory.register(Address.self, name: "demo.address")
+ #expect(Bool(false))
+ } catch {
+ #expect("\(error)".contains("cannot register more types"))
+ }
+}
+
@Test
func topLevelAnyObjectRoundTrip() throws {
let fory = Fory(config: .init(xlang: true, trackRef: true))
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]