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 dd0777bec feat(swift): harden decode paths and add missing wire type 
support (#3427)
dd0777bec is described below

commit dd0777bec46d5ffa090655692b0b25bfc3e7788b
Author: Shawn Yang <[email protected]>
AuthorDate: Thu Feb 26 18:30:03 2026 +0800

    feat(swift): harden decode paths and add missing wire type support (#3427)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    
    
    ## 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
---
 .github/workflows/ci.yml                       |   7 +
 AGENTS.md                                      |  35 ++
 ci/format.sh                                   |  21 ++
 docs/compiler/compiler-guide.md                |  30 +-
 swift/.swiftlint.yml                           |  50 +++
 swift/Package.swift                            |   8 +-
 swift/Sources/Fory/AnySerializer.swift         |  20 +-
 swift/Sources/Fory/ByteBuffer.swift            |  11 +-
 swift/Sources/Fory/CollectionSerializers.swift |  74 +++-
 swift/Sources/Fory/Context.swift               |  99 ++++++
 swift/Sources/Fory/DateTimeSerializers.swift   |  28 ++
 swift/Sources/Fory/FieldSkipper.swift          | 447 ++++++++++++++++++++-----
 swift/Sources/Fory/Fory.swift                  |  58 ++--
 swift/Sources/Fory/MetaString.swift            |  61 ++--
 swift/Sources/Fory/MurmurHash3.swift           |  22 +-
 swift/Sources/Fory/OptionalSerializer.swift    |   6 +-
 swift/Sources/Fory/PrimitiveSerializers.swift  |  40 ++-
 swift/Sources/Fory/TypeMeta.swift              |  11 +-
 swift/Sources/Fory/TypeResolver.swift          | 106 +++++-
 swift/Sources/ForyMacro/ForyObjectMacro.swift  | 125 ++++++-
 swift/Tests/ForyTests/AnyTests.swift           |  98 +++++-
 swift/Tests/ForyTests/DateTimeTests.swift      |   6 +
 swift/Tests/ForyTests/EnumTests.swift          |   4 +-
 swift/Tests/ForyTests/ForySwiftTests.swift     | 133 +++++++-
 swift/Tests/ForyXlangTests/main.swift          |  64 ++--
 25 files changed, 1295 insertions(+), 269 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a78931c8e..b0db1328c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -217,6 +217,13 @@ jobs:
         run: |
           cd swift
           swift test
+      - name: Run SwiftLint check
+        run: |
+          if ! command -v swiftlint >/dev/null; then
+            brew install swiftlint
+          fi
+          cd swift
+          swiftlint lint --config .swiftlint.yml
 
   swift_xlang:
     name: Swift Xlang Test
diff --git a/AGENTS.md b/AGENTS.md
index 56a3fc319..db711837a 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -235,6 +235,41 @@ cd fory-core
 RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1 FORY_RUST_JAVA_CI=1 
ENABLE_FORY_DEBUG_OUTPUT=1 mvn test -Dtest=org.apache.fory.xlang.RustXlangTest
 ```
 
+### Swift Development
+
+- All commands must be executed within the `swift` directory.
+- All changes to `swift` must pass lint and tests.
+- Swift lint uses `swift/.swiftlint.yml`.
+- Use `ENABLE_FORY_DEBUG_OUTPUT=1` when debugging Swift tests.
+
+```bash
+# Build package
+swift build
+
+# Run tests
+swift test
+
+# Run tests with debug output
+ENABLE_FORY_DEBUG_OUTPUT=1 swift test
+
+# Lint check
+swiftlint lint --config .swiftlint.yml
+
+# Auto-fix lint issues where supported
+swiftlint --fix --config .swiftlint.yml
+```
+
+Run Swift xlang tests:
+
+```bash
+cd swift
+swift build -c release --disable-automatic-resolution --product ForyXlangTests
+cd ../java
+mvn -T16 install -DskipTests
+cd fory-core
+FORY_SWIFT_JAVA_CI=1 ENABLE_FORY_DEBUG_OUTPUT=1 mvn -T16 test 
-Dtest=org.apache.fory.xlang.SwiftXlangTest
+```
+
 ### JavaScript/TypeScript Development
 
 - All commands must be executed within the `javascript` directory.
diff --git a/ci/format.sh b/ci/format.sh
index 5501dc481..0545ea231 100755
--- a/ci/format.sh
+++ b/ci/format.sh
@@ -213,6 +213,18 @@ format_go() {
     fi
 }
 
+format_swift() {
+    echo "$(date)" "SwiftLint check Swift files...."
+    if command -v swiftlint >/dev/null; then
+      pushd "$ROOT/swift"
+      swiftlint lint --config .swiftlint.yml
+      popd
+      echo "$(date)" "SwiftLint done!"
+    else
+      echo "WARNING: swiftlint is not installed, skip swift lint check"
+    fi
+}
+
 # Format all files, and print the diff to stdout for travis.
 format_all() {
     format_all_scripts "${@}"
@@ -239,6 +251,9 @@ format_all() {
       git ls-files -- '*.go' "${GIT_LS_EXCLUDES[@]}" | xargs -P 5 gofmt -w
     fi
 
+    echo "$(date)" "lint swift...."
+    format_swift
+
     echo "$(date)" "done!"
 }
 
@@ -292,6 +307,10 @@ format_changed() {
         prettier --write "**/*.md"
         popd
     fi
+
+    if ! git diff --diff-filter=ACRM --quiet --exit-code "$MERGEBASE" -- 
'swift' &>/dev/null; then
+        format_swift
+    fi
 }
 
 
@@ -316,6 +335,8 @@ elif [ "${1-}" == '--python' ]; then
     format_python
 elif [ "${1-}" == '--go' ]; then
     format_go
+elif [ "${1-}" == '--swift' ]; then
+    format_swift
 else
     # Add the origin remote if it doesn't exist
     if ! git remote -v | grep -q origin; then
diff --git a/docs/compiler/compiler-guide.md b/docs/compiler/compiler-guide.md
index 4a513f290..0457751d2 100644
--- a/docs/compiler/compiler-guide.md
+++ b/docs/compiler/compiler-guide.md
@@ -52,21 +52,21 @@ foryc --scan-generated [OPTIONS]
 
 Compile options:
 
-| Option                                | Description                          
                 | Default             |
-| ------------------------------------- | 
----------------------------------------------------- | ------------------- |
-| `--lang`                              | Comma-separated target languages     
                 | `all`               |
-| `--output`, `-o`                      | Output directory                     
                 | `./generated`       |
-| `--package`                           | Override package name from Fory IDL 
file              | (from file)         |
-| `-I`, `--proto_path`, `--import_path` | Add directory to import search path 
(can be repeated) | (none)              |
-| `--java_out=DST_DIR`                  | Generate Java code in DST_DIR        
                 | (none)              |
-| `--python_out=DST_DIR`                | Generate Python code in DST_DIR      
                 | (none)              |
-| `--cpp_out=DST_DIR`                   | Generate C++ code in DST_DIR         
                 | (none)              |
-| `--go_out=DST_DIR`                    | Generate Go code in DST_DIR          
                 | (none)              |
-| `--rust_out=DST_DIR`                  | Generate Rust code in DST_DIR        
                 | (none)              |
-| `--csharp_out=DST_DIR`                | Generate C# code in DST_DIR          
                 | (none)              |
-| `--go_nested_type_style`              | Go nested type naming: `camelcase` 
or `underscore`    | `underscore`        |
-| `--emit-fdl`                          | Emit translated FDL (for non-FDL 
inputs)              | `false`             |
-| `--emit-fdl-path`                     | Write translated FDL to this path 
(file or directory) | (stdout)            |
+| Option                                | Description                          
                 | Default       |
+| ------------------------------------- | 
----------------------------------------------------- | ------------- |
+| `--lang`                              | Comma-separated target languages     
                 | `all`         |
+| `--output`, `-o`                      | Output directory                     
                 | `./generated` |
+| `--package`                           | Override package name from Fory IDL 
file              | (from file)   |
+| `-I`, `--proto_path`, `--import_path` | Add directory to import search path 
(can be repeated) | (none)        |
+| `--java_out=DST_DIR`                  | Generate Java code in DST_DIR        
                 | (none)        |
+| `--python_out=DST_DIR`                | Generate Python code in DST_DIR      
                 | (none)        |
+| `--cpp_out=DST_DIR`                   | Generate C++ code in DST_DIR         
                 | (none)        |
+| `--go_out=DST_DIR`                    | Generate Go code in DST_DIR          
                 | (none)        |
+| `--rust_out=DST_DIR`                  | Generate Rust code in DST_DIR        
                 | (none)        |
+| `--csharp_out=DST_DIR`                | Generate C# code in DST_DIR          
                 | (none)        |
+| `--go_nested_type_style`              | Go nested type naming: `camelcase` 
or `underscore`    | `underscore`  |
+| `--emit-fdl`                          | Emit translated FDL (for non-FDL 
inputs)              | `false`       |
+| `--emit-fdl-path`                     | Write translated FDL to this path 
(file or directory) | (stdout)      |
 
 Scan options (with `--scan-generated`):
 
diff --git a/swift/.swiftlint.yml b/swift/.swiftlint.yml
new file mode 100644
index 000000000..eb64b45c7
--- /dev/null
+++ b/swift/.swiftlint.yml
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+included:
+  - Sources
+  - Tests
+  - Package.swift
+
+excluded:
+  - .build
+
+identifier_name:
+  min_length:
+    warning: 2
+    error: 1
+
+line_length:
+  warning: 160
+  error: 200
+  ignores_comments: true
+
+function_body_length:
+  warning: 200
+  error: 260
+
+type_body_length:
+  warning: 900
+  error: 1400
+
+file_length:
+  warning: 1900
+  error: 2200
+
+cyclomatic_complexity:
+  warning: 50
+  error: 70
diff --git a/swift/Package.swift b/swift/Package.swift
index cb2f60e71..c5a7f8a61 100644
--- a/swift/Package.swift
+++ b/swift/Package.swift
@@ -6,7 +6,7 @@ let package = Package(
     name: "fory-swift",
     platforms: [
         .macOS(.v13),
-        .iOS(.v16),
+        .iOS(.v16)
     ],
     products: [
         .library(
@@ -16,7 +16,7 @@ let package = Package(
         .executable(
             name: "ForyXlangTests",
             targets: ["ForyXlangTests"]
-        ),
+        )
     ],
     dependencies: [
         .package(url: "https://github.com/swiftlang/swift-syntax.git";, from: 
"600.0.0")
@@ -28,7 +28,7 @@ let package = Package(
                 .product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
                 .product(name: "SwiftSyntax", package: "swift-syntax"),
                 .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
-                .product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
+                .product(name: "SwiftSyntaxMacros", package: "swift-syntax")
             ],
             path: "Sources/ForyMacro"
         ),
@@ -47,6 +47,6 @@ let package = Package(
             name: "ForyTests",
             dependencies: ["Fory"],
             path: "Tests/ForyTests"
-        ),
+        )
     ]
 )
diff --git a/swift/Sources/Fory/AnySerializer.swift 
b/swift/Sources/Fory/AnySerializer.swift
index 70f68107b..e0e1968c0 100644
--- a/swift/Sources/Fory/AnySerializer.swift
+++ b/swift/Sources/Fory/AnySerializer.swift
@@ -103,7 +103,7 @@ private protocol OptionalTypeMarker {
 }
 
 extension Optional: OptionalTypeMarker {
-    static var noneValue: Optional<Wrapped> { nil }
+    static var noneValue: Wrapped? { nil }
 }
 
 private struct DynamicAnyValue: Serializer {
@@ -312,6 +312,9 @@ private func writeAnyTypeInfo(_ value: Any, context: 
WriteContext) throws {
 }
 
 private func writeAnyPayload(_ value: Any, context: WriteContext, hasGenerics: 
Bool) throws {
+    try context.enterDynamicAnyDepth()
+    defer { context.leaveDynamicAnyDepth() }
+
     if let serializer = value as? any Serializer {
         try serializer.foryWriteData(context, hasGenerics: hasGenerics)
         return
@@ -340,18 +343,25 @@ private func writeAnyPayload(_ value: Any, context: 
WriteContext, hasGenerics: B
 
 public func castAnyDynamicValue<T>(_ value: Any?, to type: T.Type) throws -> T 
{
     _ = type
+    func castNilSentinel(_ sentinel: Any) throws -> T {
+        guard let casted = sentinel as? T else {
+            throw ForyError.invalidData("cannot cast dynamic Any value to 
\(type)")
+        }
+        return casted
+    }
+
     if value == nil {
         if T.self == Any.self {
-            return ForyAnyNullValue() as! T
+            return try castNilSentinel(ForyAnyNullValue())
         }
         if T.self == AnyObject.self {
-            return NSNull() as! T
+            return try castNilSentinel(NSNull())
         }
         if T.self == (any Serializer).self {
-            return ForyAnyNullValue() as! T
+            return try castNilSentinel(ForyAnyNullValue())
         }
         if let optionalType = T.self as? any OptionalTypeMarker.Type {
-            return optionalType.noneValue as! T
+            return try castNilSentinel(optionalType.noneValue)
         }
     }
 
diff --git a/swift/Sources/Fory/ByteBuffer.swift 
b/swift/Sources/Fory/ByteBuffer.swift
index 96b978580..214c22c5d 100644
--- a/swift/Sources/Fory/ByteBuffer.swift
+++ b/swift/Sources/Fory/ByteBuffer.swift
@@ -870,7 +870,7 @@ public final class ByteBuffer {
         if count == 0 {
             return []
         }
-        return try Array<UInt8>(unsafeUninitializedCapacity: count) { 
destination, initializedCount in
+        return try [UInt8](unsafeUninitializedCapacity: count) { destination, 
initializedCount in
             try readBytes(into: UnsafeMutableRawBufferPointer(destination))
             initializedCount = count
         }
@@ -883,12 +883,11 @@ public final class ByteBuffer {
         let start = cursor
         let end = start + count
         cursor = end
-        return storage.withUnsafeBufferPointer { buffer in
-            String(
-                decoding: UnsafeBufferPointer(rebasing: buffer[start..<end]),
-                as: UTF8.self
-            )
+        let utf8Bytes = storage[start..<end]
+        guard let decoded = String(bytes: utf8Bytes, encoding: .utf8) else {
+            throw ForyError.invalidData("invalid UTF-8 sequence")
         }
+        return decoded
     }
 
     @inlinable
diff --git a/swift/Sources/Fory/CollectionSerializers.swift 
b/swift/Sources/Fory/CollectionSerializers.swift
index 0a1ed5e09..4e2f04de1 100644
--- a/swift/Sources/Fory/CollectionSerializers.swift
+++ b/swift/Sources/Fory/CollectionSerializers.swift
@@ -44,6 +44,8 @@ private func primitiveArrayTypeID<Element: Serializer>(for _: 
Element.Type) -> T
     if Element.self == UInt16.self { return .uint16Array }
     if Element.self == UInt32.self { return .uint32Array }
     if Element.self == UInt64.self { return .uint64Array }
+    if Element.self == Float16.self { return .float16Array }
+    if Element.self == BFloat16.self { return .bfloat16Array }
     if Element.self == Float.self { return .float32Array }
     if Element.self == Double.self { return .float64Array }
     return nil
@@ -62,7 +64,7 @@ private func readArrayUninitialized<Element>(
     count: Int,
     _ initializer: (UnsafeMutablePointer<Element>) throws -> Void
 ) rethrows -> [Element] {
-    try Array<Element>(unsafeUninitializedCapacity: count) { destination, 
initializedCount in
+    try [Element](unsafeUninitializedCapacity: count) { destination, 
initializedCount in
         if count > 0 {
             try initializer(destination.baseAddress!)
         }
@@ -186,6 +188,24 @@ private func writePrimitiveArray<Element: Serializer>(_ 
value: [Element], contex
         return
     }
 
+    if Element.self == Float16.self {
+        let values = uncheckedArrayCast(value, to: Float16.self)
+        context.buffer.writeVarUInt32(UInt32(values.count * 2))
+        for item in values {
+            context.buffer.writeUInt16(item.bitPattern)
+        }
+        return
+    }
+
+    if Element.self == BFloat16.self {
+        let values = uncheckedArrayCast(value, to: BFloat16.self)
+        context.buffer.writeVarUInt32(UInt32(values.count * 2))
+        for item in values {
+            context.buffer.writeUInt16(item.rawValue)
+        }
+        return
+    }
+
     if Element.self == Float.self {
         let values = uncheckedArrayCast(value, to: Float.self)
         context.buffer.writeVarUInt32(UInt32(values.count * 4))
@@ -216,13 +236,16 @@ private func writePrimitiveArray<Element: Serializer>(_ 
value: [Element], contex
 
 private func readPrimitiveArray<Element: Serializer>(_ context: ReadContext) 
throws -> [Element] {
     let payloadSize = Int(try context.buffer.readVarUInt32())
+    try context.ensureRemainingBytes(payloadSize, label: 
"\(Element.self)_array_payload")
 
     if Element.self == UInt8.self {
+        try context.ensureCollectionLength(payloadSize, label: "uint8_array")
         let bytes = try context.buffer.readBytes(count: payloadSize)
         return uncheckedArrayCast(bytes, to: Element.self)
     }
 
     if Element.self == Bool.self {
+        try context.ensureCollectionLength(payloadSize, label: "bool_array")
         let out = try readArrayUninitialized(count: payloadSize) { destination 
in
             for index in 0..<payloadSize {
                 destination.advanced(by: index).initialize(to: try 
context.buffer.readUInt8() != 0)
@@ -232,6 +255,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
     }
 
     if Element.self == Int8.self {
+        try context.ensureCollectionLength(payloadSize, label: "int8_array")
         var out = Array(repeating: Int8(0), count: payloadSize)
         try out.withUnsafeMutableBytes { rawBytes in
             try context.buffer.readBytes(into: rawBytes)
@@ -242,6 +266,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
     if Element.self == Int16.self {
         if payloadSize % 2 != 0 { throw ForyError.invalidData("int16 array 
payload size mismatch") }
         let count = payloadSize / 2
+        try context.ensureCollectionLength(count, label: "int16_array")
         if hostIsLittleEndian {
             var out = Array(repeating: Int16(0), count: count)
             try out.withUnsafeMutableBytes { rawBytes in
@@ -260,6 +285,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
     if Element.self == Int32.self {
         if payloadSize % 4 != 0 { throw ForyError.invalidData("int32 array 
payload size mismatch") }
         let count = payloadSize / 4
+        try context.ensureCollectionLength(count, label: "int32_array")
         if hostIsLittleEndian {
             var out = Array(repeating: Int32(0), count: count)
             try out.withUnsafeMutableBytes { rawBytes in
@@ -278,6 +304,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
     if Element.self == UInt32.self {
         if payloadSize % 4 != 0 { throw ForyError.invalidData("uint32 array 
payload size mismatch") }
         let count = payloadSize / 4
+        try context.ensureCollectionLength(count, label: "uint32_array")
         if hostIsLittleEndian {
             var out = Array(repeating: UInt32(0), count: count)
             try out.withUnsafeMutableBytes { rawBytes in
@@ -296,6 +323,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
     if Element.self == Int64.self {
         if payloadSize % 8 != 0 { throw ForyError.invalidData("int64 array 
payload size mismatch") }
         let count = payloadSize / 8
+        try context.ensureCollectionLength(count, label: "int64_array")
         if hostIsLittleEndian {
             var out = Array(repeating: Int64(0), count: count)
             try out.withUnsafeMutableBytes { rawBytes in
@@ -314,6 +342,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
     if Element.self == UInt64.self {
         if payloadSize % 8 != 0 { throw ForyError.invalidData("uint64 array 
payload size mismatch") }
         let count = payloadSize / 8
+        try context.ensureCollectionLength(count, label: "uint64_array")
         if hostIsLittleEndian {
             var out = Array(repeating: UInt64(0), count: count)
             try out.withUnsafeMutableBytes { rawBytes in
@@ -332,6 +361,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
     if Element.self == UInt16.self {
         if payloadSize % 2 != 0 { throw ForyError.invalidData("uint16 array 
payload size mismatch") }
         let count = payloadSize / 2
+        try context.ensureCollectionLength(count, label: "uint16_array")
         if hostIsLittleEndian {
             var out = Array(repeating: UInt16(0), count: count)
             try out.withUnsafeMutableBytes { rawBytes in
@@ -347,9 +377,34 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
         return uncheckedArrayCast(out, to: Element.self)
     }
 
+    if Element.self == Float16.self {
+        if payloadSize % 2 != 0 { throw ForyError.invalidData("float16 array 
payload size mismatch") }
+        let count = payloadSize / 2
+        try context.ensureCollectionLength(count, label: "float16_array")
+        let values = try readArrayUninitialized(count: count) { destination in
+            for index in 0..<count {
+                destination.advanced(by: index).initialize(to: 
Float16(bitPattern: try context.buffer.readUInt16()))
+            }
+        }
+        return uncheckedArrayCast(values, to: Element.self)
+    }
+
+    if Element.self == BFloat16.self {
+        if payloadSize % 2 != 0 { throw ForyError.invalidData("bfloat16 array 
payload size mismatch") }
+        let count = payloadSize / 2
+        try context.ensureCollectionLength(count, label: "bfloat16_array")
+        let values = try readArrayUninitialized(count: count) { destination in
+            for index in 0..<count {
+                destination.advanced(by: index).initialize(to: 
BFloat16(rawValue: try context.buffer.readUInt16()))
+            }
+        }
+        return uncheckedArrayCast(values, to: Element.self)
+    }
+
     if Element.self == Float.self {
         if payloadSize % 4 != 0 { throw ForyError.invalidData("float32 array 
payload size mismatch") }
         let count = payloadSize / 4
+        try context.ensureCollectionLength(count, label: "float32_array")
         if hostIsLittleEndian {
             var out = Array(repeating: Float(0), count: count)
             try out.withUnsafeMutableBytes { rawBytes in
@@ -367,6 +422,7 @@ private func readPrimitiveArray<Element: Serializer>(_ 
context: ReadContext) thr
 
     if payloadSize % 8 != 0 { throw ForyError.invalidData("float64 array 
payload size mismatch") }
     let count = payloadSize / 8
+    try context.ensureCollectionLength(count, label: "float64_array")
     if hostIsLittleEndian {
         var out = Array(repeating: Double(0), count: count)
         try out.withUnsafeMutableBytes { rawBytes in
@@ -467,6 +523,7 @@ extension Array: Serializer where Element: Serializer {
 
         let buffer = context.buffer
         let length = Int(try buffer.readVarUInt32())
+        try context.ensureCollectionLength(length, label: "array")
         if length == 0 {
             return []
         }
@@ -608,12 +665,12 @@ extension Set: Serializer where Element: Serializer & 
Hashable {
     }
 
     public static func foryReadData(_ context: ReadContext) throws -> 
Set<Element> {
-        Set(try Array<Element>.foryReadData(context))
+        Set(try [Element].foryReadData(context))
     }
 }
 
 extension Dictionary: Serializer where Key: Serializer & Hashable, Value: 
Serializer {
-    public static func foryDefault() -> Dictionary<Key, Value> { [:] }
+    public static func foryDefault() -> [Key: Value] { [:] }
 
     public static var staticTypeId: TypeId { .map }
 
@@ -823,14 +880,15 @@ extension Dictionary: Serializer where Key: Serializer & 
Hashable, Value: Serial
         }
     }
 
-    public static func foryReadData(_ context: ReadContext) throws -> 
Dictionary<Key, Value> {
+    public static func foryReadData(_ context: ReadContext) throws -> [Key: 
Value] {
         let totalLength = Int(try context.buffer.readVarUInt32())
+        try context.ensureCollectionLength(totalLength, label: "map")
         if totalLength == 0 {
             return [:]
         }
 
         var map: [Key: Value] = [:]
-        map.reserveCapacity(totalLength)
+        map.reserveCapacity(Swift.min(totalLength, context.buffer.remaining))
         let keyDynamicType = Key.staticTypeId == .unknown
         let valueDynamicType = Value.staticTypeId == .unknown
         let canonicalizeValues = context.trackRef && 
Value.isReferenceTrackableType
@@ -891,6 +949,9 @@ extension Dictionary: Serializer where Key: Serializer & 
Hashable, Value: Serial
                 }
 
                 let chunkSize = Int(try context.buffer.readUInt8())
+                if chunkSize > (totalLength - dynamicReadCount) {
+                    throw ForyError.invalidData("map dynamic chunk size 
exceeds remaining entries")
+                }
                 if !keyDeclared {
                     try Key.foryReadTypeInfo(context)
                 }
@@ -987,6 +1048,9 @@ extension Dictionary: Serializer where Key: Serializer & 
Hashable, Value: Serial
             }
 
             let chunkSize = Int(try context.buffer.readUInt8())
+            if chunkSize > (totalLength - readCount) {
+                throw ForyError.invalidData("map chunk size exceeds remaining 
entries")
+            }
             if !keyDeclared {
                 try Key.foryReadTypeInfo(context)
             }
diff --git a/swift/Sources/Fory/Context.swift b/swift/Sources/Fory/Context.swift
index 08de2b918..7832f7e67 100644
--- a/swift/Sources/Fory/Context.swift
+++ b/swift/Sources/Fory/Context.swift
@@ -182,11 +182,13 @@ public final class WriteContext {
     public let trackRef: Bool
     public let compatible: Bool
     public let checkClassVersion: Bool
+    public let maxDepth: Int
     public let refWriter: RefWriter
     public let compatibleTypeDefState: CompatibleTypeDefWriteState
     public let metaStringWriteState: MetaStringWriteState
     private var compatibleTypeDefStateUsed = false
     private var metaStringWriteStateUsed = false
+    private var dynamicAnyDepth = 0
 
     public init(
         buffer: ByteBuffer,
@@ -194,6 +196,7 @@ public final class WriteContext {
         trackRef: Bool,
         compatible: Bool = false,
         checkClassVersion: Bool = true,
+        maxDepth: Int = 5,
         compatibleTypeDefState: CompatibleTypeDefWriteState = 
CompatibleTypeDefWriteState(),
         metaStringWriteState: MetaStringWriteState = MetaStringWriteState()
     ) {
@@ -202,11 +205,33 @@ public final class WriteContext {
         self.trackRef = trackRef
         self.compatible = compatible
         self.checkClassVersion = checkClassVersion
+        self.maxDepth = maxDepth
         self.refWriter = RefWriter()
         self.compatibleTypeDefState = compatibleTypeDefState
         self.metaStringWriteState = metaStringWriteState
     }
 
+    @inline(__always)
+    public func enterDynamicAnyDepth() throws {
+        if maxDepth < 0 {
+            throw ForyError.invalidData("configured maxDepth \(maxDepth) is 
negative")
+        }
+        let nextDepth = dynamicAnyDepth + 1
+        if nextDepth > maxDepth {
+            throw ForyError.invalidData(
+                "dynamic Any nesting depth \(nextDepth) exceeds configured 
maxDepth \(maxDepth)"
+            )
+        }
+        dynamicAnyDepth = nextDepth
+    }
+
+    @inline(__always)
+    public func leaveDynamicAnyDepth() {
+        if dynamicAnyDepth > 0 {
+            dynamicAnyDepth -= 1
+        }
+    }
+
     public func writeCompatibleTypeMeta<T: Serializer>(
         for type: T.Type,
         typeMeta: TypeMeta
@@ -233,6 +258,9 @@ public final class WriteContext {
     }
 
     public func resetObjectState() {
+        if dynamicAnyDepth != 0 {
+            dynamicAnyDepth = 0
+        }
         if trackRef {
             refWriter.reset()
         }
@@ -267,11 +295,15 @@ public final class ReadContext {
     public let trackRef: Bool
     public let compatible: Bool
     public let checkClassVersion: Bool
+    public let maxCollectionLength: Int
+    public let maxBinaryLength: Int
+    public let maxDepth: Int
     public let refReader: RefReader
     public let compatibleTypeDefState: CompatibleTypeDefReadState
     public let metaStringReadState: MetaStringReadState
     private var compatibleTypeDefStateUsed = false
     private var metaStringReadStateUsed = false
+    private var dynamicAnyDepth = 0
 
     private var pendingRefStack: [PendingRefSlot] = []
     private var pendingCompatibleTypeMeta: [ObjectIdentifier: [TypeMeta]] = [:]
@@ -284,6 +316,9 @@ public final class ReadContext {
         trackRef: Bool,
         compatible: Bool = false,
         checkClassVersion: Bool = true,
+        maxCollectionLength: Int = 1_000_000,
+        maxBinaryLength: Int = 64 * 1024 * 1024,
+        maxDepth: Int = 5,
         compatibleTypeDefState: CompatibleTypeDefReadState = 
CompatibleTypeDefReadState(),
         metaStringReadState: MetaStringReadState = MetaStringReadState()
     ) {
@@ -292,11 +327,72 @@ public final class ReadContext {
         self.trackRef = trackRef
         self.compatible = compatible
         self.checkClassVersion = checkClassVersion
+        self.maxCollectionLength = maxCollectionLength
+        self.maxBinaryLength = maxBinaryLength
+        self.maxDepth = maxDepth
         self.refReader = RefReader()
         self.compatibleTypeDefState = compatibleTypeDefState
         self.metaStringReadState = metaStringReadState
     }
 
+    @inline(__always)
+    public func enterDynamicAnyDepth() throws {
+        if maxDepth < 0 {
+            throw ForyError.invalidData("configured maxDepth \(maxDepth) is 
negative")
+        }
+        let nextDepth = dynamicAnyDepth + 1
+        if nextDepth > maxDepth {
+            throw ForyError.invalidData(
+                "dynamic Any nesting depth \(nextDepth) exceeds configured 
maxDepth \(maxDepth)"
+            )
+        }
+        dynamicAnyDepth = nextDepth
+    }
+
+    @inline(__always)
+    public func leaveDynamicAnyDepth() {
+        if dynamicAnyDepth > 0 {
+            dynamicAnyDepth -= 1
+        }
+    }
+
+    @inline(__always)
+    public func ensureCollectionLength(_ length: Int, label: String) throws {
+        if length < 0 {
+            throw ForyError.invalidData("\(label) length is negative")
+        }
+        if length > maxCollectionLength {
+            throw ForyError.invalidData(
+                "\(label) length \(length) exceeds configured 
maxCollectionLength \(maxCollectionLength)"
+            )
+        }
+    }
+
+    @inline(__always)
+    public func ensureBinaryLength(_ length: Int, label: String) throws {
+        if length < 0 {
+            throw ForyError.invalidData("\(label) size is negative")
+        }
+        if length > maxBinaryLength {
+            throw ForyError.invalidData(
+                "\(label) size \(length) exceeds configured maxBinaryLength 
\(maxBinaryLength)"
+            )
+        }
+    }
+
+    @inline(__always)
+    public func ensureRemainingBytes(_ byteCount: Int, label: String) throws {
+        if byteCount < 0 {
+            throw ForyError.invalidData("\(label) size is negative")
+        }
+        let remainingBytes = buffer.remaining
+        if byteCount > remainingBytes {
+            throw ForyError.invalidData(
+                "\(label) requires \(byteCount) bytes but only 
\(remainingBytes) remain in buffer"
+            )
+        }
+    }
+
     public func pushPendingReference(_ refID: UInt32) {
         pendingRefStack.append(PendingRefSlot(refID: refID, bound: false))
     }
@@ -410,6 +506,9 @@ public final class ReadContext {
     }
 
     public func resetObjectState() {
+        if dynamicAnyDepth != 0 {
+            dynamicAnyDepth = 0
+        }
         if trackRef {
             refReader.reset()
             if !pendingRefStack.isEmpty {
diff --git a/swift/Sources/Fory/DateTimeSerializers.swift 
b/swift/Sources/Fory/DateTimeSerializers.swift
index 75afd8af6..3fa502c15 100644
--- a/swift/Sources/Fory/DateTimeSerializers.swift
+++ b/swift/Sources/Fory/DateTimeSerializers.swift
@@ -94,6 +94,34 @@ public struct ForyTimestamp: Serializer, Equatable, Hashable 
{
     }
 }
 
+extension Duration: Serializer {
+    public static func foryDefault() -> Duration {
+        .zero
+    }
+
+    public static var staticTypeId: TypeId {
+        .duration
+    }
+
+    public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) 
throws {
+        _ = hasGenerics
+        let components = self.components
+        let nanos = components.attoseconds / 1_000_000_000
+        let remainder = components.attoseconds % 1_000_000_000
+        if remainder != 0 {
+            throw ForyError.encodingError("Duration precision finer than 
nanoseconds is not supported")
+        }
+        context.buffer.writeVarInt64(components.seconds)
+        context.buffer.writeInt32(Int32(nanos))
+    }
+
+    public static func foryReadData(_ context: ReadContext) throws -> Duration 
{
+        let seconds = try context.buffer.readVarInt64()
+        let nanos = try context.buffer.readInt32()
+        return .seconds(seconds) + .nanoseconds(Int64(nanos))
+    }
+}
+
 extension Date: Serializer {
     public static func foryDefault() -> Date {
         Date(timeIntervalSince1970: 0)
diff --git a/swift/Sources/Fory/FieldSkipper.swift 
b/swift/Sources/Fory/FieldSkipper.swift
index 65af9dd3b..7d346150e 100644
--- a/swift/Sources/Fory/FieldSkipper.swift
+++ b/swift/Sources/Fory/FieldSkipper.swift
@@ -22,105 +22,392 @@ public enum FieldSkipper {
         context: ReadContext,
         fieldType: TypeMetaFieldType
     ) throws {
-        _ = try readFieldValue(context: context, fieldType: fieldType)
+        _ = try readFieldValue(
+            context: context,
+            fieldType: fieldType,
+            readTypeInfo: needsTypeInfoForField(fieldType.typeID)
+        )
     }
 
-    private static func readEnumOrdinal(
-        _ context: ReadContext,
-        refMode: RefMode
-    ) throws -> UInt32? {
+    private static func needsTypeInfoForField(_ typeID: UInt32) -> Bool {
+        guard let resolved = TypeId(rawValue: typeID) else {
+            return true
+        }
+        return TypeId.needsTypeInfoForField(resolved)
+    }
+
+    private static func readFieldValue(
+        context: ReadContext,
+        fieldType: TypeMetaFieldType,
+        runtimeTypeInfo: DynamicTypeInfo? = nil,
+        readTypeInfo: Bool
+    ) throws -> Any? {
+        let refMode = RefMode.from(nullable: fieldType.nullable, trackRef: 
fieldType.trackRef)
+        return try readValueWithRefMode(
+            context: context,
+            fieldType: fieldType,
+            runtimeTypeInfo: runtimeTypeInfo,
+            refMode: refMode,
+            readTypeInfo: readTypeInfo
+        )
+    }
+
+    private static func readValueWithRefMode(
+        context: ReadContext,
+        fieldType: TypeMetaFieldType,
+        runtimeTypeInfo: DynamicTypeInfo?,
+        refMode: RefMode,
+        readTypeInfo: Bool
+    ) throws -> Any? {
         switch refMode {
         case .none:
-            return try context.buffer.readVarUInt32()
+            return try readFieldPayload(
+                context: context,
+                fieldType: fieldType,
+                runtimeTypeInfo: runtimeTypeInfo,
+                readTypeInfo: readTypeInfo
+            )
         case .nullOnly:
             let flag = try context.buffer.readInt8()
             if flag == RefFlag.null.rawValue {
                 return nil
             }
-            if flag != RefFlag.notNullValue.rawValue {
-                throw ForyError.invalidData("unexpected enum nullOnly flag 
\(flag)")
+            guard flag == RefFlag.notNullValue.rawValue else {
+                throw ForyError.invalidData("unexpected nullOnly flag \(flag)")
             }
-            return try context.buffer.readVarUInt32()
+            return try readFieldPayload(
+                context: context,
+                fieldType: fieldType,
+                runtimeTypeInfo: runtimeTypeInfo,
+                readTypeInfo: readTypeInfo
+            )
         case .tracking:
-            throw ForyError.invalidData("enum tracking ref mode is not 
supported")
+            let rawFlag = try context.buffer.readInt8()
+            guard let flag = RefFlag(rawValue: rawFlag) else {
+                throw ForyError.invalidData("unexpected tracking flag 
\(rawFlag)")
+            }
+
+            switch flag {
+            case .null:
+                return nil
+            case .ref:
+                let refID = try context.buffer.readVarUInt32()
+                return try context.refReader.readRefValue(refID)
+            case .refValue:
+                let refID = context.refReader.reserveRefID()
+                let value = try readFieldPayload(
+                    context: context,
+                    fieldType: fieldType,
+                    runtimeTypeInfo: runtimeTypeInfo,
+                    readTypeInfo: readTypeInfo
+                )
+                context.refReader.storeRef(value, at: refID)
+                return value
+            case .notNullValue:
+                return try readFieldPayload(
+                    context: context,
+                    fieldType: fieldType,
+                    runtimeTypeInfo: runtimeTypeInfo,
+                    readTypeInfo: readTypeInfo
+                )
+            }
         }
     }
 
-    private static func readFieldValue(
+    private static func readFieldPayload(
+        context: ReadContext,
+        fieldType: TypeMetaFieldType,
+        runtimeTypeInfo: DynamicTypeInfo?,
+        readTypeInfo: Bool
+    ) throws -> Any {
+        if let runtimeTypeInfo {
+            return try context.typeResolver.readDynamicValue(typeInfo: 
runtimeTypeInfo, context: context)
+        }
+        if readTypeInfo {
+            let typeInfo = try 
context.typeResolver.readDynamicTypeInfo(context: context)
+            return try context.typeResolver.readDynamicValue(typeInfo: 
typeInfo, context: context)
+        }
+
+        guard let resolvedTypeID = TypeId(rawValue: fieldType.typeID) else {
+            throw ForyError.invalidData("unknown compatible field type id 
\(fieldType.typeID)")
+        }
+
+        switch resolvedTypeID {
+        case .none:
+            return ForyAnyNullValue()
+        case .bool:
+            return try Bool.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int8:
+            return try Int8.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int16:
+            return try Int16.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int32:
+            return try ForyInt32Fixed.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .varint32:
+            return try Int32.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int64:
+            return try ForyInt64Fixed.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .varint64:
+            return try Int64.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .taggedInt64:
+            return try ForyInt64Tagged.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .uint8:
+            return try UInt8.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .uint16:
+            return try UInt16.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .uint32:
+            return try ForyUInt32Fixed.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .varUInt32:
+            return try UInt32.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .uint64:
+            return try ForyUInt64Fixed.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .varUInt64:
+            return try UInt64.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .taggedUInt64:
+            return try ForyUInt64Tagged.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .float16:
+            return try Float16.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .bfloat16:
+            return try BFloat16.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .float32:
+            return try Float.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .float64:
+            return try Double.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .string:
+            return try String.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .duration:
+            return try Duration.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .timestamp:
+            return try Date.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .date:
+            return try ForyDate.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .binary, .uint8Array:
+            return try Data.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .boolArray:
+            return try [Bool].foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int8Array:
+            return try [Int8].foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int16Array:
+            return try [Int16].foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int32Array:
+            return try [Int32].foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .int64Array:
+            return try [Int64].foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .uint16Array:
+            return try [UInt16].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .uint32Array:
+            return try [UInt32].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .uint64Array:
+            return try [UInt64].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .float16Array:
+            return try [Float16].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .bfloat16Array:
+            return try [BFloat16].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .float32Array:
+            return try [Float].foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .float64Array:
+            return try [Double].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .array, .list:
+            return try readCollection(context: context, fieldType: fieldType)
+        case .set:
+            return try readSet(context: context, fieldType: fieldType)
+        case .map:
+            return try readMap(context: context, fieldType: fieldType)
+        case .enumType, .namedEnum:
+            return try context.buffer.readVarUInt32()
+        default:
+            throw ForyError.invalidData("unsupported compatible field type id 
\(fieldType.typeID)")
+        }
+    }
+
+    private static func readCollection(
         context: ReadContext,
         fieldType: TypeMetaFieldType
-    ) throws -> Any? {
-        let refMode = RefMode.from(nullable: fieldType.nullable, trackRef: 
fieldType.trackRef)
-        switch fieldType.typeID {
-        case TypeId.bool.rawValue:
-            return fieldType.nullable
-                ? try Bool?.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-                : try Bool.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.int8.rawValue:
-            return fieldType.nullable
-                ? try Int8?.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-                : try Int8.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.int16.rawValue:
-            return fieldType.nullable
-                ? try Int16?.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-                : try Int16.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.varint32.rawValue:
-            return fieldType.nullable
-                ? try Int32?.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-                : try Int32.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.varint64.rawValue:
-            return fieldType.nullable
-                ? try Int64?.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-                : try Int64.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.float32.rawValue:
-            return fieldType.nullable
-                ? try Float?.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-                : try Float.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.float64.rawValue:
-            return fieldType.nullable
-                ? try Double?.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-                : try Double.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.string.rawValue:
-            return fieldType.nullable
-                ? try String?.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-                : try String.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.timestamp.rawValue:
-            return fieldType.nullable
-                ? try Date?.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-                : try Date.foryRead(context, refMode: refMode, readTypeInfo: 
false)
-        case TypeId.date.rawValue:
-            return fieldType.nullable
-                ? try ForyDate?.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-                : try ForyDate.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-        case TypeId.list.rawValue:
-            guard fieldType.generics.count == 1,
-                  fieldType.generics[0].typeID == TypeId.string.rawValue else {
-                throw ForyError.invalidData("unsupported compatible list 
element type")
+    ) throws -> [Any] {
+        let elementFieldType = fieldType.generics.first
+            ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: 
true)
+        let length = Int(try context.buffer.readVarUInt32())
+        try context.ensureCollectionLength(length, label: 
"compatible_collection")
+        if length == 0 {
+            return []
+        }
+
+        let header = try context.buffer.readUInt8()
+        let trackRef = (header & 0b0000_0001) != 0
+        let hasNull = (header & 0b0000_0010) != 0
+        let declared = (header & 0b0000_0100) != 0
+        let sameType = (header & 0b0000_1000) != 0
+
+        var runtimeTypeInfo: DynamicTypeInfo?
+        if sameType, !declared {
+            runtimeTypeInfo = try 
context.typeResolver.readDynamicTypeInfo(context: context)
+        }
+
+        for _ in 0..<length {
+            if sameType {
+                if trackRef {
+                    _ = try readValueWithRefMode(
+                        context: context,
+                        fieldType: elementFieldType,
+                        runtimeTypeInfo: runtimeTypeInfo,
+                        refMode: .tracking,
+                        readTypeInfo: false
+                    )
+                } else if hasNull {
+                    let refFlag = try context.buffer.readInt8()
+                    if refFlag == RefFlag.null.rawValue {
+                        continue
+                    }
+                    if refFlag != RefFlag.notNullValue.rawValue {
+                        throw ForyError.invalidData("invalid collection 
nullability flag \(refFlag)")
+                    }
+                    _ = try readFieldPayload(
+                        context: context,
+                        fieldType: elementFieldType,
+                        runtimeTypeInfo: runtimeTypeInfo,
+                        readTypeInfo: false
+                    )
+                } else {
+                    _ = try readFieldPayload(
+                        context: context,
+                        fieldType: elementFieldType,
+                        runtimeTypeInfo: runtimeTypeInfo,
+                        readTypeInfo: false
+                    )
+                }
+                continue
             }
-            return fieldType.nullable
-                ? try [String]?.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-                : try [String].foryRead(context, refMode: refMode, 
readTypeInfo: false)
-        case TypeId.set.rawValue:
-            guard fieldType.generics.count == 1,
-                  fieldType.generics[0].typeID == TypeId.string.rawValue else {
-                throw ForyError.invalidData("unsupported compatible set 
element type")
+
+            if trackRef {
+                _ = try readValueWithRefMode(
+                    context: context,
+                    fieldType: elementFieldType,
+                    runtimeTypeInfo: nil,
+                    refMode: .tracking,
+                    readTypeInfo: true
+                )
+            } else if hasNull {
+                let refFlag = try context.buffer.readInt8()
+                if refFlag == RefFlag.null.rawValue {
+                    continue
+                }
+                if refFlag != RefFlag.notNullValue.rawValue {
+                    throw ForyError.invalidData("invalid collection 
nullability flag \(refFlag)")
+                }
+                _ = try readFieldPayload(
+                    context: context,
+                    fieldType: elementFieldType,
+                    runtimeTypeInfo: nil,
+                    readTypeInfo: true
+                )
+            } else {
+                _ = try readFieldPayload(
+                    context: context,
+                    fieldType: elementFieldType,
+                    runtimeTypeInfo: nil,
+                    readTypeInfo: true
+                )
             }
-            return fieldType.nullable
-                ? try Set<String>?.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-                : try Set<String>.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-        case TypeId.map.rawValue:
-            guard fieldType.generics.count == 2,
-                  fieldType.generics[0].typeID == TypeId.string.rawValue,
-                  fieldType.generics[1].typeID == TypeId.string.rawValue else {
-                throw ForyError.invalidData("unsupported compatible map 
key/value type")
+        }
+
+        return []
+    }
+
+    private static func readSet(
+        context: ReadContext,
+        fieldType: TypeMetaFieldType
+    ) throws -> Set<AnyHashable> {
+        _ = try readCollection(context: context, fieldType: fieldType)
+        return []
+    }
+
+    private static func readMap(
+        context: ReadContext,
+        fieldType: TypeMetaFieldType
+    ) throws -> [AnyHashable: Any] {
+        let keyType = fieldType.generics.first
+            ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: 
true)
+        let valueType = fieldType.generics.dropFirst().first
+            ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: 
true)
+
+        let totalLength = Int(try context.buffer.readVarUInt32())
+        try context.ensureCollectionLength(totalLength, label: 
"compatible_map")
+        if totalLength == 0 {
+            return [:]
+        }
+
+        var readCount = 0
+        while readCount < totalLength {
+            let header = try context.buffer.readUInt8()
+            let trackKeyRef = (header & 0b0000_0001) != 0
+            let keyNull = (header & 0b0000_0010) != 0
+            let keyDeclared = (header & 0b0000_0100) != 0
+
+            let trackValueRef = (header & 0b0000_1000) != 0
+            let valueNull = (header & 0b0001_0000) != 0
+            let valueDeclared = (header & 0b0010_0000) != 0
+
+            if keyNull && valueNull {
+                readCount += 1
+                continue
             }
-            return fieldType.nullable
-                ? try [String: String]?.foryRead(context, refMode: refMode, 
readTypeInfo: false)
-                : try [String: String].foryRead(context, refMode: refMode, 
readTypeInfo: false)
-        case TypeId.enumType.rawValue:
-            return try readEnumOrdinal(context, refMode: refMode)
-        default:
-            throw ForyError.invalidData("unsupported compatible field type id 
\(fieldType.typeID)")
+
+            if keyNull {
+                let valueRuntimeType = valueDeclared ? nil : try 
context.typeResolver.readDynamicTypeInfo(context: context)
+                _ = try readValueWithRefMode(
+                    context: context,
+                    fieldType: valueType,
+                    runtimeTypeInfo: valueRuntimeType,
+                    refMode: trackValueRef ? .tracking : .none,
+                    readTypeInfo: false
+                )
+                readCount += 1
+                continue
+            }
+
+            if valueNull {
+                let keyRuntimeType = keyDeclared ? nil : try 
context.typeResolver.readDynamicTypeInfo(context: context)
+                _ = try readValueWithRefMode(
+                    context: context,
+                    fieldType: keyType,
+                    runtimeTypeInfo: keyRuntimeType,
+                    refMode: trackKeyRef ? .tracking : .none,
+                    readTypeInfo: false
+                )
+                readCount += 1
+                continue
+            }
+
+            let chunkSize = Int(try context.buffer.readUInt8())
+            if chunkSize <= 0 {
+                throw ForyError.invalidData("invalid map chunk size 
\(chunkSize)")
+            }
+            if chunkSize > (totalLength - readCount) {
+                throw ForyError.invalidData("map chunk size exceeds remaining 
entries")
+            }
+
+            let keyRuntimeType = keyDeclared ? nil : try 
context.typeResolver.readDynamicTypeInfo(context: context)
+            let valueRuntimeType = valueDeclared ? nil : try 
context.typeResolver.readDynamicTypeInfo(context: context)
+
+            for _ in 0..<chunkSize {
+                _ = try readValueWithRefMode(
+                    context: context,
+                    fieldType: keyType,
+                    runtimeTypeInfo: keyRuntimeType,
+                    refMode: trackKeyRef ? .tracking : .none,
+                    readTypeInfo: false
+                )
+                _ = try readValueWithRefMode(
+                    context: context,
+                    fieldType: valueType,
+                    runtimeTypeInfo: valueRuntimeType,
+                    refMode: trackValueRef ? .tracking : .none,
+                    readTypeInfo: false
+                )
+            }
+            readCount += chunkSize
         }
+
+        return [:]
     }
 }
diff --git a/swift/Sources/Fory/Fory.swift b/swift/Sources/Fory/Fory.swift
index 99019aeca..9edb7a6c5 100644
--- a/swift/Sources/Fory/Fory.swift
+++ b/swift/Sources/Fory/Fory.swift
@@ -22,17 +22,26 @@ public struct ForyConfig {
     public var trackRef: Bool
     public var compatible: Bool
     public var checkClassVersion: Bool
+    public var maxCollectionLength: Int
+    public var maxBinaryLength: Int
+    public var maxDepth: Int
 
     public init(
         xlang: Bool = true,
         trackRef: Bool = false,
         compatible: Bool = false,
-        checkClassVersion: Bool = true
+        checkClassVersion: Bool = true,
+        maxCollectionLength: Int = 1_000_000,
+        maxBinaryLength: Int = 64 * 1024 * 1024,
+        maxDepth: Int = 5
     ) {
         self.xlang = xlang
         self.trackRef = trackRef
         self.compatible = compatible
         self.checkClassVersion = checkClassVersion
+        self.maxCollectionLength = maxCollectionLength
+        self.maxBinaryLength = maxBinaryLength
+        self.maxDepth = maxDepth
     }
 }
 
@@ -56,6 +65,7 @@ private final class ForyRuntimeContext {
             trackRef: config.trackRef,
             compatible: config.compatible,
             checkClassVersion: config.checkClassVersion,
+            maxDepth: config.maxDepth,
             compatibleTypeDefState: CompatibleTypeDefWriteState(),
             metaStringWriteState: MetaStringWriteState()
         )
@@ -67,6 +77,9 @@ private final class ForyRuntimeContext {
             trackRef: config.trackRef,
             compatible: config.compatible,
             checkClassVersion: config.checkClassVersion,
+            maxCollectionLength: config.maxCollectionLength,
+            maxBinaryLength: config.maxBinaryLength,
+            maxDepth: config.maxDepth,
             compatibleTypeDefState: CompatibleTypeDefReadState(),
             metaStringReadState: MetaStringReadState()
         )
@@ -138,14 +151,20 @@ public final class Fory {
         xlang: Bool = true,
         trackRef: Bool = false,
         compatible: Bool = false,
-        checkClassVersion: Bool? = nil
+        checkClassVersion: Bool? = nil,
+        maxCollectionLength: Int = 1_000_000,
+        maxBinaryLength: Int = 64 * 1024 * 1024,
+        maxDepth: Int = 5
     ) {
         let effectiveCheckClassVersion = checkClassVersion ?? (xlang && 
!compatible)
         self.config = ForyConfig(
             xlang: xlang,
             trackRef: trackRef,
             compatible: compatible,
-            checkClassVersion: effectiveCheckClassVersion
+            checkClassVersion: effectiveCheckClassVersion,
+            maxCollectionLength: maxCollectionLength,
+            maxBinaryLength: maxBinaryLength,
+            maxDepth: maxDepth
         )
         self.typeResolver = TypeResolver()
         self.instanceID = Self.allocateInstanceID()
@@ -156,7 +175,10 @@ public final class Fory {
             xlang: config.xlang,
             trackRef: config.trackRef,
             compatible: config.compatible,
-            checkClassVersion: config.checkClassVersion
+            checkClassVersion: config.checkClassVersion,
+            maxCollectionLength: config.maxCollectionLength,
+            maxBinaryLength: config.maxBinaryLength,
+            maxDepth: config.maxDepth
         )
     }
 
@@ -534,6 +556,7 @@ public final class Fory {
             trackRef: config.trackRef,
             compatible: config.compatible,
             checkClassVersion: config.checkClassVersion,
+            maxDepth: config.maxDepth,
             compatibleTypeDefState: CompatibleTypeDefWriteState(),
             metaStringWriteState: MetaStringWriteState()
         )
@@ -547,6 +570,9 @@ public final class Fory {
             trackRef: config.trackRef,
             compatible: config.compatible,
             checkClassVersion: config.checkClassVersion,
+            maxCollectionLength: config.maxCollectionLength,
+            maxBinaryLength: config.maxBinaryLength,
+            maxDepth: config.maxDepth,
             compatibleTypeDefState: CompatibleTypeDefReadState(),
             metaStringReadState: MetaStringReadState()
         )
@@ -602,20 +628,10 @@ public final class Fory {
         }
 
         runtimeContext.readInUse = true
-        let shouldReplace = data.withUnsafeBytes { rawBytes in
-            if rawBytes.count != runtimeContext.lastReadDataCount {
-                return true
-            }
-            return rawBytes.baseAddress != runtimeContext.lastReadDataAddress
-        }
-        if shouldReplace {
-            runtimeContext.readBuffer.replace(with: data)
-            data.withUnsafeBytes { rawBytes in
-                runtimeContext.lastReadDataAddress = rawBytes.baseAddress
-                runtimeContext.lastReadDataCount = rawBytes.count
-            }
-        } else {
-            runtimeContext.readBuffer.setCursor(0)
+        runtimeContext.readBuffer.replace(with: data)
+        data.withUnsafeBytes { rawBytes in
+            runtimeContext.lastReadDataAddress = rawBytes.baseAddress
+            runtimeContext.lastReadDataCount = rawBytes.count
         }
         defer {
             runtimeContext.readContext.reset()
@@ -673,7 +689,11 @@ public final class Fory {
             if try readHead(buffer: context.buffer) {
                 return nilValue()
             }
-            return try body(context)
+            let value = try body(context)
+            if context.buffer.remaining != 0 {
+                throw ForyError.invalidData("unexpected trailing bytes at 
root: \(context.buffer.remaining)")
+            }
+            return value
         }
     }
 
diff --git a/swift/Sources/Fory/MetaString.swift 
b/swift/Sources/Fory/MetaString.swift
index cc128fe2a..72dabec5e 100644
--- a/swift/Sources/Fory/MetaString.swift
+++ b/swift/Sources/Fory/MetaString.swift
@@ -57,13 +57,16 @@ public struct MetaString: Equatable, Hashable, Sendable {
     }
 
     public static func empty(specialChar1: Character, specialChar2: Character) 
-> MetaString {
-        try! MetaString(
+        guard let emptyMetaString = try? MetaString(
             value: "",
             encoding: .utf8,
             specialChar1: specialChar1,
             specialChar2: specialChar2,
             bytes: []
-        )
+        ) else {
+            preconditionFailure("failed to create empty MetaString")
+        }
+        return emptyMetaString
     }
 }
 
@@ -176,11 +179,11 @@ public struct MetaStringEncoder: Sendable {
         var canLowerUpperDigitSpecial = true
 
         for scalar in input.unicodeScalars {
-            let c = Character(scalar)
+            let character = Character(scalar)
             if canLowerSpecial {
                 let isValid =
                     (scalar.value >= 97 && scalar.value <= 122) ||
-                    c == "." || c == "_" || c == "$" || c == "|"
+                    character == "." || character == "_" || character == "$" 
|| character == "|"
                 if !isValid {
                     canLowerSpecial = false
                 }
@@ -189,7 +192,7 @@ public struct MetaStringEncoder: Sendable {
                 let isLower = scalar.value >= 97 && scalar.value <= 122
                 let isUpper = scalar.value >= 65 && scalar.value <= 90
                 let isDigit = scalar.value >= 48 && scalar.value <= 57
-                let isSpecial = c == specialChar1 || c == specialChar2
+                let isSpecial = character == specialChar1 || character == 
specialChar2
                 if !(isLower || isUpper || isDigit || isSpecial) {
                     canLowerUpperDigitSpecial = false
                 }
@@ -211,8 +214,7 @@ public struct MetaStringEncoder: Sendable {
             }
             if upperCount == 1,
                input.first?.isUppercase == true,
-               allow(.firstToLowerSpecial)
-            {
+               allow(.firstToLowerSpecial) {
                 return .firstToLowerSpecial
             }
             if ((input.count + upperCount) * 5) < (input.count * 6), 
allow(.allToLowerSpecial) {
@@ -236,10 +238,10 @@ public struct MetaStringEncoder: Sendable {
         var bytes = Array(repeating: UInt8(0), count: byteLength)
         var currentBit = 1
 
-        for c in chars {
-            let value = try mapper(c)
-            for i in stride(from: bitsPerChar - 1, through: 0, by: -1) {
-                if ((value >> UInt8(i)) & 0x01) != 0 {
+        for character in chars {
+            let value = try mapper(character)
+            for bitOffset in stride(from: bitsPerChar - 1, through: 0, by: -1) 
{
+                if ((value >> UInt8(bitOffset)) & 0x01) != 0 {
                     let bytePos = currentBit / 8
                     let bitPos = currentBit % 8
                     bytes[bytePos] |= UInt8(1 << (7 - bitPos))
@@ -254,14 +256,14 @@ public struct MetaStringEncoder: Sendable {
         return bytes
     }
 
-    private func mapLowerSpecial(_ c: Character) throws -> UInt8 {
-        guard let scalar = c.unicodeScalars.first, c.unicodeScalars.count == 1 
else {
+    private func mapLowerSpecial(_ character: Character) throws -> UInt8 {
+        guard let scalar = character.unicodeScalars.first, 
character.unicodeScalars.count == 1 else {
             throw ForyError.encodingError("unsupported character in 
LOWER_SPECIAL")
         }
         if scalar.value >= 97 && scalar.value <= 122 {
             return UInt8(scalar.value - 97)
         }
-        switch c {
+        switch character {
         case ".": return 26
         case "_": return 27
         case "$": return 28
@@ -271,8 +273,8 @@ public struct MetaStringEncoder: Sendable {
         }
     }
 
-    private func mapLowerUpperDigitSpecial(_ c: Character) throws -> UInt8 {
-        guard let scalar = c.unicodeScalars.first, c.unicodeScalars.count == 1 
else {
+    private func mapLowerUpperDigitSpecial(_ character: Character) throws -> 
UInt8 {
+        guard let scalar = character.unicodeScalars.first, 
character.unicodeScalars.count == 1 else {
             throw ForyError.encodingError("unsupported character in 
LOWER_UPPER_DIGIT_SPECIAL")
         }
         if scalar.value >= 97 && scalar.value <= 122 {
@@ -284,10 +286,10 @@ public struct MetaStringEncoder: Sendable {
         if scalar.value >= 48 && scalar.value <= 57 {
             return UInt8(52 + scalar.value - 48)
         }
-        if c == specialChar1 {
+        if character == specialChar1 {
             return 62
         }
-        if c == specialChar2 {
+        if character == specialChar2 {
             return 63
         }
         throw ForyError.encodingError("unsupported character in 
LOWER_UPPER_DIGIT_SPECIAL")
@@ -304,12 +306,12 @@ public struct MetaStringEncoder: Sendable {
     private func escapeAllUpper(_ input: String) -> String {
         var out = String()
         out.reserveCapacity(input.count * 2)
-        for c in input {
-            if c.isUppercase {
+        for character in input {
+            if character.isUppercase {
                 out.append("|")
-                out.append(String(c).lowercased())
+                out.append(String(character).lowercased())
             } else {
-                out.append(c)
+                out.append(character)
             }
         }
         return out
@@ -340,7 +342,10 @@ public struct MetaStringDecoder: Sendable {
         let value: String
         switch encoding {
         case .utf8:
-            value = String(decoding: bytes, as: UTF8.self)
+            guard let decoded = String(bytes: bytes, encoding: .utf8) else {
+                throw ForyError.encodingError("invalid UTF-8 meta string 
payload")
+            }
+            value = decoded
         case .lowerSpecial:
             value = try decodeGeneric(bytes: bytes, bitsPerChar: 5, mapper: 
unmapLowerSpecial)
         case .lowerUpperDigitSpecial:
@@ -431,12 +436,12 @@ public struct MetaStringDecoder: Sendable {
     private func unescapeAllUpper(_ input: String) -> String {
         var out = String()
         out.reserveCapacity(input.count)
-        var it = input.makeIterator()
-        while let c = it.next() {
-            if c == "|", let next = it.next() {
-                out.append(String(next).uppercased())
+        var iterator = input.makeIterator()
+        while let currentCharacter = iterator.next() {
+            if currentCharacter == "|", let nextCharacter = iterator.next() {
+                out.append(String(nextCharacter).uppercased())
             } else {
-                out.append(c)
+                out.append(currentCharacter)
             }
         }
         return out
diff --git a/swift/Sources/Fory/MurmurHash3.swift 
b/swift/Sources/Fory/MurmurHash3.swift
index bbde19a19..aef3c9d48 100644
--- a/swift/Sources/Fory/MurmurHash3.swift
+++ b/swift/Sources/Fory/MurmurHash3.swift
@@ -29,8 +29,8 @@ enum MurmurHash3 {
         let nblocks = length / 16
 
         if nblocks > 0 {
-            for i in 0..<nblocks {
-                let base = i * 16
+            for blockIndex in 0..<nblocks {
+                let base = blockIndex * 16
                 var k1 = readUInt64LE(bytes, offset: base)
                 var k2 = readUInt64LE(bytes, offset: base + 8)
 
@@ -142,17 +142,17 @@ enum MurmurHash3 {
         return value
     }
 
-    private static func rotl64(_ x: UInt64, _ r: UInt64) -> UInt64 {
-        (x << r) | (x >> (64 - r))
+    private static func rotl64(_ value: UInt64, _ rotationBits: UInt64) -> 
UInt64 {
+        (value << rotationBits) | (value >> (64 - rotationBits))
     }
 
     private static func fmix64(_ value: UInt64) -> UInt64 {
-        var x = value
-        x ^= x >> 33
-        x &*= 0xff51afd7ed558ccd
-        x ^= x >> 33
-        x &*= 0xc4ceb9fe1a85ec53
-        x ^= x >> 33
-        return x
+        var mixed = value
+        mixed ^= mixed >> 33
+        mixed &*= 0xff51afd7ed558ccd
+        mixed ^= mixed >> 33
+        mixed &*= 0xc4ceb9fe1a85ec53
+        mixed ^= mixed >> 33
+        return mixed
     }
 }
diff --git a/swift/Sources/Fory/OptionalSerializer.swift 
b/swift/Sources/Fory/OptionalSerializer.swift
index bad89c615..70f38bcf7 100644
--- a/swift/Sources/Fory/OptionalSerializer.swift
+++ b/swift/Sources/Fory/OptionalSerializer.swift
@@ -18,7 +18,7 @@
 import Foundation
 
 extension Optional: Serializer where Wrapped: Serializer {
-    public static func foryDefault() -> Optional<Wrapped> {
+    public static func foryDefault() -> Wrapped? {
         nil
     }
 
@@ -45,7 +45,7 @@ extension Optional: Serializer where Wrapped: Serializer {
         try wrapped.foryWriteData(context, hasGenerics: hasGenerics)
     }
 
-    public static func foryReadData(_ context: ReadContext) throws -> 
Optional<Wrapped> {
+    public static func foryReadData(_ context: ReadContext) throws -> Wrapped? 
{
         .some(try Wrapped.foryReadData(context))
     }
 
@@ -89,7 +89,7 @@ extension Optional: Serializer where Wrapped: Serializer {
         _ context: ReadContext,
         refMode: RefMode,
         readTypeInfo: Bool
-    ) throws -> Optional<Wrapped> {
+    ) throws -> Wrapped? {
         switch refMode {
         case .none:
             return .some(try Wrapped.foryRead(context, refMode: .none, 
readTypeInfo: readTypeInfo))
diff --git a/swift/Sources/Fory/PrimitiveSerializers.swift 
b/swift/Sources/Fory/PrimitiveSerializers.swift
index c2531c45d..b1b010612 100644
--- a/swift/Sources/Fory/PrimitiveSerializers.swift
+++ b/swift/Sources/Fory/PrimitiveSerializers.swift
@@ -315,6 +315,41 @@ extension Double: Serializer {
     }
 }
 
+public struct BFloat16: Serializer, Equatable, Hashable, Sendable {
+    public var rawValue: UInt16
+
+    public init(rawValue: UInt16 = 0) {
+        self.rawValue = rawValue
+    }
+
+    public static func foryDefault() -> BFloat16 { .init() }
+    public static var staticTypeId: TypeId { .bfloat16 }
+
+    public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) 
throws {
+        _ = hasGenerics
+        context.buffer.writeUInt16(rawValue)
+    }
+
+    public static func foryReadData(_ context: ReadContext) throws -> BFloat16 
{
+        .init(rawValue: try context.buffer.readUInt16())
+    }
+}
+
+extension Float16: Serializer {
+    public static var staticTypeId: TypeId { .float16 }
+
+    public static func foryDefault() -> Float16 { 0 }
+
+    public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) 
throws {
+        _ = hasGenerics
+        context.buffer.writeUInt16(bitPattern)
+    }
+
+    public static func foryReadData(_ context: ReadContext) throws -> Float16 {
+        Float16(bitPattern: try context.buffer.readUInt16())
+    }
+}
+
 private enum StringEncoding: UInt64 {
     case latin1 = 0
     case utf16 = 1
@@ -386,7 +421,10 @@ extension Data: Serializer {
 
     public static func foryReadData(_ context: ReadContext) throws -> Data {
         let length = try context.buffer.readVarUInt32()
-        let bytes = try context.buffer.readBytes(count: Int(length))
+        let byteLength = Int(length)
+        try context.ensureBinaryLength(byteLength, label: "binary")
+        try context.ensureRemainingBytes(byteLength, label: "binary")
+        let bytes = try context.buffer.readBytes(count: byteLength)
         return Data(bytes)
     }
 }
diff --git a/swift/Sources/Fory/TypeMeta.swift 
b/swift/Sources/Fory/TypeMeta.swift
index d85b61f7c..4e4585aa0 100644
--- a/swift/Sources/Fory/TypeMeta.swift
+++ b/swift/Sources/Fory/TypeMeta.swift
@@ -32,20 +32,20 @@ private let noUserTypeID: UInt32 = UInt32.max
 public let namespaceMetaStringEncodings: [MetaStringEncoding] = [
     .utf8,
     .allToLowerSpecial,
-    .lowerUpperDigitSpecial,
+    .lowerUpperDigitSpecial
 ]
 
 public let typeNameMetaStringEncodings: [MetaStringEncoding] = [
     .utf8,
     .allToLowerSpecial,
     .lowerUpperDigitSpecial,
-    .firstToLowerSpecial,
+    .firstToLowerSpecial
 ]
 
 public let fieldNameMetaStringEncodings: [MetaStringEncoding] = [
     .utf8,
     .allToLowerSpecial,
-    .lowerUpperDigitSpecial,
+    .lowerUpperDigitSpecial
 ]
 
 public struct TypeMetaFieldType: Equatable, Sendable {
@@ -372,6 +372,11 @@ public struct TypeMeta: Equatable, Sendable {
         }
 
         var fieldInfos: [TypeMetaFieldInfo] = []
+        if numFields > bodyReader.remaining {
+            throw ForyError.invalidData(
+                "type meta field count \(numFields) exceeds remaining bytes 
\(bodyReader.remaining)"
+            )
+        }
         fieldInfos.reserveCapacity(numFields)
         for _ in 0..<numFields {
             fieldInfos.append(try TypeMetaFieldInfo.read(bodyReader))
diff --git a/swift/Sources/Fory/TypeResolver.swift 
b/swift/Sources/Fory/TypeResolver.swift
index 36c2c4e09..b63dd3a48 100644
--- a/swift/Sources/Fory/TypeResolver.swift
+++ b/swift/Sources/Fory/TypeResolver.swift
@@ -17,7 +17,7 @@
 
 import Foundation
 
-public struct RegisteredTypeInfo {
+public struct RegisteredTypeInfo: Equatable {
     public let userTypeID: UInt32?
     public let kind: TypeId
     public let registerByName: Bool
@@ -51,6 +51,7 @@ private enum DynamicRegistrationMode {
 }
 
 private struct TypeReader {
+    let swiftType: ObjectIdentifier
     let kind: TypeId
     let reader: (ReadContext) throws -> Any
     let compatibleReader: (ReadContext, TypeMeta) throws -> Any
@@ -65,7 +66,16 @@ public final class TypeResolver {
     public init() {}
 
     public func register<T: Serializer>(_ type: T.Type, id: UInt32) {
+        do {
+            try registerByID(type, id: id)
+        } catch {
+            preconditionFailure("conflicting registration for \(type): 
\(error)")
+        }
+    }
+
+    private func registerByID<T: Serializer>(_ type: T.Type, id: UInt32) 
throws {
         let key = ObjectIdentifier(type)
+        try validateIDRegistration(key: key, type: type, id: id)
         let info = RegisteredTypeInfo(
             userTypeID: id,
             kind: T.staticTypeId,
@@ -73,9 +83,13 @@ public final class TypeResolver {
             namespace: nil,
             typeName: MetaString.empty(specialChar1: "$", specialChar2: "_")
         )
+        if bySwiftType[key] == info {
+            return
+        }
         bySwiftType[key] = info
         markRegistrationMode(kind: info.kind, registerByName: false)
         byUserTypeID[id] = TypeReader(
+            swiftType: key,
             kind: T.staticTypeId,
             reader: { context in
                 try T.foryRead(context, refMode: .none, readTypeInfo: false)
@@ -97,6 +111,12 @@ public final class TypeResolver {
             allowedEncodings: typeNameMetaStringEncodings
         )
         let key = ObjectIdentifier(type)
+        try validateNameRegistration(
+            key: key,
+            type: type,
+            namespace: namespace,
+            typeName: typeName
+        )
         let info = RegisteredTypeInfo(
             userTypeID: nil,
             kind: T.staticTypeId,
@@ -104,9 +124,13 @@ public final class TypeResolver {
             namespace: namespaceMeta,
             typeName: typeNameMeta
         )
+        if bySwiftType[key] == info {
+            return
+        }
         bySwiftType[key] = info
         markRegistrationMode(kind: info.kind, registerByName: true)
         byTypeName[TypeNameKey(namespace: namespace, typeName: typeName)] = 
TypeReader(
+            swiftType: key,
             kind: T.staticTypeId,
             reader: { context in
                 try T.foryRead(context, refMode: .none, readTypeInfo: false)
@@ -254,7 +278,14 @@ public final class TypeResolver {
                     compatibleTypeMeta: nil
                 )
             case .mixed:
-                throw ForyError.invalidData("ambiguous dynamic type 
registration mode for \(wireTypeID)")
+                // Wire ids for user kinds are explicit: plain ids always 
carry user_type_id.
+                return DynamicTypeInfo(
+                    wireTypeID: wireTypeID,
+                    userTypeID: try context.buffer.readVarUInt32(),
+                    namespace: nil,
+                    typeName: nil,
+                    compatibleTypeMeta: nil
+                )
             }
         default:
             return DynamicTypeInfo(
@@ -268,6 +299,9 @@ public final class TypeResolver {
     }
 
     public func readDynamicValue(typeInfo: DynamicTypeInfo, context: 
ReadContext) throws -> Any {
+        try context.enterDynamicAnyDepth()
+        defer { context.leaveDynamicAnyDepth() }
+
         let value: Any
         switch typeInfo.wireTypeID {
         case .bool:
@@ -300,12 +334,18 @@ public final class TypeResolver {
             value = try UInt64.foryRead(context, refMode: .none, readTypeInfo: 
false)
         case .taggedUInt64:
             value = try ForyUInt64Tagged.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .float16:
+            value = try Float16.foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .bfloat16:
+            value = try BFloat16.foryRead(context, refMode: .none, 
readTypeInfo: false)
         case .float32:
             value = try Float.foryRead(context, refMode: .none, readTypeInfo: 
false)
         case .float64:
             value = try Double.foryRead(context, refMode: .none, readTypeInfo: 
false)
         case .string:
             value = try String.foryRead(context, refMode: .none, readTypeInfo: 
false)
+        case .duration:
+            value = try Duration.foryRead(context, refMode: .none, 
readTypeInfo: false)
         case .timestamp:
             value = try Date.foryRead(context, refMode: .none, readTypeInfo: 
false)
         case .date:
@@ -328,12 +368,18 @@ public final class TypeResolver {
             value = try [UInt32].foryRead(context, refMode: .none, 
readTypeInfo: false)
         case .uint64Array:
             value = try [UInt64].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .float16Array:
+            value = try [Float16].foryRead(context, refMode: .none, 
readTypeInfo: false)
+        case .bfloat16Array:
+            value = try [BFloat16].foryRead(context, refMode: .none, 
readTypeInfo: false)
         case .float32Array:
             value = try [Float].foryRead(context, refMode: .none, 
readTypeInfo: false)
         case .float64Array:
             value = try [Double].foryRead(context, refMode: .none, 
readTypeInfo: false)
-        case .list:
+        case .array, .list:
             value = try context.readAnyList(refMode: .none) ?? []
+        case .set:
+            value = try Set<AnyHashable>.foryRead(context, refMode: .none, 
readTypeInfo: false)
         case .map:
             value = try readDynamicAnyMapValue(context: context)
         case .structType, .enumType, .ext, .typedUnion:
@@ -404,6 +450,60 @@ public final class TypeResolver {
         return mode
     }
 
+    private func validateIDRegistration<T: Serializer>(
+        key: ObjectIdentifier,
+        type: T.Type,
+        id: UInt32
+    ) throws {
+        if let existing = bySwiftType[key] {
+            if existing.registerByName {
+                throw ForyError.invalidData(
+                    "\(type) was already registered by name, cannot 
re-register by id"
+                )
+            }
+            if existing.kind != T.staticTypeId || existing.userTypeID != id {
+                let existingID = existing.userTypeID.map { String($0) } ?? 
"nil"
+                throw ForyError.invalidData(
+                    "\(type) registration conflict: existing id=\(existingID), 
new id=\(id)"
+                )
+            }
+        }
+
+        if let existing = byUserTypeID[id], existing.swiftType != key {
+            throw ForyError.invalidData("user type id \(id) is already 
registered by another type")
+        }
+    }
+
+    private func validateNameRegistration<T: Serializer>(
+        key: ObjectIdentifier,
+        type: T.Type,
+        namespace: String,
+        typeName: String
+    ) throws {
+        if let existing = bySwiftType[key] {
+            if !existing.registerByName {
+                throw ForyError.invalidData(
+                    "\(type) was already registered by id, cannot re-register 
by name"
+                )
+            }
+            if existing.kind != T.staticTypeId ||
+                existing.namespace?.value != namespace ||
+                existing.typeName.value != typeName {
+                throw ForyError.invalidData(
+                    """
+                    \(type) registration conflict: existing 
name=\(existing.namespace?.value ?? "")::\(existing.typeName.value), \
+                    new name=\(namespace)::\(typeName)
+                    """
+                )
+            }
+        }
+
+        let nameKey = TypeNameKey(namespace: namespace, typeName: typeName)
+        if let existing = byTypeName[nameKey], existing.swiftType != key {
+            throw ForyError.invalidData("type name \(namespace)::\(typeName) 
is already registered by another type")
+        }
+    }
+
     private static func readMetaString(
         buffer: ByteBuffer,
         decoder: MetaStringDecoder,
diff --git a/swift/Sources/ForyMacro/ForyObjectMacro.swift 
b/swift/Sources/ForyMacro/ForyObjectMacro.swift
index dd951b6aa..c29a2f252 100644
--- a/swift/Sources/ForyMacro/ForyObjectMacro.swift
+++ b/swift/Sources/ForyMacro/ForyObjectMacro.swift
@@ -68,7 +68,7 @@ public struct ForyObjectMacro: MemberMacro, ExtensionMacro {
             writeWrapperDecl,
             readWrapperDecl,
             writeDecl,
-            readDecl,
+            readDecl
         ].compactMap { $0 }
     }
 
@@ -972,7 +972,13 @@ private func buildWriteDataDecl(sortedFields: 
[ParsedField]) -> String {
     }
     let schemaBody = schemaBodyLines.joined(separator: "\n        ")
 
-    let compatibleWriteLines = compatibleLines.isEmpty ? "\n            _ = 
hasGenerics" : "\n            \(compatibleLines.joined(separator: "\n           
 "))"
+    let compatibleWriteLines: String
+    if compatibleLines.isEmpty {
+        compatibleWriteLines = "\n            _ = hasGenerics"
+    } else {
+        let joinedCompatibleLines = compatibleLines.joined(separator: "\n      
      ")
+        compatibleWriteLines = "\n            \(joinedCompatibleLines)"
+    }
 
     return """
     @inlinable
@@ -1045,9 +1051,23 @@ private func schemaWriteLine(for field: ParsedField) -> 
String {
     if let codecType = field.customCodecType {
         let refMode = fieldRefModeExpression(field)
         if field.isOptional {
-            return "try (self.\(field.name).map { \(codecType)(rawValue: $0) 
}).foryWrite(context, refMode: \(refMode), writeTypeInfo: false, hasGenerics: 
false)"
+            return """
+            try (self.\(field.name).map { \(codecType)(rawValue: $0) 
}).foryWrite(
+                context,
+                refMode: \(refMode),
+                writeTypeInfo: false,
+                hasGenerics: false
+            )
+            """
         }
-        return "try \(codecType)(rawValue: 
self.\(field.name)).foryWrite(context, refMode: \(refMode), writeTypeInfo: 
false, hasGenerics: false)"
+        return """
+        try \(codecType)(rawValue: self.\(field.name)).foryWrite(
+            context,
+            refMode: \(refMode),
+            writeTypeInfo: false,
+            hasGenerics: false
+        )
+        """
     }
     if !field.isOptional, field.typeID != 27 {
         if let primitiveLine = primitiveSchemaWriteLine(field) {
@@ -1071,11 +1091,32 @@ private func compatibleWriteLine(for field: 
ParsedField) -> String {
     let hasGenerics = field.isCollection ? "true" : "false"
     if let codecType = field.customCodecType {
         if field.isOptional {
-            return "try (self.\(field.name).map { \(codecType)(rawValue: $0) 
}).foryWrite(context, refMode: \(refMode), writeTypeInfo: false, hasGenerics: 
false)"
+            return """
+            try (self.\(field.name).map { \(codecType)(rawValue: $0) 
}).foryWrite(
+                context,
+                refMode: \(refMode),
+                writeTypeInfo: false,
+                hasGenerics: false
+            )
+            """
         }
-        return "try \(codecType)(rawValue: 
self.\(field.name)).foryWrite(context, refMode: \(refMode), writeTypeInfo: 
false, hasGenerics: false)"
+        return """
+        try \(codecType)(rawValue: self.\(field.name)).foryWrite(
+            context,
+            refMode: \(refMode),
+            writeTypeInfo: false,
+            hasGenerics: false
+        )
+        """
     }
-    return "try self.\(field.name).foryWrite(context, refMode: \(refMode), 
writeTypeInfo: TypeId.needsTypeInfoForField(\(field.typeText).staticTypeId), 
hasGenerics: \(hasGenerics))"
+    return """
+    try self.\(field.name).foryWrite(
+        context,
+        refMode: \(refMode),
+        writeTypeInfo: 
TypeId.needsTypeInfoForField(\(field.typeText).staticTypeId),
+        hasGenerics: \(hasGenerics)
+    )
+    """
 }
 
 private func buildReadDataDecl(isClass: Bool, fields: [ParsedField], 
sortedFields: [ParsedField]) -> String {
@@ -1583,16 +1624,66 @@ private func classifyType(_ typeText: String) -> 
TypeClassification {
         if elem.typeID == 9 { // UInt8
             return .init(typeID: 41, isPrimitive: false, isBuiltIn: true, 
isCollection: true, isMap: false, isCompressedNumeric: false, primitiveSize: 0)
         }
-        if elem.typeID == 1 { return .init(typeID: 43, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 2 { return .init(typeID: 44, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 3 { return .init(typeID: 45, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 5 { return .init(typeID: 46, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 7 { return .init(typeID: 47, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 10 { return .init(typeID: 49, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 12 { return .init(typeID: 50, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 14 { return .init(typeID: 51, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 19 { return .init(typeID: 55, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
-        if elem.typeID == 20 { return .init(typeID: 56, isPrimitive: false, 
isBuiltIn: true, isCollection: true, isMap: false, isCompressedNumeric: false, 
primitiveSize: 0) }
+        if elem.typeID == 1 {
+            return .init(
+                typeID: 43, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 2 {
+            return .init(
+                typeID: 44, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 3 {
+            return .init(
+                typeID: 45, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 5 {
+            return .init(
+                typeID: 46, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 7 {
+            return .init(
+                typeID: 47, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 10 {
+            return .init(
+                typeID: 49, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 12 {
+            return .init(
+                typeID: 50, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 14 {
+            return .init(
+                typeID: 51, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 19 {
+            return .init(
+                typeID: 55, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
+        if elem.typeID == 20 {
+            return .init(
+                typeID: 56, isPrimitive: false, isBuiltIn: true, isCollection: 
true, isMap: false,
+                isCompressedNumeric: false, primitiveSize: 0
+            )
+        }
         return .init(typeID: 22, isPrimitive: false, isBuiltIn: true, 
isCollection: true, isMap: false, isCompressedNumeric: false, primitiveSize: 0)
     }
 
diff --git a/swift/Tests/ForyTests/AnyTests.swift 
b/swift/Tests/ForyTests/AnyTests.swift
index a90b9f6bc..ca30be8e5 100644
--- a/swift/Tests/ForyTests/AnyTests.swift
+++ b/swift/Tests/ForyTests/AnyTests.swift
@@ -44,7 +44,7 @@ private final class AnyObjectDynamicNode {
 @ForyObject
 private struct AnyHashableMapHolder {
     var map: [AnyHashable: Any] = [:]
-    var optionalMap: [AnyHashable: Any]? = nil
+    var optionalMap: [AnyHashable: Any]?
 }
 
 @ForyObject
@@ -60,7 +60,7 @@ private struct AnyCoreFieldHolder {
 @ForyObject
 private struct AnyHashableSetHolder {
     var set: Set<AnyHashable> = []
-    var optionalSet: Set<AnyHashable>? = nil
+    var optionalSet: Set<AnyHashable>?
 }
 
 @ForyObject
@@ -68,6 +68,17 @@ private struct AnyHashableValueHolder {
     var value: AnyHashable = AnyHashable(Int32(0))
 }
 
+private func nestedDynamicAnyList(depth: Int) -> Any {
+    var value: Any = Int32(1)
+    if depth <= 0 {
+        return value
+    }
+    for _ in 0..<depth {
+        value = [value] as [Any]
+    }
+    return value
+}
+
 @Test
 func topLevelAnyHashableRoundTrip() throws {
     let fory = Fory()
@@ -93,7 +104,7 @@ func topLevelAnyHashableAnyMapRoundTrip() throws {
         AnyHashable("name"): "fory",
         AnyHashable(Int32(7)): Int64(9001),
         AnyHashable(true): NSNull(),
-        AnyHashable(AnyHashableDynamicKey(id: 3)): 
AnyHashableDynamicValue(label: "swift", score: 99),
+        AnyHashable(AnyHashableDynamicKey(id: 3)): 
AnyHashableDynamicValue(label: "swift", score: 99)
     ]
 
     let data = try fory.serialize(value)
@@ -124,7 +135,7 @@ func topLevelAnyHashableSetRoundTrip() throws {
         AnyHashable("name"),
         AnyHashable(Int32(7)),
         AnyHashable(true),
-        AnyHashable(AnyHashableDynamicKey(id: 11)),
+        AnyHashable(AnyHashableDynamicKey(id: 11))
     ]
 
     let data = try fory.serialize(value)
@@ -137,6 +148,26 @@ func topLevelAnyHashableSetRoundTrip() throws {
     #expect(decoded.contains(AnyHashable(AnyHashableDynamicKey(id: 11))))
 }
 
+@Test
+func topLevelDynamicAnySetRoundTrip() throws {
+    let fory = Fory()
+    fory.register(AnyHashableDynamicKey.self, id: 413)
+
+    let value: Any = Set<AnyHashable>([
+        AnyHashable("name"),
+        AnyHashable(Int32(9)),
+        AnyHashable(AnyHashableDynamicKey(id: 12))
+    ])
+
+    let data = try fory.serialize(value)
+    let decoded: Any = try fory.deserialize(data)
+    let set = decoded as? Set<AnyHashable>
+    #expect(set != nil)
+    #expect(set?.contains(AnyHashable("name")) == true)
+    #expect(set?.contains(AnyHashable(Int32(9))) == true)
+    #expect(set?.contains(AnyHashable(AnyHashableDynamicKey(id: 12))) == true)
+}
+
 @Test
 func macroAnyHashableAnyMapFieldsRoundTrip() throws {
     let fory = Fory()
@@ -148,10 +179,10 @@ func macroAnyHashableAnyMapFieldsRoundTrip() throws {
         map: [
             AnyHashable("id"): Int32(1),
             AnyHashable(Int32(2)): "value2",
-            AnyHashable(AnyHashableDynamicKey(id: 5)): 
AnyHashableDynamicValue(label: "nested", score: 8),
+            AnyHashable(AnyHashableDynamicKey(id: 5)): 
AnyHashableDynamicValue(label: "nested", score: 8)
         ],
         optionalMap: [
-            AnyHashable(false): NSNull(),
+            AnyHashable(false): NSNull()
         ]
     )
 
@@ -177,10 +208,10 @@ func macroAnyHashableSetFieldsRoundTrip() throws {
         set: [
             AnyHashable("a"),
             AnyHashable(Int32(3)),
-            AnyHashable(AnyHashableDynamicKey(id: 9)),
+            AnyHashable(AnyHashableDynamicKey(id: 9))
         ],
         optionalSet: [
-            AnyHashable(false),
+            AnyHashable(false)
         ]
     )
 
@@ -208,11 +239,11 @@ func macroCoreAnyFieldsRoundTrip() throws {
         anyList: [Int32(44), "core-list", AnyHashableDynamicValue(label: 
"core-list-obj", score: 45)],
         stringAnyMap: [
             "k1": Int32(46),
-            "k2": AnyHashableDynamicValue(label: "core-map-a", score: 47),
+            "k2": AnyHashableDynamicValue(label: "core-map-a", score: 47)
         ],
         int32AnyMap: [
             48: "core-map-b",
-            49: AnyHashableDynamicValue(label: "core-map-c", score: 50),
+            49: AnyHashableDynamicValue(label: "core-map-c", score: 50)
         ]
     )
 
@@ -254,7 +285,7 @@ func dynamicAnyMapNormalizationForAnyHashableKeys() throws {
 
     let heterogeneous: Any = [
         AnyHashable("k"): Int32(1),
-        AnyHashable(Int32(2)): "v2",
+        AnyHashable(Int32(2)): "v2"
     ] as [AnyHashable: Any]
     let heteroData = try fory.serialize(heterogeneous)
     let heteroDecoded: Any = try fory.deserialize(heteroData)
@@ -265,7 +296,7 @@ func dynamicAnyMapNormalizationForAnyHashableKeys() throws {
 
     let homogeneous: Any = [
         AnyHashable("a"): Int32(10),
-        AnyHashable("b"): Int32(20),
+        AnyHashable("b"): Int32(20)
     ] as [AnyHashable: Any]
     let homogeneousData = try fory.serialize(homogeneous)
     let homogeneousDecoded: Any = try fory.deserialize(homogeneousData)
@@ -305,7 +336,7 @@ func topLevelAllSupportedAnyTypesRoundTrip() throws {
     let anyListValue: [Any] = [
         Int32(4),
         "list",
-        AnyHashableDynamicValue(label: "list-obj", score: 5),
+        AnyHashableDynamicValue(label: "list-obj", score: 5)
     ]
     let anyListData = try fory.serialize(anyListValue)
     let anyListDecoded: [Any] = try fory.deserialize(anyListData)
@@ -316,7 +347,7 @@ func topLevelAllSupportedAnyTypesRoundTrip() throws {
 
     let stringAnyMapValue: [String: Any] = [
         "a": Int32(6),
-        "b": AnyHashableDynamicValue(label: "map-a", score: 7),
+        "b": AnyHashableDynamicValue(label: "map-a", score: 7)
     ]
     let stringAnyMapData = try fory.serialize(stringAnyMapValue)
     let stringAnyMapDecoded: [String: Any] = try 
fory.deserialize(stringAnyMapData)
@@ -325,7 +356,7 @@ func topLevelAllSupportedAnyTypesRoundTrip() throws {
 
     let int32AnyMapValue: [Int32: Any] = [
         8: "v8",
-        9: AnyHashableDynamicValue(label: "map-b", score: 9),
+        9: AnyHashableDynamicValue(label: "map-b", score: 9)
     ]
     let int32AnyMapData = try fory.serialize(int32AnyMapValue)
     let int32AnyMapDecoded: [Int32: Any] = try 
fory.deserialize(int32AnyMapData)
@@ -334,7 +365,7 @@ func topLevelAllSupportedAnyTypesRoundTrip() throws {
 
     let anyHashableAnyMapValue: [AnyHashable: Any] = [
         AnyHashable("x"): Int32(10),
-        AnyHashable(Int32(11)): AnyHashableDynamicValue(label: "map-c", score: 
11),
+        AnyHashable(Int32(11)): AnyHashableDynamicValue(label: "map-c", score: 
11)
     ]
     let anyHashableAnyMapData = try fory.serialize(anyHashableAnyMapValue)
     let anyHashableAnyMapDecoded: [AnyHashable: Any] = try 
fory.deserialize(anyHashableAnyMapData)
@@ -347,7 +378,7 @@ func topLevelAllSupportedAnyTypesRoundTrip() throws {
     let anyHashableSetValue: Set<AnyHashable> = [
         AnyHashable("set"),
         AnyHashable(Int32(12)),
-        AnyHashable(AnyHashableDynamicKey(id: 13)),
+        AnyHashable(AnyHashableDynamicKey(id: 13))
     ]
     let anyHashableSetData = try fory.serialize(anyHashableSetValue)
     let anyHashableSetDecoded: Set<AnyHashable> = try 
fory.deserialize(anyHashableSetData)
@@ -356,3 +387,36 @@ func topLevelAllSupportedAnyTypesRoundTrip() throws {
     #expect(anyHashableSetDecoded.contains(AnyHashable(Int32(12))))
     
#expect(anyHashableSetDecoded.contains(AnyHashable(AnyHashableDynamicKey(id: 
13))))
 }
+
+@Test
+func dynamicAnyMaxDepthRejectsDeepNesting() throws {
+    let value = nestedDynamicAnyList(depth: 3)
+    let writer = Fory(config: .init(maxDepth: 8))
+    let payload = try writer.serialize(value)
+
+    let limited = Fory(config: .init(maxDepth: 3))
+    do {
+        let _: Any = try limited.deserialize(payload)
+        #expect(Bool(false))
+    } catch {
+        #expect(String(describing: error).contains("maxDepth"))
+    }
+}
+
+@Test
+func dynamicAnyMaxDepthAllowsBoundaryDepth() throws {
+    let value = nestedDynamicAnyList(depth: 3)
+    let fory = Fory(config: .init(maxDepth: 4))
+
+    let payload = try fory.serialize(value)
+    let decoded: Any = try fory.deserialize(payload)
+
+    let level1 = decoded as? [Any]
+    let level2 = level1?.first as? [Any]
+    let level3 = level2?.first as? [Any]
+
+    #expect(level1 != nil)
+    #expect(level2 != nil)
+    #expect(level3 != nil)
+    #expect(level3?.first as? Int32 == 1)
+}
diff --git a/swift/Tests/ForyTests/DateTimeTests.swift 
b/swift/Tests/ForyTests/DateTimeTests.swift
index 399b20479..599897a34 100644
--- a/swift/Tests/ForyTests/DateTimeTests.swift
+++ b/swift/Tests/ForyTests/DateTimeTests.swift
@@ -30,6 +30,7 @@ private struct DateMacroHolder {
 func dateAndTimestampTypeIds() {
     #expect(ForyDate.staticTypeId == .date)
     #expect(ForyTimestamp.staticTypeId == .timestamp)
+    #expect(Duration.staticTypeId == .duration)
     #expect(Date.staticTypeId == .timestamp)
 }
 
@@ -47,6 +48,11 @@ func dateAndTimestampRoundTrip() throws {
     let tsDecoded: ForyTimestamp = try fory.deserialize(tsData)
     #expect(tsDecoded == ts)
 
+    let duration = Duration.seconds(-7) + Duration.nanoseconds(12_000_000)
+    let durationData = try fory.serialize(duration)
+    let durationDecoded: Duration = try fory.deserialize(durationData)
+    #expect(durationDecoded == duration)
+
     let instant = Date(timeIntervalSince1970: 1_731_234_567.123_456_7)
     let instantData = try fory.serialize(instant)
     let instantDecoded: Date = try fory.deserialize(instantData)
diff --git a/swift/Tests/ForyTests/EnumTests.swift 
b/swift/Tests/ForyTests/EnumTests.swift
index 4053066ee..f16c2c6be 100644
--- a/swift/Tests/ForyTests/EnumTests.swift
+++ b/swift/Tests/ForyTests/EnumTests.swift
@@ -100,7 +100,7 @@ func mixedEnumShapesRoundTrip() throws {
     let nestedMap: [String: Token] = [
         "one": .number(1),
         "plus": .plus,
-        "nested": .child(.ident("deep")),
+        "nested": .child(.ident("deep"))
     ]
 
     let tokens: [Token] = [
@@ -111,7 +111,7 @@ func mixedEnumShapesRoundTrip() throws {
         .other(42),
         .other(nil),
         .child(.child(.other(nil))),
-        .map(nestedMap),
+        .map(nestedMap)
     ]
 
     let data = try fory.serialize(tokens)
diff --git a/swift/Tests/ForyTests/ForySwiftTests.swift 
b/swift/Tests/ForyTests/ForySwiftTests.swift
index 9e5fd6541..96fb536fe 100644
--- a/swift/Tests/ForyTests/ForySwiftTests.swift
+++ b/swift/Tests/ForyTests/ForySwiftTests.swift
@@ -38,10 +38,10 @@ struct Person: Equatable {
 
 @ForyObject
 struct FieldOrder: Equatable {
-    var z: String
-    var a: Int64
-    var b: Int16
-    var c: Int32
+    var textTail: String
+    var longValue: Int64
+    var shortValue: Int16
+    var intValue: Int32
 }
 
 @ForyObject
@@ -144,22 +144,96 @@ func primitiveRoundTrip() throws {
     #expect(binaryValue == binary)
 }
 
+@Test
+func extendedWireTypesRoundTrip() throws {
+    let fory = Fory()
+
+    let float16Value = Float16(3.5)
+    let float16Data = try fory.serialize(float16Value)
+    let float16Decoded: Float16 = try fory.deserialize(float16Data)
+    #expect(float16Decoded.bitPattern == float16Value.bitPattern)
+
+    let bfloatValue = BFloat16(rawValue: 0x3F80)
+    let bfloatData = try fory.serialize(bfloatValue)
+    let bfloatDecoded: BFloat16 = try fory.deserialize(bfloatData)
+    #expect(bfloatDecoded == bfloatValue)
+
+    let durationValue = Duration.seconds(-2) + 
Duration.nanoseconds(123_456_789)
+    let durationData = try fory.serialize(durationValue)
+    let durationDecoded: Duration = try fory.deserialize(durationData)
+    #expect(durationDecoded == durationValue)
+
+    let float16Array: [Float16] = [Float16(1), Float16(-2), Float16(4.5)]
+    let float16ArrayData = try fory.serialize(float16Array)
+    let float16ArrayDecoded: [Float16] = try fory.deserialize(float16ArrayData)
+    #expect(float16ArrayDecoded.map(\.bitPattern) == 
float16Array.map(\.bitPattern))
+}
+
 @Test
 func namedInitializerBuildsConfig() {
     let defaultConfig = Fory()
     #expect(defaultConfig.config.xlang == true)
     #expect(defaultConfig.config.trackRef == false)
     #expect(defaultConfig.config.compatible == false)
+    #expect(defaultConfig.config.maxDepth == 5)
 
-    let explicitConfig = Fory(xlang: false, trackRef: true, compatible: true)
+    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.maxDepth == 7)
 
-    let configInit = Fory(config: .init(xlang: false, trackRef: false, 
compatible: true))
+    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.maxDepth == 9)
+}
+
+@Test
+func decodeLimitsRejectOversizedPayloads() throws {
+    let writer = Fory()
+
+    let oversizedCollection = try writer.serialize(["a", "b", "c"])
+    let collectionLimited = Fory(config: .init(maxCollectionLength: 2))
+    do {
+        let _: [String] = try 
collectionLimited.deserialize(oversizedCollection)
+        #expect(Bool(false))
+    } catch {}
+
+    let oversizedMap = try writer.serialize([Int32(1): Int32(1), 2: 2, 3: 3])
+    do {
+        let _: [Int32: Int32] = try collectionLimited.deserialize(oversizedMap)
+        #expect(Bool(false))
+    } catch {}
+
+    let oversizedBinary = try writer.serialize(Data([0x01, 0x02, 0x03, 0x04]))
+    let binaryLimited = Fory(config: .init(maxBinaryLength: 3))
+    do {
+        let _: Data = try binaryLimited.deserialize(oversizedBinary)
+        #expect(Bool(false))
+    } catch {}
+
+    let oversizedArrayPayload = try writer.serialize([UInt16(1), 2])
+    let payloadLimited = Fory(config: .init(maxCollectionLength: 1))
+    do {
+        let _: [UInt16] = try payloadLimited.deserialize(oversizedArrayPayload)
+        #expect(Bool(false))
+    } catch {}
+}
+
+@Test
+func deserializeRejectsTrailingBytes() throws {
+    let fory = Fory()
+    let payload = try fory.serialize(Int32(7))
+    var bytes = [UInt8](payload)
+    bytes.append(0xFF)
+    let withTrailing = Data(bytes)
+
+    do {
+        let _: Int32 = try fory.deserialize(withTrailing)
+        #expect(Bool(false))
+    } catch {}
 }
 
 @Test
@@ -299,6 +373,29 @@ func topLevelAnyRoundTrip() throws {
     #expect(nullDecoded is ForyAnyNullValue)
 }
 
+@Test
+func mixedDynamicRegistrationModesCanDecodeByID() throws {
+    let fory = Fory()
+    fory.register(Address.self, id: 600)
+    try fory.register(Person.self, name: "demo.person")
+
+    let value: Any = Address(street: "mixed", zip: 7788)
+    let data = try fory.serialize(value)
+    let decoded: Any = try fory.deserialize(data)
+    #expect(decoded as? Address == Address(street: "mixed", zip: 7788))
+}
+
+@Test
+func duplicateNameRegistrationIsRejected() throws {
+    let resolver = TypeResolver()
+    try resolver.register(Address.self, namespace: "demo", typeName: "entity")
+
+    do {
+        try resolver.register(Person.self, namespace: "demo", typeName: 
"entity")
+        #expect(Bool(false))
+    } catch {}
+}
+
 @Test
 func topLevelAnyObjectRoundTrip() throws {
     let fory = Fory(config: .init(xlang: true, trackRef: true))
@@ -363,7 +460,7 @@ func macroDynamicAnyObjectAndAnySerializerFieldsRoundTrip() 
throws {
         items: [Int32(11), Address(street: "Nested", zip: 10002)],
         map: [
             "age": Int64(19),
-            "address": Address(street: "Mapped", zip: 10003),
+            "address": Address(street: "Mapped", zip: 10003)
         ]
     )
     let serializerData = try fory.serialize(serializerHolder)
@@ -391,13 +488,13 @@ func macroAnyFieldsRoundTrip() throws {
             "count": Int64(3),
             "name": "map",
             "address": Address(street: "AnyMap", zip: 11003),
-            "empty": NSNull(),
+            "empty": NSNull()
         ],
         int32Map: [
             1: Int32(-9),
             2: "v2",
             3: Address(street: "AnyIntMap", zip: 11004),
-            4: NSNull(),
+            4: NSNull()
         ]
     )
     let data = try fory.serialize(value)
@@ -464,7 +561,7 @@ func macroFieldOrderFollowsForyRules() throws {
     let fory = Fory()
     fory.register(FieldOrder.self, id: 300)
 
-    let value = FieldOrder(z: "tail", a: 123456789, b: 17, c: 99)
+    let value = FieldOrder(textTail: "tail", longValue: 123456789, shortValue: 
17, intValue: 99)
     let data = try fory.serialize(value)
 
     let buffer = ByteBuffer(data: data)
@@ -481,10 +578,10 @@ func macroFieldOrderFollowsForyRules() throws {
     let tailContext = ReadContext(buffer: buffer, typeResolver: 
fory.typeResolver, trackRef: false)
     let fourth = try String.foryReadData(tailContext)
 
-    #expect(first == value.b)
-    #expect(second == value.a)
-    #expect(third == value.c)
-    #expect(fourth == value.z)
+    #expect(first == value.shortValue)
+    #expect(second == value.longValue)
+    #expect(third == value.intValue)
+    #expect(fourth == value.textTail)
 }
 
 @Test
@@ -543,7 +640,7 @@ func pvlVarInt64AndVarUInt64Extremes() throws {
         72_057_594_037_927_935,
         72_057_594_037_927_936,
         UInt64(Int64.max),
-        UInt64.max,
+        UInt64.max
     ]
     let intValues: [Int64] = [
         Int64.min,
@@ -560,7 +657,7 @@ func pvlVarInt64AndVarUInt64Extremes() throws {
         1_000_000,
         1_000_000_000_000,
         Int64.max - 1,
-        Int64.max,
+        Int64.max
     ]
 
     let writeBuffer = ByteBuffer()
@@ -641,7 +738,7 @@ func typeMetaRoundTripByName() throws {
                 nullable: true,
                 generics: [
                     .init(typeID: TypeId.string.rawValue, nullable: false),
-                    .init(typeID: TypeId.varint32.rawValue, nullable: true),
+                    .init(typeID: TypeId.varint32.rawValue, nullable: true)
                 ]
             )
         ),
@@ -649,7 +746,7 @@ func typeMetaRoundTripByName() throws {
             fieldID: 7,
             fieldName: "ignored_for_tag_mode",
             fieldType: .init(typeID: TypeId.varint32.rawValue, nullable: false)
-        ),
+        )
     ]
 
     let meta = try TypeMeta(
diff --git a/swift/Tests/ForyXlangTests/main.swift 
b/swift/Tests/ForyXlangTests/main.swift
index d9a3d2791..707c0c261 100644
--- a/swift/Tests/ForyXlangTests/main.swift
+++ b/swift/Tests/ForyXlangTests/main.swift
@@ -76,7 +76,7 @@ private struct StructWithMap {
 @ForyObject
 private struct VersionCheckStruct {
     var f1: Int32 = 0
-    var f2: String? = nil
+    var f2: String?
     var f3: Double = 0
 }
 
@@ -85,7 +85,7 @@ private struct EmptyStructEvolution {}
 
 @ForyObject
 private struct OneStringFieldStruct {
-    var f1: String? = nil
+    var f1: String?
 }
 
 @ForyObject
@@ -120,16 +120,16 @@ private struct NullableComprehensiveSchemaConsistent {
     var setField: Set<String> = []
     var mapField: [String: String] = [:]
 
-    var nullableInt: Int32? = nil
-    var nullableLong: Int64? = nil
-    var nullableFloat: Float? = nil
+    var nullableInt: Int32?
+    var nullableLong: Int64?
+    var nullableFloat: Float?
 
-    var nullableDouble: Double? = nil
-    var nullableBool: Bool? = nil
-    var nullableString: String? = nil
-    var nullableList: [String]? = nil
-    var nullableSet: Set<String>? = nil
-    var nullableMap: [String: String]? = nil
+    var nullableDouble: Double?
+    var nullableBool: Bool?
+    var nullableString: String?
+    var nullableList: [String]?
+    var nullableSet: Set<String>?
+    var nullableMap: [String: String]?
 }
 
 @ForyObject
@@ -175,8 +175,8 @@ private final class RefInnerSchemaConsistent {
 
 @ForyObject
 private final class RefOuterSchemaConsistent {
-    var inner1: RefInnerSchemaConsistent? = nil
-    var inner2: RefInnerSchemaConsistent? = nil
+    var inner1: RefInnerSchemaConsistent?
+    var inner2: RefInnerSchemaConsistent?
 
     required init() {}
 }
@@ -191,8 +191,8 @@ private final class RefInnerCompatible {
 
 @ForyObject
 private final class RefOuterCompatible {
-    var inner1: RefInnerCompatible? = nil
-    var inner2: RefInnerCompatible? = nil
+    var inner1: RefInnerCompatible?
+    var inner2: RefInnerCompatible?
 
     required init() {}
 }
@@ -216,7 +216,7 @@ private final class RefOverrideContainer {
 @ForyObject
 private final class CircularRefStruct {
     var name: String = ""
-    weak var selfRef: CircularRefStruct? = nil
+    weak var selfRef: CircularRefStruct?
 
     required init() {}
 }
@@ -260,7 +260,7 @@ private struct EmptyWrapper {}
 @ForyObject
 private struct Dog {
     var age: Int32 = 0
-    var name: String? = nil
+    var name: String?
 }
 
 @ForyObject
@@ -295,7 +295,7 @@ private struct UnsignedSchemaConsistentSimple {
     @ForyField(encoding: .tagged)
     var u64Tagged: UInt64 = 0
     @ForyField(encoding: .tagged)
-    var u64TaggedNullable: UInt64? = nil
+    var u64TaggedNullable: UInt64?
 }
 
 @ForyObject
@@ -311,30 +311,30 @@ private struct UnsignedSchemaConsistent {
     @ForyField(encoding: .tagged)
     var u64TaggedField: UInt64 = 0
 
-    var u8NullableField: UInt8? = nil
-    var u16NullableField: UInt16? = nil
-    var u32VarNullableField: UInt32? = nil
+    var u8NullableField: UInt8?
+    var u16NullableField: UInt16?
+    var u32VarNullableField: UInt32?
     @ForyField(encoding: .fixed)
-    var u32FixedNullableField: UInt32? = nil
-    var u64VarNullableField: UInt64? = nil
+    var u32FixedNullableField: UInt32?
+    var u64VarNullableField: UInt64?
     @ForyField(encoding: .fixed)
-    var u64FixedNullableField: UInt64? = nil
+    var u64FixedNullableField: UInt64?
     @ForyField(encoding: .tagged)
-    var u64TaggedNullableField: UInt64? = nil
+    var u64TaggedNullableField: UInt64?
 }
 
 @ForyObject
 private struct UnsignedSchemaCompatible {
-    var u8Field1: UInt8? = nil
-    var u16Field1: UInt16? = nil
-    var u32VarField1: UInt32? = nil
+    var u8Field1: UInt8?
+    var u16Field1: UInt16?
+    var u32VarField1: UInt32?
     @ForyField(encoding: .fixed)
-    var u32FixedField1: UInt32? = nil
-    var u64VarField1: UInt64? = nil
+    var u32FixedField1: UInt32?
+    var u64VarField1: UInt64?
     @ForyField(encoding: .fixed)
-    var u64FixedField1: UInt64? = nil
+    var u64FixedField1: UInt64?
     @ForyField(encoding: .tagged)
-    var u64TaggedField1: UInt64? = nil
+    var u64TaggedField1: UInt64?
 
     var u8Field2: UInt8 = 0
     var u16Field2: UInt16 = 0


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to