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]


Reply via email to