You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fory.apache.org by ch...@apache.org on 2026/03/10 08:07:27 UTC

(fory) branch main updated: perf(swift): optimize swift performance (#3457)

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 24aaacba3 perf(swift): optimize swift performance (#3457)
24aaacba3 is described below

commit 24aaacba3a7aa3a24777b6394a13a53d819f9c4d
Author: Shawn Yang <sh...@gmail.com>
AuthorDate: Tue Mar 10 16:07:24 2026 +0800

    perf(swift): optimize swift performance (#3457)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    ## Related issues
    
    #3355
    
    
    ## 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
    
    | Datatype | Operation | Fory TPS | Protobuf TPS | Msgpack TPS | Fastest
    |
    | --- | --- | ---: | ---: | ---: | --- |
    | Struct | Serialize | 9,727,950 | 6,572,406 | 141,248 | fory (1.48x) |
    | Struct | Deserialize | 11,889,570 | 8,584,510 | 99,792 | fory (1.39x)
    |
    | Sample | Serialize | 3,496,305 | 1,281,983 | 17,188 | fory (2.73x) |
    | Sample | Deserialize | 1,045,018 | 765,706 | 12,767 | fory (1.36x) |
    | MediaContent | Serialize | 1,425,354 | 678,542 | 29,048 | fory (2.10x)
    |
    | MediaContent | Deserialize | 614,447 | 478,298 | 12,711 | fory (1.28x)
    |
    | StructList | Serialize | 3,307,962 | 1,028,210 | 24,781 | fory (3.22x)
    |
    | StructList | Deserialize | 2,788,200 | 708,596 | 8,160 | fory (3.93x)
    |
    | SampleList | Serialize | 715,734 | 205,380 | 3,361 | fory (3.48x) |
    | SampleList | Deserialize | 199,317 | 133,425 | 1,498 | fory (1.49x) |
    | MediaContentList | Serialize | 364,097 | 103,721 | 5,538 | fory
    (3.51x) |
    | MediaContentList | Deserialize | 103,421 | 86,331 | 1,529 | fory
    (1.20x) |
---
 .gitignore                                         |    3 +-
 AGENTS.md                                          |    1 +
 README.md                                          |    8 +
 .../Sources/SwiftBenchmark/BenchmarkModels.swift   |   52 +
 .../Sources/SwiftBenchmark/BenchmarkRunner.swift   |   10 +-
 benchmarks/swift/benchmark_report.py               |    2 +-
 docs/benchmarks/swift/README.md                    |   46 +
 docs/benchmarks/swift/throughput.png               |  Bin 0 -> 84759 bytes
 docs/guide/swift/configuration.md                  |    5 +
 swift/README.md                                    |    4 +
 swift/Sources/Fory/AnySerializer.swift             |   95 +-
 swift/Sources/Fory/ByteBuffer.swift                |  452 ++++---
 swift/Sources/Fory/CollectionSerializers.swift     |  273 ++--
 swift/Sources/Fory/CollectionUtil.swift            |   78 ++
 swift/Sources/Fory/Context.swift                   |  830 ------------
 swift/Sources/Fory/DateTimeSerializers.swift       |   32 +
 swift/Sources/Fory/FieldSkipper.swift              |  271 ++--
 swift/Sources/Fory/FlatMap.swift                   |  273 ++++
 swift/Sources/Fory/Fory.swift                      |  387 ++----
 swift/Sources/Fory/MacroDeclarations.swift         |   13 +-
 swift/Sources/Fory/MetaString.swift                |  138 +-
 swift/Sources/Fory/OptionalSerializer.swift        |   29 +-
 swift/Sources/Fory/PrimitiveSerializers.swift      |  194 ++-
 swift/Sources/Fory/ReadContext.swift               |  633 +++++++++
 swift/Sources/Fory/RefResolver.swift               |    8 +-
 swift/Sources/Fory/Serializer.swift                |  564 ++------
 swift/Sources/Fory/TypeMeta.swift                  |  512 +++++---
 swift/Sources/Fory/TypeResolver.swift              |  821 +++++++-----
 swift/Sources/Fory/UnsafeUtil.swift                | 1383 ++++++++++++++++++++
 swift/Sources/Fory/WriteContext.swift              |  288 ++++
 swift/Sources/ForyMacro/ForyObjectMacro.swift      |  625 +++------
 .../ForyObjectMacroPrimitiveFastPath.swift         |  371 ++++++
 .../ForyMacro/ForyObjectMacroReadGeneration.swift  |  500 +++++++
 swift/Tests/ForyTests/ForySwiftTests.swift         |  109 +-
 swift/Tests/ForyTests/ObjectIdMapTests.swift       |   84 ++
 swift/Tests/ForyXlangTests/main.swift              |   13 +-
 36 files changed, 5981 insertions(+), 3126 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4c4b03068..fbc9ee0e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,10 +103,11 @@ examples/cpp/cmake_example/build
 **/benchmark_*.png
 **/results/
 benchmarks/**/report/
-ignored/**
+**/ignored/**
 ci-logs/**
 **/*.log
 swift/.build
+.build-*
 integration_tests/idl_tests/swift/.build
 integration_tests/idl_tests/swift/idl_package/.build
 
diff --git a/AGENTS.md b/AGENTS.md
index f2d997653..f205ad2d4 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -623,6 +623,7 @@ Fory rust provides macro-based serialization and deserialization. Fory rust cons
 
 - **Performance First**: Never introduce code that reduces performance without explicit justification
 - **Benchmark Required After Perf Optimizations**: For every code change expected to improve performance, run the relevant benchmark immediately after applying the change and report the measured results (command + before/after numbers) in your response/PR.
+- **Performance Trace Log**: For every performance-optimization round, append the hypothesis, code change, benchmark command, before/after numbers, and keep/revert decision to `tasks/perf_optimization_rounds.md` before moving to the next round.
 - **Zero-Copy**: Leverage zero-copy techniques when possible
 - **JIT Compilation**: Consider JIT compilation opportunities
 - **Memory Layout**: Optimize for cache-friendly memory access patterns
diff --git a/README.md b/README.md
index 4e1379b07..79bcab751 100644
--- a/README.md
+++ b/README.md
@@ -129,6 +129,14 @@ Fory C# demonstrates excellent performance compared to protobuf-net and MessageP
 
 For more detailed benchmarks and methodology, see [C# Benchmarks](docs/benchmarks/csharp).
 
+### Swift Serialization Performance
+
+<p align="center">
+<img src="docs/benchmarks/swift/throughput.png" width="95%">
+</p>
+
+For more detailed benchmarks and methodology, see [SwiftBenchmarks](docs/benchmarks/swift).
+
 ## Installation
 
 **Java**:
diff --git a/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkModels.swift b/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkModels.swift
index f2bbd74ee..17fc06411 100644
--- a/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkModels.swift
+++ b/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkModels.swift
@@ -65,39 +65,69 @@ enum OperationKind: String, CaseIterable {
 
 @ForyObject
 struct NumericStruct: Codable, Equatable {
+    @ForyField(id: 1)
     var f1: Int32 = 0
+    @ForyField(id: 2)
     var f2: Int32 = 0
+    @ForyField(id: 3)
     var f3: Int32 = 0
+    @ForyField(id: 4)
     var f4: Int32 = 0
+    @ForyField(id: 5)
     var f5: Int32 = 0
+    @ForyField(id: 6)
     var f6: Int32 = 0
+    @ForyField(id: 7)
     var f7: Int32 = 0
+    @ForyField(id: 8)
     var f8: Int32 = 0
 }
 
 @ForyObject
 struct Sample: Codable, Equatable {
+    @ForyField(id: 1)
     var intValue: Int32 = 0
+    @ForyField(id: 2)
     var longValue: Int64 = 0
+    @ForyField(id: 3)
     var floatValue: Float = 0
+    @ForyField(id: 4)
     var doubleValue: Double = 0
+    @ForyField(id: 5)
     var shortValue: Int32 = 0
+    @ForyField(id: 6)
     var charValue: Int32 = 0
+    @ForyField(id: 7)
     var booleanValue: Bool = false
+    @ForyField(id: 8)
     var intValueBoxed: Int32 = 0
+    @ForyField(id: 9)
     var longValueBoxed: Int64 = 0
+    @ForyField(id: 10)
     var floatValueBoxed: Float = 0
+    @ForyField(id: 11)
     var doubleValueBoxed: Double = 0
+    @ForyField(id: 12)
     var shortValueBoxed: Int32 = 0
+    @ForyField(id: 13)
     var charValueBoxed: Int32 = 0
+    @ForyField(id: 14)
     var booleanValueBoxed: Bool = false
+    @ForyField(id: 15)
     var intArray: [Int32] = []
+    @ForyField(id: 16)
     var longArray: [Int64] = []
+    @ForyField(id: 17)
     var floatArray: [Float] = []
+    @ForyField(id: 18)
     var doubleArray: [Double] = []
+    @ForyField(id: 19)
     var shortArray: [Int32] = []
+    @ForyField(id: 20)
     var charArray: [Int32] = []
+    @ForyField(id: 21)
     var booleanArray: [Bool] = []
+    @ForyField(id: 22)
     var string: String = ""
 }
 
@@ -115,47 +145,69 @@ enum Size: Int32, Codable, Equatable {
 
 @ForyObject
 struct Media: Codable, Equatable {
+    @ForyField(id: 1)
     var uri: String = ""
+    @ForyField(id: 2)
     var title: String = ""
+    @ForyField(id: 3)
     var width: Int32 = 0
+    @ForyField(id: 4)
     var height: Int32 = 0
+    @ForyField(id: 5)
     var format: String = ""
+    @ForyField(id: 6)
     var duration: Int64 = 0
+    @ForyField(id: 7)
     var size: Int64 = 0
+    @ForyField(id: 8)
     var bitrate: Int32 = 0
+    @ForyField(id: 9)
     var hasBitrate: Bool = false
+    @ForyField(id: 10)
     var persons: [String] = []
+    @ForyField(id: 11)
     var player: Player = .java
+    @ForyField(id: 12)
     var copyright: String = ""
 }
 
 @ForyObject
 struct Image: Codable, Equatable {
+    @ForyField(id: 1)
     var uri: String = ""
+    @ForyField(id: 2)
     var title: String = ""
+    @ForyField(id: 3)
     var width: Int32 = 0
+    @ForyField(id: 4)
     var height: Int32 = 0
+    @ForyField(id: 5)
     var size: Size = .small
 }
 
 @ForyObject
 struct MediaContent: Codable, Equatable {
+    @ForyField(id: 1)
     var media: Media = .init()
+    @ForyField(id: 2)
     var images: [Image] = []
 }
 
 @ForyObject
 struct StructList: Codable, Equatable {
+    @ForyField(id: 1)
     var structList: [NumericStruct] = []
 }
 
 @ForyObject
 struct SampleList: Codable, Equatable {
+    @ForyField(id: 1)
     var sampleList: [Sample] = []
 }
 
 @ForyObject
 struct MediaContentList: Codable, Equatable {
+    @ForyField(id: 1)
     var mediaContentList: [MediaContent] = []
 }
 
diff --git a/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkRunner.swift b/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkRunner.swift
index 4b7043795..5f6d09a6c 100644
--- a/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkRunner.swift
+++ b/benchmarks/swift/Sources/SwiftBenchmark/BenchmarkRunner.swift
@@ -68,7 +68,7 @@ final class BenchmarkSuite {
 
     init(config: BenchmarkConfig) {
         self.config = config
-        self.fory = Fory(xlang: false, trackRef: false, compatible: false)
+        self.fory = Fory(xlang: false, trackRef: false, compatible: true)
         registerTypes()
     }
 
@@ -129,11 +129,9 @@ final class BenchmarkSuite {
         fory.register(Media.self, id: 3)
         fory.register(Image.self, id: 4)
         fory.register(MediaContent.self, id: 5)
-        fory.register(Player.self, id: 6)
-        fory.register(Size.self, id: 7)
-        fory.register(StructList.self, id: 8)
-        fory.register(SampleList.self, id: 9)
-        fory.register(MediaContentList.self, id: 10)
+        fory.register(StructList.self, id: 6)
+        fory.register(SampleList.self, id: 7)
+        fory.register(MediaContentList.self, id: 8)
     }
 
     private func shouldRun(_ dataKind: DataKind, _ serializer: SerializerKind) -> Bool {
diff --git a/benchmarks/swift/benchmark_report.py b/benchmarks/swift/benchmark_report.py
index 517a1b5f9..a9f7d58bb 100755
--- a/benchmarks/swift/benchmark_report.py
+++ b/benchmarks/swift/benchmark_report.py
@@ -253,7 +253,7 @@ def write_report(
     else:
         image_path = plot_name
     lines.append('<p align="center">')
-    lines.append(f'<img src="{image_path}" width="95%">')
+    lines.append(f'<img src="{image_path}" width="95%" />')
     lines.append("</p>")
     lines.append("")
     lines.append(
diff --git a/docs/benchmarks/swift/README.md b/docs/benchmarks/swift/README.md
new file mode 100644
index 000000000..58b6c032a
--- /dev/null
+++ b/docs/benchmarks/swift/README.md
@@ -0,0 +1,46 @@
+# Fory Swift Benchmark
+
+This benchmark compares serialization and deserialization throughput for Apache Fory, Protocol Buffers, and MessagePack in Swift.
+
+## Hardware and Runtime Info
+
+| Key                   | Value                         |
+| --------------------- | ----------------------------- |
+| Timestamp             | 2026-03-10T06:25:16Z          |
+| OS                    | Version 15.7.2 (Build 24G325) |
+| Host                  | macbook-pro.local             |
+| CPU Cores (Logical)   | 12                            |
+| Memory (GB)           | 48.00                         |
+| Duration per case (s) | 3                             |
+
+## Throughput Results
+
+<p align="center">
+<img src="throughput.png" width="95%" />
+</p>
+
+| Datatype         | Operation   |   Fory TPS | Protobuf TPS | Msgpack TPS | Fastest      |
+| ---------------- | ----------- | ---------: | -----------: | ----------: | ------------ |
+| Struct           | Serialize   |  9,727,950 |    6,572,406 |     141,248 | fory (1.48x) |
+| Struct           | Deserialize | 11,889,570 |    8,584,510 |      99,792 | fory (1.39x) |
+| Sample           | Serialize   |  3,496,305 |    1,281,983 |      17,188 | fory (2.73x) |
+| Sample           | Deserialize |  1,045,018 |      765,706 |      12,767 | fory (1.36x) |
+| MediaContent     | Serialize   |  1,425,354 |      678,542 |      29,048 | fory (2.10x) |
+| MediaContent     | Deserialize |    614,447 |      478,298 |      12,711 | fory (1.28x) |
+| StructList       | Serialize   |  3,307,962 |    1,028,210 |      24,781 | fory (3.22x) |
+| StructList       | Deserialize |  2,788,200 |      708,596 |       8,160 | fory (3.93x) |
+| SampleList       | Serialize   |    715,734 |      205,380 |       3,361 | fory (3.48x) |
+| SampleList       | Deserialize |    199,317 |      133,425 |       1,498 | fory (1.49x) |
+| MediaContentList | Serialize   |    364,097 |      103,721 |       5,538 | fory (3.51x) |
+| MediaContentList | Deserialize |    103,421 |       86,331 |       1,529 | fory (1.20x) |
+
+## Serialized Size (bytes)
+
+| Datatype         | Fory | Protobuf | Msgpack |
+| ---------------- | ---: | -------: | ------: |
+| MediaContent     |  365 |      301 |     524 |
+| MediaContentList | 1535 |     1520 |    2639 |
+| Sample           |  446 |      375 |     737 |
+| SampleList       | 1980 |     1890 |    3698 |
+| Struct           |   58 |       61 |      65 |
+| StructList       |  184 |      315 |     338 |
diff --git a/docs/benchmarks/swift/throughput.png b/docs/benchmarks/swift/throughput.png
new file mode 100644
index 000000000..291dc8145
Binary files /dev/null and b/docs/benchmarks/swift/throughput.png differ
diff --git a/docs/guide/swift/configuration.md b/docs/guide/swift/configuration.md
index 4b90cc906..0e464807a 100644
--- a/docs/guide/swift/configuration.md
+++ b/docs/guide/swift/configuration.md
@@ -39,6 +39,11 @@ Default configuration:
 let fory = Fory() // xlang=true, trackRef=false, compatible=false
 ```
 
+## Threading
+
+`Fory` is single-threaded and optimized to reuse one read/write context pair on the calling thread.
+Reuse one instance per thread and do not use the same instance concurrently.
+
 ## Options
 
 ### `xlang`
diff --git a/swift/README.md b/swift/README.md
index c28a0b931..7f51298ee 100644
--- a/swift/README.md
+++ b/swift/README.md
@@ -76,6 +76,10 @@ let output2: User = try fory.deserialize(from: buffer)
 assert(output2 == input)
 ```
 
+### 4. Threading
+
+`Fory` is the fastest option for single-threaded reuse. Keep one instance per thread.
+
 ## 📚 Core Features
 
 ### 1. Object Graph Serialization
diff --git a/swift/Sources/Fory/AnySerializer.swift b/swift/Sources/Fory/AnySerializer.swift
index 6765ee32b..ea263e5fd 100644
--- a/swift/Sources/Fory/AnySerializer.swift
+++ b/swift/Sources/Fory/AnySerializer.swift
@@ -28,6 +28,14 @@ public struct ForyAnyNullValue: Serializer {
         .none
     }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public var foryIsNone: Bool {
         true
     }
@@ -57,17 +65,22 @@ extension AnyHashable: Serializer {
     }
 
     public static func foryReadData(_ context: ReadContext) throws -> AnyHashable {
-        guard let typeInfo = context.dynamicTypeInfo(for: Self.self) else {
-            throw ForyError.invalidData("dynamic AnyHashable key requires type info")
-        }
-        if typeInfo.wireTypeID == .none {
+        _ = context
+        throw ForyError.invalidData(
+            "dynamic AnyHashable key read requires type info; foryReadData should not be called directly"
+        )
+    }
+
+    public static func foryReadCompatibleData(_ context: ReadContext, remoteTypeInfo: TypeInfo) throws -> AnyHashable {
+        let typeInfo = remoteTypeInfo
+        if typeInfo.typeID == .none {
             throw ForyError.invalidData("dynamic AnyHashable key cannot be null")
         }
-        let decoded = try context.typeResolver.readDynamicValue(typeInfo: typeInfo, context: context)
+        let decoded = try context.readAnyValue(typeInfo: typeInfo)
         return try toAnyHashableKey(decoded)
     }
 
-    public static func foryWriteTypeInfo(_ context: WriteContext) throws {
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
         _ = context
         throw ForyError.invalidData("dynamic AnyHashable key type info is runtime-only")
     }
@@ -76,9 +89,8 @@ extension AnyHashable: Serializer {
         try writeAnyTypeInfo(base, context: context)
     }
 
-    public static func foryReadTypeInfo(_ context: ReadContext) throws {
-        let typeInfo = try context.typeResolver.readDynamicTypeInfo(context: context)
-        context.setDynamicTypeInfo(for: Self.self, typeInfo)
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try context.readTypeInfo()
     }
 
     public func foryWrite(
@@ -105,7 +117,7 @@ extension Optional: OptionalTypeMarker {
     static var noneValue: Wrapped? { nil }
 }
 
-private struct DynamicAnyValue: Serializer {
+struct DynamicAnyValue: Serializer {
     var value: Any = ForyAnyNullValue()
 
     init(_ value: Any) {
@@ -124,7 +136,7 @@ private struct DynamicAnyValue: Serializer {
         true
     }
 
-    static var isReferenceTrackableType: Bool {
+    static var isRefType: Bool {
         true
     }
 
@@ -161,16 +173,21 @@ private struct DynamicAnyValue: Serializer {
     }
 
     static func foryReadData(_ context: ReadContext) throws -> DynamicAnyValue {
-        guard let typeInfo = context.dynamicTypeInfo(for: Self.self) else {
-            throw ForyError.invalidData("dynamic Any value requires type info")
-        }
-        if typeInfo.wireTypeID == .none {
+        _ = context
+        throw ForyError.invalidData(
+            "dynamic Any read requires type info; foryReadData should not be called directly"
+        )
+    }
+
+    static func foryReadCompatibleData(_ context: ReadContext, remoteTypeInfo: TypeInfo) throws -> DynamicAnyValue {
+        let typeInfo = remoteTypeInfo
+        if typeInfo.typeID == .none {
             return .foryDefault()
         }
-        return DynamicAnyValue(try context.typeResolver.readDynamicValue(typeInfo: typeInfo, context: context))
+        return DynamicAnyValue(try context.readAnyValue(typeInfo: typeInfo))
     }
 
-    static func foryWriteTypeInfo(_ context: WriteContext) throws {
+    static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
         _ = context
         throw ForyError.invalidData("dynamic Any value type info is runtime-only")
     }
@@ -183,9 +200,8 @@ private struct DynamicAnyValue: Serializer {
         try writeAnyTypeInfo(value, context: context)
     }
 
-    static func foryReadTypeInfo(_ context: ReadContext) throws {
-        let typeInfo = try context.typeResolver.readDynamicTypeInfo(context: context)
-        context.setDynamicTypeInfo(for: Self.self, typeInfo)
+    static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try context.readTypeInfo()
     }
 
     func foryWrite(
@@ -199,8 +215,8 @@ private struct DynamicAnyValue: Serializer {
                 context.buffer.writeInt8(RefFlag.null.rawValue)
                 return
             }
-            if refMode == .tracking, anyValueIsReferenceTrackable(value), let object = value as AnyObject? {
-                if context.refWriter.tryWriteReference(buffer: context.buffer, object: object) {
+            if refMode == .tracking, anyValueIsRefType(value), let object = value as AnyObject? {
+                if context.refWriter.tryWriteRef(buffer: context.buffer, object: object) {
                     return
                 }
             } else {
@@ -219,6 +235,20 @@ private struct DynamicAnyValue: Serializer {
         refMode: RefMode,
         readTypeInfo: Bool
     ) throws -> DynamicAnyValue {
+        @inline(__always)
+        func requireDynamicTypeInfo() throws -> TypeInfo {
+            if readTypeInfo {
+                guard let remoteTypeInfo = try foryReadTypeInfo(context) else {
+                    throw ForyError.invalidData("dynamic Any value requires type info")
+                }
+                return remoteTypeInfo
+            }
+            guard let remoteTypeInfo = context.getTypeInfo(for: Self.self) else {
+                throw ForyError.invalidData("dynamic Any value requires type info")
+            }
+            return remoteTypeInfo
+        }
+
         if refMode != .none {
             let rawFlag = try context.buffer.readInt8()
             guard let flag = RefFlag(rawValue: rawFlag) else {
@@ -239,24 +269,19 @@ private struct DynamicAnyValue: Serializer {
                 }
                 return DynamicAnyValue(referenced)
             case .refValue:
-                let reservedRefID = context.refReader.reserveRefID()
-                context.pushPendingReference(reservedRefID)
-                if readTypeInfo {
-                    try foryReadTypeInfo(context)
+                let reservedRefID = context.trackRef ? context.refReader.reserveRefID() : nil
+                let remoteTypeInfo = try requireDynamicTypeInfo()
+                let value = try foryReadCompatibleData(context, remoteTypeInfo: remoteTypeInfo)
+                if let reservedRefID {
+                    context.refReader.storeRef(value, at: reservedRefID)
                 }
-                let value = try foryReadData(context)
-                context.finishPendingReferenceIfNeeded(value)
-                context.popPendingReference()
                 return value
             case .notNullValue:
                 break
             }
         }
 
-        if readTypeInfo {
-            try foryReadTypeInfo(context)
-        }
-        return try foryReadData(context)
+        return try foryReadCompatibleData(context, remoteTypeInfo: requireDynamicTypeInfo())
     }
 }
 
@@ -271,11 +296,11 @@ private func unwrapOptionalAny(_ value: Any) -> Any? {
     return child
 }
 
-private func anyValueIsReferenceTrackable(_ value: Any) -> Bool {
+private func anyValueIsRefType(_ value: Any) -> Bool {
     guard let serializer = value as? any Serializer else {
         return false
     }
-    return type(of: serializer).isReferenceTrackableType
+    return type(of: serializer).isRefType
 }
 
 private func toAnyHashableKey(_ value: Any) throws -> AnyHashable {
diff --git a/swift/Sources/Fory/ByteBuffer.swift b/swift/Sources/Fory/ByteBuffer.swift
index 214c22c5d..0ddc18028 100644
--- a/swift/Sources/Fory/ByteBuffer.swift
+++ b/swift/Sources/Fory/ByteBuffer.swift
@@ -24,6 +24,8 @@ public final class ByteBuffer {
     @usableFromInline
     internal var cursor: Int
 
+    private var dataBridge = Data()
+
     @inlinable
     public init(capacity: Int = 256) {
         storage = []
@@ -53,6 +55,49 @@ public final class ByteBuffer {
         storage.count - cursor
     }
 
+    @usableFromInline
+    @inline(__always)
+    internal var readableCount: Int {
+        storage.count
+    }
+
+    @usableFromInline
+    @inline(__always)
+    internal func byte(at index: Int) -> UInt8 {
+        return storage[index]
+    }
+
+    @usableFromInline
+    @inline(__always)
+    internal func copyBytes(start: Int, end: Int) -> [UInt8] {
+        let length = end - start
+        guard length > 0 else {
+            return []
+        }
+        return Array(storage[start..<end])
+    }
+
+    @usableFromInline
+    @inline(__always)
+    internal func matchesBytes(start: Int, bytes: [UInt8]) -> Bool {
+        var index = 0
+        while index < bytes.count {
+            if storage[start + index] != bytes[index] {
+                return false
+            }
+            index += 1
+        }
+        return true
+    }
+
+    @usableFromInline
+    @inline(__always)
+    internal func withUnsafeReadableBytes<R>(
+        _ body: (UnsafeBufferPointer<UInt8>) throws -> R
+    ) rethrows -> R {
+        return try storage.withUnsafeBufferPointer(body)
+    }
+
     @inlinable
     public func reserve(_ additional: Int) {
         storage.reserveCapacity(storage.count + additional)
@@ -90,14 +135,71 @@ public final class ByteBuffer {
 
         if dataCount > 0 {
             data.withUnsafeBytes { source in
-                storage.withUnsafeMutableBytes { destination in
-                    destination.copyBytes(from: source)
+                storage.withUnsafeMutableBufferPointer { destination in
+                    guard let sourceBase = source.baseAddress, let destinationBase = destination.baseAddress else {
+                        return
+                    }
+                    UnsafeMutableRawPointer(destinationBase).copyMemory(
+                        from: sourceBase,
+                        byteCount: dataCount
+                    )
                 }
             }
         }
         cursor = 0
     }
 
+    @usableFromInline
+    @inline(__always)
+    internal func swapState(with other: ByteBuffer) {
+        swap(&storage, &other.storage)
+        swap(&cursor, &other.cursor)
+        swap(&dataBridge, &other.dataBridge)
+    }
+
+    @usableFromInline
+    @inline(__always)
+    internal func copyToData() -> Data {
+        let byteCount = storage.count
+        if dataBridge.count != byteCount {
+            dataBridge.count = byteCount
+        }
+        if byteCount > 0 {
+            dataBridge.withUnsafeMutableBytes { destination in
+                guard let destinationBase = destination.baseAddress else {
+                    return
+                }
+                storage.withUnsafeBytes { source in
+                    guard let sourceBase = source.baseAddress else {
+                        return
+                    }
+                    destinationBase.copyMemory(from: sourceBase, byteCount: byteCount)
+                }
+            }
+        }
+        return dataBridge
+    }
+
+    @usableFromInline
+    @inline(__always)
+    internal func materializeData(
+        byteCount: Int,
+        _ body: (UnsafeMutablePointer<UInt8>) -> Void
+    ) -> Data {
+        if dataBridge.count != byteCount {
+            dataBridge.count = byteCount
+        }
+        if byteCount > 0 {
+            dataBridge.withUnsafeMutableBytes { destination in
+                guard let base = destination.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
+                    return
+                }
+                body(base)
+            }
+        }
+        return dataBridge
+    }
+
     @inlinable
     public func getCursor() -> Int {
         cursor
@@ -117,22 +219,6 @@ public final class ByteBuffer {
         }
     }
 
-    @inlinable
-    @inline(__always)
-    internal func appendUninitializedBytes(
-        count: Int,
-        _ body: (UnsafeMutablePointer<UInt8>) -> Void
-    ) {
-        guard count > 0 else {
-            return
-        }
-        let start = storage.count
-        storage.append(contentsOf: repeatElement(0, count: count))
-        storage.withUnsafeMutableBufferPointer { buffer in
-            body(buffer.baseAddress!.advanced(by: start))
-        }
-    }
-
     @inlinable
     @inline(__always)
     public func writeUInt8(_ value: UInt8) {
@@ -186,51 +272,29 @@ public final class ByteBuffer {
             return
         }
         if value < 0x4000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = UInt8(truncatingIfNeeded: value >> 7)
-            appendUninitializedBytes(count: 2) { dst in
-                dst[0] = u1
-                dst[1] = u2
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 7))
             return
         }
         if value < 0x20_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = UInt8(truncatingIfNeeded: value >> 14)
-            appendUninitializedBytes(count: 3) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 14))
             return
         }
         if value < 0x1000_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-            let u4 = UInt8(truncatingIfNeeded: value >> 21)
-            appendUninitializedBytes(count: 4) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-                dst[3] = u4
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 21))
             return
         }
 
-        let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-        let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-        let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-        let u4 = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
-        let u5 = UInt8(truncatingIfNeeded: value >> 28)
-        appendUninitializedBytes(count: 5) { dst in
-            dst[0] = u1
-            dst[1] = u2
-            dst[2] = u3
-            dst[3] = u4
-            dst[4] = u5
-        }
+        storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80)
+        storage.append(UInt8(truncatingIfNeeded: value >> 28))
     }
 
     @inlinable
@@ -241,131 +305,71 @@ public final class ByteBuffer {
             return
         }
         if value < 0x4000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = UInt8(truncatingIfNeeded: value >> 7)
-            appendUninitializedBytes(count: 2) { dst in
-                dst[0] = u1
-                dst[1] = u2
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 7))
             return
         }
         if value < 0x20_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = UInt8(truncatingIfNeeded: value >> 14)
-            appendUninitializedBytes(count: 3) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 14))
             return
         }
         if value < 0x1000_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-            let u4 = UInt8(truncatingIfNeeded: value >> 21)
-            appendUninitializedBytes(count: 4) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-                dst[3] = u4
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 21))
             return
         }
         if value < 0x8_0000_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-            let u4 = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
-            let u5 = UInt8(truncatingIfNeeded: value >> 28)
-            appendUninitializedBytes(count: 5) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-                dst[3] = u4
-                dst[4] = u5
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 28))
             return
         }
         if value < 0x400_0000_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-            let u4 = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
-            let u5 = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
-            let u6 = UInt8(truncatingIfNeeded: value >> 35)
-            appendUninitializedBytes(count: 6) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-                dst[3] = u4
-                dst[4] = u5
-                dst[5] = u6
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 35))
             return
         }
         if value < 0x2_0000_0000_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-            let u4 = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
-            let u5 = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
-            let u6 = (UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80
-            let u7 = UInt8(truncatingIfNeeded: value >> 42)
-            appendUninitializedBytes(count: 7) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-                dst[3] = u4
-                dst[4] = u5
-                dst[5] = u6
-                dst[6] = u7
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 42))
             return
         }
         if value < 0x100_0000_0000_0000 {
-            let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-            let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-            let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-            let u4 = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
-            let u5 = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
-            let u6 = (UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80
-            let u7 = (UInt8(truncatingIfNeeded: value >> 42) & 0x7F) | 0x80
-            let u8 = UInt8(truncatingIfNeeded: value >> 49)
-            appendUninitializedBytes(count: 8) { dst in
-                dst[0] = u1
-                dst[1] = u2
-                dst[2] = u3
-                dst[3] = u4
-                dst[4] = u5
-                dst[5] = u6
-                dst[6] = u7
-                dst[7] = u8
-            }
+            storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80)
+            storage.append((UInt8(truncatingIfNeeded: value >> 42) & 0x7F) | 0x80)
+            storage.append(UInt8(truncatingIfNeeded: value >> 49))
             return
         }
 
-        let u1 = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
-        let u2 = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
-        let u3 = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
-        let u4 = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
-        let u5 = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
-        let u6 = (UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80
-        let u7 = (UInt8(truncatingIfNeeded: value >> 42) & 0x7F) | 0x80
-        let u8 = (UInt8(truncatingIfNeeded: value >> 49) & 0x7F) | 0x80
-        let u9 = UInt8(truncatingIfNeeded: value >> 56)
-        appendUninitializedBytes(count: 9) { dst in
-            dst[0] = u1
-            dst[1] = u2
-            dst[2] = u3
-            dst[3] = u4
-            dst[4] = u5
-            dst[5] = u6
-            dst[6] = u7
-            dst[7] = u8
-            dst[8] = u9
-        }
+        storage.append((UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 42) & 0x7F) | 0x80)
+        storage.append((UInt8(truncatingIfNeeded: value >> 49) & 0x7F) | 0x80)
+        storage.append(UInt8(truncatingIfNeeded: value >> 56))
     }
 
     @inlinable
@@ -423,6 +427,12 @@ public final class ByteBuffer {
         storage.append(contentsOf: bytes)
     }
 
+    @inlinable
+    @inline(__always)
+    public func writeBytes(_ bytes: [UInt8]) {
+        storage.append(contentsOf: bytes)
+    }
+
     @inlinable
     public func writeBytes(_ bytes: UnsafeRawBufferPointer) {
         storage.append(contentsOf: bytes)
@@ -450,16 +460,23 @@ public final class ByteBuffer {
     @inlinable
     @inline(__always)
     public func checkBound(_ need: Int) throws {
-        if cursor + need > storage.count {
-            throw ForyError.outOfBounds(cursor: cursor, need: need, length: storage.count)
+        let length = readableCount
+        if cursor + need > length {
+            throw ForyError.outOfBounds(cursor: cursor, need: need, length: length)
         }
     }
 
     @inlinable
     public func readBytes(into destination: UnsafeMutableRawBufferPointer) throws {
         try checkBound(destination.count)
-        storage.withUnsafeBytes { rawBytes in
-            destination.copyBytes(from: UnsafeRawBufferPointer(rebasing: rawBytes[cursor..<(cursor + destination.count)]))
+        guard destination.count > 0, let destinationBase = destination.baseAddress else {
+            return
+        }
+        withUnsafeReadableBytes { rawBytes in
+            guard let sourceBase = rawBytes.baseAddress else {
+                return
+            }
+            destinationBase.copyMemory(from: sourceBase.advanced(by: cursor), byteCount: destination.count)
         }
         cursor += destination.count
     }
@@ -469,10 +486,11 @@ public final class ByteBuffer {
     public func readUInt8() throws -> UInt8 {
         try checkBound(1)
         defer { cursor += 1 }
-        return storage[cursor]
+        return byte(at: cursor)
     }
 
     @inlinable
+    @inline(__always)
     public func readInt8() throws -> Int8 {
         Int8(bitPattern: try readUInt8())
     }
@@ -481,8 +499,8 @@ public final class ByteBuffer {
     @inline(__always)
     public func readUInt16() throws -> UInt16 {
         try checkBound(2)
-        let b0 = UInt16(storage[cursor])
-        let b1 = UInt16(storage[cursor + 1]) << 8
+        let b0 = UInt16(byte(at: cursor))
+        let b1 = UInt16(byte(at: cursor + 1)) << 8
         cursor += 2
         return b0 | b1
     }
@@ -496,10 +514,10 @@ public final class ByteBuffer {
     @inline(__always)
     public func readUInt32() throws -> UInt32 {
         try checkBound(4)
-        let b0 = UInt32(storage[cursor])
-        let b1 = UInt32(storage[cursor + 1]) << 8
-        let b2 = UInt32(storage[cursor + 2]) << 16
-        let b3 = UInt32(storage[cursor + 3]) << 24
+        let b0 = UInt32(byte(at: cursor))
+        let b1 = UInt32(byte(at: cursor + 1)) << 8
+        let b2 = UInt32(byte(at: cursor + 2)) << 16
+        let b3 = UInt32(byte(at: cursor + 3)) << 24
         cursor += 4
         return b0 | b1 | b2 | b3
     }
@@ -513,14 +531,14 @@ public final class ByteBuffer {
     @inline(__always)
     public func readUInt64() throws -> UInt64 {
         try checkBound(8)
-        let b0 = UInt64(storage[cursor])
-        let b1 = UInt64(storage[cursor + 1]) << 8
-        let b2 = UInt64(storage[cursor + 2]) << 16
-        let b3 = UInt64(storage[cursor + 3]) << 24
-        let b4 = UInt64(storage[cursor + 4]) << 32
-        let b5 = UInt64(storage[cursor + 5]) << 40
-        let b6 = UInt64(storage[cursor + 6]) << 48
-        let b7 = UInt64(storage[cursor + 7]) << 56
+        let b0 = UInt64(byte(at: cursor))
+        let b1 = UInt64(byte(at: cursor + 1)) << 8
+        let b2 = UInt64(byte(at: cursor + 2)) << 16
+        let b3 = UInt64(byte(at: cursor + 3)) << 24
+        let b4 = UInt64(byte(at: cursor + 4)) << 32
+        let b5 = UInt64(byte(at: cursor + 5)) << 40
+        let b6 = UInt64(byte(at: cursor + 6)) << 48
+        let b7 = UInt64(byte(at: cursor + 7)) << 56
         cursor += 8
         return b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7
     }
@@ -533,28 +551,28 @@ public final class ByteBuffer {
     @inlinable
     @inline(__always)
     public func readVarUInt32() throws -> UInt32 {
-        let available = storage.count - cursor
+        let available = readableCount - cursor
         if available >= 5 {
             let offset = cursor
-            let b0 = storage[offset]
+            let b0 = byte(at: offset)
             if b0 < 0x80 {
                 cursor = offset + 1
                 return UInt32(b0)
             }
 
-            let b1 = storage[offset + 1]
+            let b1 = byte(at: offset + 1)
             if b1 < 0x80 {
                 cursor = offset + 2
                 return UInt32(b0 & 0x7F) | (UInt32(b1) << 7)
             }
 
-            let b2 = storage[offset + 2]
+            let b2 = byte(at: offset + 2)
             if b2 < 0x80 {
                 cursor = offset + 3
                 return UInt32(b0 & 0x7F) | (UInt32(b1 & 0x7F) << 7) | (UInt32(b2) << 14)
             }
 
-            let b3 = storage[offset + 3]
+            let b3 = byte(at: offset + 3)
             if b3 < 0x80 {
                 cursor = offset + 4
                 return UInt32(b0 & 0x7F) |
@@ -563,7 +581,7 @@ public final class ByteBuffer {
                     (UInt32(b3) << 21)
             }
 
-            let b4 = storage[offset + 4]
+            let b4 = byte(at: offset + 4)
             if b4 >= 0x80 {
                 throw ForyError.encodingError("varuint32 overflow")
             }
@@ -576,28 +594,28 @@ public final class ByteBuffer {
         }
 
         try checkBound(1)
-        let b0 = storage[cursor]
+        let b0 = byte(at: cursor)
         if b0 < 0x80 {
             cursor += 1
             return UInt32(b0)
         }
 
         try checkBound(2)
-        let b1 = storage[cursor + 1]
+        let b1 = byte(at: cursor + 1)
         if b1 < 0x80 {
             cursor += 2
             return UInt32(b0 & 0x7F) | (UInt32(b1) << 7)
         }
 
         try checkBound(3)
-        let b2 = storage[cursor + 2]
+        let b2 = byte(at: cursor + 2)
         if b2 < 0x80 {
             cursor += 3
             return UInt32(b0 & 0x7F) | (UInt32(b1 & 0x7F) << 7) | (UInt32(b2) << 14)
         }
 
         try checkBound(4)
-        let b3 = storage[cursor + 3]
+        let b3 = byte(at: cursor + 3)
         if b3 < 0x80 {
             cursor += 4
             return UInt32(b0 & 0x7F) |
@@ -607,7 +625,7 @@ public final class ByteBuffer {
         }
 
         try checkBound(5)
-        let b4 = storage[cursor + 4]
+        let b4 = byte(at: cursor + 4)
         if b4 >= 0x80 {
             throw ForyError.encodingError("varuint32 overflow")
         }
@@ -622,22 +640,22 @@ public final class ByteBuffer {
     @inlinable
     @inline(__always)
     public func readVarUInt64() throws -> UInt64 {
-        let available = storage.count - cursor
+        let available = readableCount - cursor
         if available >= 9 {
             let offset = cursor
-            let b0 = storage[offset]
+            let b0 = byte(at: offset)
             if b0 < 0x80 {
                 cursor = offset + 1
                 return UInt64(b0)
             }
 
-            let b1 = storage[offset + 1]
+            let b1 = byte(at: offset + 1)
             if b1 < 0x80 {
                 cursor = offset + 2
                 return UInt64(b0 & 0x7F) | (UInt64(b1) << 7)
             }
 
-            let b2 = storage[offset + 2]
+            let b2 = byte(at: offset + 2)
             if b2 < 0x80 {
                 cursor = offset + 3
                 return UInt64(b0 & 0x7F) |
@@ -645,7 +663,7 @@ public final class ByteBuffer {
                     (UInt64(b2) << 14)
             }
 
-            let b3 = storage[offset + 3]
+            let b3 = byte(at: offset + 3)
             if b3 < 0x80 {
                 cursor = offset + 4
                 return UInt64(b0 & 0x7F) |
@@ -654,7 +672,7 @@ public final class ByteBuffer {
                     (UInt64(b3) << 21)
             }
 
-            let b4 = storage[offset + 4]
+            let b4 = byte(at: offset + 4)
             if b4 < 0x80 {
                 cursor = offset + 5
                 return UInt64(b0 & 0x7F) |
@@ -664,7 +682,7 @@ public final class ByteBuffer {
                     (UInt64(b4) << 28)
             }
 
-            let b5 = storage[offset + 5]
+            let b5 = byte(at: offset + 5)
             if b5 < 0x80 {
                 cursor = offset + 6
                 return UInt64(b0 & 0x7F) |
@@ -675,7 +693,7 @@ public final class ByteBuffer {
                     (UInt64(b5) << 35)
             }
 
-            let b6 = storage[offset + 6]
+            let b6 = byte(at: offset + 6)
             if b6 < 0x80 {
                 cursor = offset + 7
                 return UInt64(b0 & 0x7F) |
@@ -687,7 +705,7 @@ public final class ByteBuffer {
                     (UInt64(b6) << 42)
             }
 
-            let b7 = storage[offset + 7]
+            let b7 = byte(at: offset + 7)
             if b7 < 0x80 {
                 cursor = offset + 8
                 return UInt64(b0 & 0x7F) |
@@ -700,7 +718,7 @@ public final class ByteBuffer {
                     (UInt64(b7) << 49)
             }
 
-            let b8 = storage[offset + 8]
+            let b8 = byte(at: offset + 8)
             cursor = offset + 9
             let low = UInt64(b0 & 0x7F) |
                 (UInt64(b1 & 0x7F) << 7) |
@@ -715,21 +733,21 @@ public final class ByteBuffer {
         }
 
         try checkBound(1)
-        let b0 = storage[cursor]
+        let b0 = byte(at: cursor)
         if b0 < 0x80 {
             cursor += 1
             return UInt64(b0)
         }
 
         try checkBound(2)
-        let b1 = storage[cursor + 1]
+        let b1 = byte(at: cursor + 1)
         if b1 < 0x80 {
             cursor += 2
             return UInt64(b0 & 0x7F) | (UInt64(b1) << 7)
         }
 
         try checkBound(3)
-        let b2 = storage[cursor + 2]
+        let b2 = byte(at: cursor + 2)
         if b2 < 0x80 {
             cursor += 3
             return UInt64(b0 & 0x7F) |
@@ -738,7 +756,7 @@ public final class ByteBuffer {
         }
 
         try checkBound(4)
-        let b3 = storage[cursor + 3]
+        let b3 = byte(at: cursor + 3)
         if b3 < 0x80 {
             cursor += 4
             return UInt64(b0 & 0x7F) |
@@ -748,7 +766,7 @@ public final class ByteBuffer {
         }
 
         try checkBound(5)
-        let b4 = storage[cursor + 4]
+        let b4 = byte(at: cursor + 4)
         if b4 < 0x80 {
             cursor += 5
             return UInt64(b0 & 0x7F) |
@@ -759,7 +777,7 @@ public final class ByteBuffer {
         }
 
         try checkBound(6)
-        let b5 = storage[cursor + 5]
+        let b5 = byte(at: cursor + 5)
         if b5 < 0x80 {
             cursor += 6
             return UInt64(b0 & 0x7F) |
@@ -771,7 +789,7 @@ public final class ByteBuffer {
         }
 
         try checkBound(7)
-        let b6 = storage[cursor + 6]
+        let b6 = byte(at: cursor + 6)
         if b6 < 0x80 {
             cursor += 7
             return UInt64(b0 & 0x7F) |
@@ -784,7 +802,7 @@ public final class ByteBuffer {
         }
 
         try checkBound(8)
-        let b7 = storage[cursor + 7]
+        let b7 = byte(at: cursor + 7)
         if b7 < 0x80 {
             cursor += 8
             return UInt64(b0 & 0x7F) |
@@ -798,7 +816,7 @@ public final class ByteBuffer {
         }
 
         try checkBound(9)
-        let b8 = storage[cursor + 8]
+        let b8 = byte(at: cursor + 8)
         cursor += 9
         let low = UInt64(b0 & 0x7F) |
             (UInt64(b1 & 0x7F) << 7) |
@@ -880,11 +898,20 @@ public final class ByteBuffer {
     @inline(__always)
     public func readUTF8String(count: Int) throws -> String {
         try checkBound(count)
+        if count == 0 {
+            return ""
+        }
         let start = cursor
         let end = start + count
         cursor = end
-        let utf8Bytes = storage[start..<end]
-        guard let decoded = String(bytes: utf8Bytes, encoding: .utf8) else {
+        let decoded = withUnsafeReadableBytes { buffer -> String? in
+            guard let base = buffer.baseAddress else {
+                return nil
+            }
+            let utf8Bytes = UnsafeBufferPointer(start: base.advanced(by: start), count: count)
+            return String(bytes: utf8Bytes, encoding: .utf8)
+        }
+        guard let decoded else {
             throw ForyError.invalidData("invalid UTF-8 sequence")
         }
         return decoded
@@ -898,6 +925,11 @@ public final class ByteBuffer {
 
     @inlinable
     public func toData() -> Data {
-        Data(storage)
+        return storage.withUnsafeBytes { rawBytes in
+            guard let baseAddress = rawBytes.baseAddress else {
+                return Data()
+            }
+            return Data(bytes: baseAddress, count: rawBytes.count)
+        }
     }
 }
diff --git a/swift/Sources/Fory/CollectionSerializers.swift b/swift/Sources/Fory/CollectionSerializers.swift
index b95a71b64..032436a58 100644
--- a/swift/Sources/Fory/CollectionSerializers.swift
+++ b/swift/Sources/Fory/CollectionSerializers.swift
@@ -236,7 +236,7 @@ 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")
+    try context.ensureRemainingBytes(payloadSize, label: "primitive_array_payload")
 
     if Element.self == UInt8.self {
         try context.ensureCollectionLength(payloadSize, label: "uint8_array")
@@ -448,7 +448,7 @@ extension Array: Serializer where Element: Serializer {
         primitiveArrayTypeID(for: Element.self) ?? .list
     }
 
-    public static func foryWriteTypeInfo(_ context: WriteContext) throws {
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
         if Element.self == UInt8.self, context.compatible {
             context.buffer.writeUInt8(UInt8(truncatingIfNeeded: TypeId.binary.rawValue))
             return
@@ -456,7 +456,7 @@ extension Array: Serializer where Element: Serializer {
         context.buffer.writeUInt8(UInt8(truncatingIfNeeded: staticTypeId.rawValue))
     }
 
-    public static func foryReadTypeInfo(_ context: ReadContext) throws {
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
         let rawTypeID = try context.buffer.readVarUInt32()
         guard let actualTypeID = TypeId(rawValue: rawTypeID) else {
             throw ForyError.invalidData("unknown type id \(rawTypeID)")
@@ -464,7 +464,7 @@ extension Array: Serializer where Element: Serializer {
 
         if Element.self == UInt8.self {
             if actualTypeID == .uint8Array || actualTypeID == .binary {
-                return
+                return nil
             }
             throw ForyError.typeMismatch(expected: TypeId.uint8Array.rawValue, actual: rawTypeID)
         }
@@ -473,6 +473,7 @@ extension Array: Serializer where Element: Serializer {
         if actualTypeID != expectedTypeID {
             throw ForyError.typeMismatch(expected: expectedTypeID.rawValue, actual: rawTypeID)
         }
+        return nil
     }
 
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
@@ -488,7 +489,7 @@ extension Array: Serializer where Element: Serializer {
         }
 
         let hasNull = Element.isNullableType && self.contains(where: { $0.foryIsNone })
-        let trackRef = context.trackRef && Element.isReferenceTrackableType
+        let trackRef = context.trackRef && Element.isRefType
         let declaredElementType = hasGenerics && !TypeId.needsTypeInfoForField(Element.staticTypeId)
         let dynamicElementType = Element.staticTypeId == .unknown
 
@@ -505,7 +506,7 @@ extension Array: Serializer where Element: Serializer {
 
         buffer.writeUInt8(header)
         if !dynamicElementType && !declaredElementType {
-            try Element.foryWriteTypeInfo(context)
+            try Element.foryWriteStaticTypeInfo(context)
         }
 
         if dynamicElementType {
@@ -560,8 +561,6 @@ extension Array: Serializer where Element: Serializer {
         let hasNull = (header & CollectionHeader.hasNull) != 0
         let declared = (header & CollectionHeader.declaredElementType) != 0
         let sameType = (header & CollectionHeader.sameType) != 0
-        let canonicalizeElements = context.trackRef && !trackRef && Element.isReferenceTrackableType
-
         if !sameType {
             if trackRef {
                 return try readArrayUninitialized(count: length) { destination in
@@ -580,18 +579,9 @@ extension Array: Serializer where Element: Serializer {
                         if refFlag == RefFlag.null.rawValue {
                             destination.advanced(by: index).initialize(to: Element.foryDefault())
                         } else if refFlag == RefFlag.notNullValue.rawValue {
-                            if canonicalizeElements {
-                                let start = buffer.getCursor()
-                                let value = try Element.foryRead(context, refMode: .none, readTypeInfo: true)
-                                let end = buffer.getCursor()
-                                destination.advanced(by: index).initialize(
-                                    to: context.canonicalizeNonTrackingReference(value, start: start, end: end)
-                                )
-                            } else {
-                                destination.advanced(by: index).initialize(
-                                    to: try Element.foryRead(context, refMode: .none, readTypeInfo: true)
-                                )
-                            }
+                            destination.advanced(by: index).initialize(
+                                to: try Element.foryRead(context, refMode: .none, readTypeInfo: true)
+                            )
                         } else {
                             throw ForyError.refError("invalid nullability flag \(refFlag)")
                         }
@@ -601,84 +591,50 @@ extension Array: Serializer where Element: Serializer {
 
             return try readArrayUninitialized(count: length) { destination in
                 for index in 0..<length {
-                    if canonicalizeElements {
-                        let start = buffer.getCursor()
-                        let value = try Element.foryRead(context, refMode: .none, readTypeInfo: true)
-                        let end = buffer.getCursor()
-                        destination.advanced(by: index).initialize(
-                            to: context.canonicalizeNonTrackingReference(value, start: start, end: end)
-                        )
-                    } else {
-                        destination.advanced(by: index).initialize(
-                            to: try Element.foryRead(context, refMode: .none, readTypeInfo: true)
-                        )
-                    }
+                    destination.advanced(by: index).initialize(
+                        to: try Element.foryRead(context, refMode: .none, readTypeInfo: true)
+                    )
                 }
             }
         }
 
-        if !declared {
-            try Element.foryReadTypeInfo(context)
-        }
-
-        if trackRef {
-            let values = try readArrayUninitialized(count: length) { destination in
-                for index in 0..<length {
-                    destination.advanced(by: index).initialize(
-                        to: try Element.foryRead(context, refMode: .tracking, readTypeInfo: false)
-                    )
+        let elementTypeInfo = declared ? nil : try Element.foryReadTypeInfo(context)
+        return try context.withTypeInfo(elementTypeInfo, for: Element.self) {
+            if trackRef {
+                return try readArrayUninitialized(count: length) { destination in
+                    for index in 0..<length {
+                        destination.advanced(by: index).initialize(
+                            to: try Element.foryRead(context, refMode: .tracking, readTypeInfo: false)
+                        )
+                    }
                 }
             }
-            if !declared {
-                context.clearDynamicTypeInfo(for: Element.self)
-            }
-            return values
-        }
 
-        if hasNull {
-            let values = try readArrayUninitialized(count: length) { destination in
-                for index in 0..<length {
-                    let refFlag = try buffer.readInt8()
-                    if refFlag == RefFlag.null.rawValue {
-                        destination.advanced(by: index).initialize(to: Element.foryDefault())
-                    } else {
-                        if canonicalizeElements {
-                            let start = buffer.getCursor()
-                            let value = try Element.foryReadData(context)
-                            let end = buffer.getCursor()
+            if hasNull {
+                return try readArrayUninitialized(count: length) { destination in
+                    for index in 0..<length {
+                        let refFlag = try buffer.readInt8()
+                        if refFlag == RefFlag.null.rawValue {
+                            destination.advanced(by: index).initialize(to: Element.foryDefault())
+                        } else if refFlag == RefFlag.notNullValue.rawValue {
                             destination.advanced(by: index).initialize(
-                                to: context.canonicalizeNonTrackingReference(value, start: start, end: end)
+                                to: try Element.foryRead(context, refMode: .none, readTypeInfo: false)
                             )
                         } else {
-                            destination.advanced(by: index).initialize(to: try Element.foryReadData(context))
+                            throw ForyError.refError("invalid nullability flag \(refFlag)")
                         }
                     }
                 }
             }
-            if !declared {
-                context.clearDynamicTypeInfo(for: Element.self)
-            }
-            return values
-        }
 
-        let values = try readArrayUninitialized(count: length) { destination in
-            for index in 0..<length {
-                if canonicalizeElements {
-                    let start = buffer.getCursor()
-                    let value = try Element.foryReadData(context)
-                    let end = buffer.getCursor()
+            return try readArrayUninitialized(count: length) { destination in
+                for index in 0..<length {
                     destination.advanced(by: index).initialize(
-                        to: context.canonicalizeNonTrackingReference(value, start: start, end: end)
+                        to: try Element.foryRead(context, refMode: .none, readTypeInfo: false)
                     )
-                } else {
-                    destination.advanced(by: index).initialize(to: try Element.foryReadData(context))
                 }
             }
         }
-        if !declared {
-            context.clearDynamicTypeInfo(for: Element.self)
-        }
-        return values
     }
 }
 
@@ -687,6 +643,14 @@ extension Set: Serializer where Element: Serializer & Hashable {
 
     public static var staticTypeId: TypeId { .set }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         try Array(self).foryWriteData(context, hasGenerics: hasGenerics)
     }
@@ -701,14 +665,22 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
 
     public static var staticTypeId: TypeId { .map }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeVarUInt32(UInt32(self.count))
         if self.isEmpty {
             return
         }
 
-        let trackKeyRef = context.trackRef && Key.isReferenceTrackableType
-        let trackValueRef = context.trackRef && Value.isReferenceTrackableType
+        let trackKeyRef = context.trackRef && Key.isRefType
+        let trackValueRef = context.trackRef && Value.isRefType
         let keyDeclared = hasGenerics && !TypeId.needsTypeInfoForField(Key.staticTypeId)
         let valueDeclared = hasGenerics && !TypeId.needsTypeInfoForField(Value.staticTypeId)
         let keyDynamicType = Key.staticTypeId == .unknown
@@ -745,7 +717,7 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
                         if valueDynamicType {
                             try pair.value.foryWriteTypeInfo(context)
                         } else {
-                            try Value.foryWriteTypeInfo(context)
+                            try Value.foryWriteStaticTypeInfo(context)
                         }
                     }
                     if trackValueRef {
@@ -766,7 +738,7 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
                         if keyDynamicType {
                             try pair.key.foryWriteTypeInfo(context)
                         } else {
-                            try Key.foryWriteTypeInfo(context)
+                            try Key.foryWriteStaticTypeInfo(context)
                         }
                     }
                     if trackKeyRef {
@@ -788,14 +760,14 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
                     if keyDynamicType {
                         try pair.key.foryWriteTypeInfo(context)
                     } else {
-                        try Key.foryWriteTypeInfo(context)
+                        try Key.foryWriteStaticTypeInfo(context)
                     }
                 }
                 if !valueDeclared {
                     if valueDynamicType {
                         try pair.value.foryWriteTypeInfo(context)
                     } else {
-                        try Value.foryWriteTypeInfo(context)
+                        try Value.foryWriteStaticTypeInfo(context)
                     }
                 }
 
@@ -846,7 +818,7 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
                 context.buffer.writeUInt8(header)
                 if !keyIsNil {
                     if !keyDeclared {
-                        try Key.foryWriteTypeInfo(context)
+                        try Key.foryWriteStaticTypeInfo(context)
                     }
                     if trackKeyRef {
                         try pair.key.foryWrite(context, refMode: .tracking, writeTypeInfo: false, hasGenerics: hasGenerics)
@@ -856,7 +828,7 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
                 }
                 if !valueIsNil {
                     if !valueDeclared {
-                        try Value.foryWriteTypeInfo(context)
+                        try Value.foryWriteStaticTypeInfo(context)
                     }
                     if trackValueRef {
                         try pair.value.foryWrite(context, refMode: .tracking, writeTypeInfo: false, hasGenerics: hasGenerics)
@@ -879,10 +851,10 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
             context.buffer.writeUInt8(0)
 
             if !keyDeclared {
-                try Key.foryWriteTypeInfo(context)
+                try Key.foryWriteStaticTypeInfo(context)
             }
             if !valueDeclared {
-                try Value.foryWriteTypeInfo(context)
+                try Value.foryWriteStaticTypeInfo(context)
             }
 
             var chunkSize: UInt8 = 0
@@ -918,8 +890,6 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
         map.reserveCapacity(Swift.min(totalLength, context.buffer.remaining))
         let keyDynamicType = Key.staticTypeId == .unknown
         let valueDynamicType = Value.staticTypeId == .unknown
-        let canonicalizeValues = context.trackRef && Value.isReferenceTrackableType
-
         if keyDynamicType || valueDynamicType {
             var dynamicReadCount = 0
             while dynamicReadCount < totalLength {
@@ -939,27 +909,12 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
                 }
 
                 if keyNull {
-                    if trackValueRef || !canonicalizeValues {
-                        let value = try Value.foryRead(
-                            context,
-                            refMode: trackValueRef ? .tracking : .none,
-                            readTypeInfo: valueDynamicType || !valueDeclared
-                        )
-                        map[Key.foryDefault()] = value
-                    } else {
-                        let start = context.buffer.getCursor()
-                        let value = try Value.foryRead(
-                            context,
-                            refMode: .none,
-                            readTypeInfo: valueDynamicType || !valueDeclared
-                        )
-                        let end = context.buffer.getCursor()
-                        map[Key.foryDefault()] = context.canonicalizeNonTrackingReference(
-                            value,
-                            start: start,
-                            end: end
-                        )
-                    }
+                    let value = try Value.foryRead(
+                        context,
+                        refMode: trackValueRef ? .tracking : .none,
+                        readTypeInfo: valueDynamicType || !valueDeclared
+                    )
+                    map[Key.foryDefault()] = value
                     dynamicReadCount += 1
                     continue
                 }
@@ -979,41 +934,24 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
                 if chunkSize > (totalLength - dynamicReadCount) {
                     throw ForyError.invalidData("map dynamic chunk size exceeds remaining entries")
                 }
-                if !keyDeclared {
-                    try Key.foryReadTypeInfo(context)
-                }
-                if !valueDeclared {
-                    try Value.foryReadTypeInfo(context)
-                }
+                let keyTypeInfo = keyDeclared ? nil : try Key.foryReadTypeInfo(context)
+                let valueTypeInfo = valueDeclared ? nil : try Value.foryReadTypeInfo(context)
                 for _ in 0..<chunkSize {
-                    let key = try Key.foryRead(
-                        context,
-                        refMode: trackKeyRef ? .tracking : .none,
-                        readTypeInfo: false
-                    )
-                    if trackValueRef || !canonicalizeValues {
-                        let value = try Value.foryRead(
+                    let key = try context.withTypeInfo(keyTypeInfo, for: Key.self) {
+                        try Key.foryRead(
                             context,
-                            refMode: trackValueRef ? .tracking : .none,
+                            refMode: trackKeyRef ? .tracking : .none,
                             readTypeInfo: false
                         )
-                        map[key] = value
-                    } else {
-                        let start = context.buffer.getCursor()
-                        let value = try Value.foryRead(
+                    }
+                    let value = try context.withTypeInfo(valueTypeInfo, for: Value.self) {
+                        try Value.foryRead(
                             context,
-                            refMode: .none,
+                            refMode: trackValueRef ? .tracking : .none,
                             readTypeInfo: false
                         )
-                        let end = context.buffer.getCursor()
-                        map[key] = context.canonicalizeNonTrackingReference(value, start: start, end: end)
                     }
-                }
-                if !keyDeclared {
-                    context.clearDynamicTypeInfo(for: Key.self)
-                }
-                if !valueDeclared {
-                    context.clearDynamicTypeInfo(for: Value.self)
+                    map[key] = value
                 }
                 dynamicReadCount += chunkSize
             }
@@ -1038,27 +976,12 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
             }
 
             if keyNull {
-                if trackValueRef || !canonicalizeValues {
-                    let value = try Value.foryRead(
-                        context,
-                        refMode: trackValueRef ? .tracking : .none,
-                        readTypeInfo: !valueDeclared
-                    )
-                    map[Key.foryDefault()] = value
-                } else {
-                    let start = context.buffer.getCursor()
-                    let value = try Value.foryRead(
-                        context,
-                        refMode: .none,
-                        readTypeInfo: !valueDeclared
-                    )
-                    let end = context.buffer.getCursor()
-                    map[Key.foryDefault()] = context.canonicalizeNonTrackingReference(
-                        value,
-                        start: start,
-                        end: end
-                    )
-                }
+                let value = try Value.foryRead(
+                    context,
+                    refMode: trackValueRef ? .tracking : .none,
+                    readTypeInfo: !valueDeclared
+                )
+                map[Key.foryDefault()] = value
                 readCount += 1
                 continue
             }
@@ -1078,36 +1001,24 @@ extension Dictionary: Serializer where Key: Serializer & Hashable, Value: Serial
             if chunkSize > (totalLength - readCount) {
                 throw ForyError.invalidData("map chunk size exceeds remaining entries")
             }
-            if !keyDeclared {
-                try Key.foryReadTypeInfo(context)
-            }
-            if !valueDeclared {
-                try Value.foryReadTypeInfo(context)
-            }
-
+            let keyTypeInfo = keyDeclared ? nil : try Key.foryReadTypeInfo(context)
+            let valueTypeInfo = valueDeclared ? nil : try Value.foryReadTypeInfo(context)
             for _ in 0..<chunkSize {
-                let key = try Key.foryRead(
-                    context,
-                    refMode: trackKeyRef ? .tracking : .none,
-                    readTypeInfo: false
-                )
-                if trackValueRef || !canonicalizeValues {
-                    let value = try Value.foryRead(
+                let key = try context.withTypeInfo(keyTypeInfo, for: Key.self) {
+                    try Key.foryRead(
                         context,
-                        refMode: trackValueRef ? .tracking : .none,
+                        refMode: trackKeyRef ? .tracking : .none,
                         readTypeInfo: false
                     )
-                    map[key] = value
-                } else {
-                    let start = context.buffer.getCursor()
-                    let value = try Value.foryRead(
+                }
+                let value = try context.withTypeInfo(valueTypeInfo, for: Value.self) {
+                    try Value.foryRead(
                         context,
-                        refMode: .none,
+                        refMode: trackValueRef ? .tracking : .none,
                         readTypeInfo: false
                     )
-                    let end = context.buffer.getCursor()
-                    map[key] = context.canonicalizeNonTrackingReference(value, start: start, end: end)
                 }
+                map[key] = value
             }
             readCount += chunkSize
         }
diff --git a/swift/Sources/Fory/CollectionUtil.swift b/swift/Sources/Fory/CollectionUtil.swift
new file mode 100644
index 000000000..889d1cb40
--- /dev/null
+++ b/swift/Sources/Fory/CollectionUtil.swift
@@ -0,0 +1,78 @@
+// 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.
+
+final class ReusableArray<Element> {
+    private var storage: UnsafeMutablePointer<Element>
+    private var capacity: Int
+    private let defaultValue: Element
+    private(set) var used = 0
+
+    init(defaultValue: Element, reserve: Int = 2) {
+        self.defaultValue = defaultValue
+        capacity = max(reserve, 2)
+        storage = UnsafeMutablePointer<Element>.allocate(capacity: capacity)
+        storage.initialize(repeating: defaultValue, count: capacity)
+    }
+
+    deinit {
+        storage.deinitialize(count: capacity)
+        storage.deallocate()
+    }
+
+    /// Reset logical usage to zero in O(1) without clearing backing slots.
+    ///
+    /// This is intentional for hot-path reuse: existing slot values stay in
+    /// storage until they are overwritten by later `push` calls or released by
+    /// `deinit`.
+    @inline(__always)
+    func reset() {
+        used = 0
+    }
+
+    @inline(__always)
+    func push(_ value: Element) {
+        if used == capacity {
+            grow()
+        }
+        storage.advanced(by: used).pointee = value
+        used += 1
+    }
+
+    @inline(__always)
+    func get(_ index: Int) -> Element {
+        guard index >= 0, index < used else {
+            return defaultValue
+        }
+        return storage.advanced(by: index).pointee
+    }
+
+    @inline(__always)
+    var isEmpty: Bool { used == 0 }
+
+    private func grow() {
+        let newCapacity = capacity << 1
+        let newStorage = UnsafeMutablePointer<Element>.allocate(capacity: newCapacity)
+        newStorage.initialize(repeating: defaultValue, count: newCapacity)
+        for index in 0 ..< used {
+            newStorage.advanced(by: index).pointee = storage.advanced(by: index).pointee
+        }
+        storage.deinitialize(count: capacity)
+        storage.deallocate()
+        storage = newStorage
+        capacity = newCapacity
+    }
+}
diff --git a/swift/Sources/Fory/Context.swift b/swift/Sources/Fory/Context.swift
deleted file mode 100644
index 733789bf0..000000000
--- a/swift/Sources/Fory/Context.swift
+++ /dev/null
@@ -1,830 +0,0 @@
-// 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.
-
-import Foundation
-
-public final class CompatibleTypeDefWriteState {
-    private var typeIndexBySwiftType: [ObjectIdentifier: UInt32] = [:]
-    private var nextIndex: UInt32 = 0
-
-    public init() {}
-
-    public func lookupIndex(for typeID: ObjectIdentifier) -> UInt32? {
-        typeIndexBySwiftType[typeID]
-    }
-
-    public func assignIndexIfAbsent(for typeID: ObjectIdentifier) -> (index: UInt32, isNew: Bool) {
-        if let existing = typeIndexBySwiftType[typeID] {
-            return (existing, false)
-        }
-        let index = nextIndex
-        nextIndex &+= 1
-        typeIndexBySwiftType[typeID] = index
-        return (index, true)
-    }
-
-    public func reset() {
-        if !typeIndexBySwiftType.isEmpty {
-            typeIndexBySwiftType.removeAll(keepingCapacity: true)
-        }
-        if nextIndex != 0 {
-            nextIndex = 0
-        }
-    }
-}
-
-public final class CompatibleTypeDefReadState {
-    private var typeMetas: [TypeMeta] = []
-
-    public init() {}
-
-    public func typeMeta(at index: Int) -> TypeMeta? {
-        guard index >= 0, index < typeMetas.count else {
-            return nil
-        }
-        return typeMetas[index]
-    }
-
-    public func storeTypeMeta(_ typeMeta: TypeMeta, at index: Int) throws {
-        if index < 0 {
-            throw ForyError.invalidData("negative compatible type definition index")
-        }
-        if index == typeMetas.count {
-            typeMetas.append(typeMeta)
-            return
-        }
-        if index < typeMetas.count {
-            typeMetas[index] = typeMeta
-            return
-        }
-        throw ForyError.invalidData(
-            "compatible type definition index gap: index=\(index), count=\(typeMetas.count)"
-        )
-    }
-
-    public func reset() {
-        if !typeMetas.isEmpty {
-            typeMetas.removeAll(keepingCapacity: true)
-        }
-    }
-}
-
-private struct MetaStringCacheKey: Hashable {
-    let encoding: MetaStringEncoding
-    let bytes: [UInt8]
-}
-
-private struct CanonicalReferenceSignature: Hashable {
-    let typeID: ObjectIdentifier
-    let hashLo: UInt64
-    let hashHi: UInt64
-    let length: Int
-}
-
-private struct CanonicalReferenceEntry {
-    let bytes: [UInt8]
-    let object: AnyObject
-}
-
-public final class MetaStringWriteState {
-    private var stringIndexByKey: [MetaStringCacheKey: UInt32] = [:]
-    private var nextIndex: UInt32 = 0
-
-    public init() {}
-
-    public func index(for value: MetaString) -> UInt32? {
-        stringIndexByKey[MetaStringCacheKey(encoding: value.encoding, bytes: value.bytes)]
-    }
-
-    public func assignIndexIfAbsent(for value: MetaString) -> (index: UInt32, isNew: Bool) {
-        let key = MetaStringCacheKey(encoding: value.encoding, bytes: value.bytes)
-        if let existing = stringIndexByKey[key] {
-            return (existing, false)
-        }
-        let index = nextIndex
-        nextIndex &+= 1
-        stringIndexByKey[key] = index
-        return (index, true)
-    }
-
-    public func reset() {
-        if !stringIndexByKey.isEmpty {
-            stringIndexByKey.removeAll(keepingCapacity: true)
-        }
-        if nextIndex != 0 {
-            nextIndex = 0
-        }
-    }
-}
-
-public final class MetaStringReadState {
-    private var values: [MetaString] = []
-
-    public init() {}
-
-    public func value(at index: Int) -> MetaString? {
-        guard index >= 0, index < values.count else {
-            return nil
-        }
-        return values[index]
-    }
-
-    public func append(_ value: MetaString) {
-        values.append(value)
-    }
-
-    public func reset() {
-        if !values.isEmpty {
-            values.removeAll(keepingCapacity: true)
-        }
-    }
-}
-
-public struct DynamicTypeInfo {
-    public let wireTypeID: TypeId
-    public let userTypeID: UInt32?
-    public let namespace: MetaString?
-    public let typeName: MetaString?
-    public let compatibleTypeMeta: TypeMeta?
-
-    public init(
-        wireTypeID: TypeId,
-        userTypeID: UInt32?,
-        namespace: MetaString?,
-        typeName: MetaString?,
-        compatibleTypeMeta: TypeMeta?
-    ) {
-        self.wireTypeID = wireTypeID
-        self.userTypeID = userTypeID
-        self.namespace = namespace
-        self.typeName = typeName
-        self.compatibleTypeMeta = compatibleTypeMeta
-    }
-}
-
-public final class WriteContext {
-    public let buffer: ByteBuffer
-    public let typeResolver: TypeResolver
-    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,
-        typeResolver: TypeResolver,
-        trackRef: Bool,
-        compatible: Bool = false,
-        checkClassVersion: Bool = true,
-        maxDepth: Int = 5,
-        compatibleTypeDefState: CompatibleTypeDefWriteState = CompatibleTypeDefWriteState(),
-        metaStringWriteState: MetaStringWriteState = MetaStringWriteState()
-    ) {
-        self.buffer = buffer
-        self.typeResolver = typeResolver
-        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
-    ) throws {
-        try writeCompatibleTypeMeta(
-            for: type,
-            encodedTypeMeta: typeMeta.encode()
-        )
-    }
-
-    public func writeCompatibleTypeMeta<T: Serializer>(
-        for type: T.Type,
-        encodedTypeMeta: [UInt8]
-    ) throws {
-        compatibleTypeDefStateUsed = true
-        let typeID = ObjectIdentifier(type)
-        let assignment = compatibleTypeDefState.assignIndexIfAbsent(for: typeID)
-        if assignment.isNew {
-            buffer.writeVarUInt32(assignment.index << 1)
-            buffer.writeBytes(encodedTypeMeta)
-        } else {
-            buffer.writeVarUInt32((assignment.index << 1) | 1)
-        }
-    }
-
-    public func resetObjectState() {
-        if dynamicAnyDepth != 0 {
-            dynamicAnyDepth = 0
-        }
-        if trackRef {
-            refWriter.reset()
-        }
-    }
-
-    @inline(__always)
-    public func markMetaStringWriteStateUsed() {
-        metaStringWriteStateUsed = true
-    }
-
-    public func reset() {
-        resetObjectState()
-        if compatibleTypeDefStateUsed {
-            compatibleTypeDefState.reset()
-            compatibleTypeDefStateUsed = false
-        }
-        if metaStringWriteStateUsed {
-            metaStringWriteState.reset()
-            metaStringWriteStateUsed = false
-        }
-    }
-}
-
-private struct PendingRefSlot {
-    var refID: UInt32
-    var bound: Bool
-}
-
-public final class ReadContext {
-    public let buffer: ByteBuffer
-    public let typeResolver: TypeResolver
-    public let trackRef: Bool
-    public let compatible: Bool
-    public let checkClassVersion: Bool
-    public let maxCollectionSize: Int
-    public let maxBinarySize: 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]] = [:]
-    private var pendingDynamicTypeInfo: [ObjectIdentifier: DynamicTypeInfo] = [:]
-    private var canonicalReferenceCache: [CanonicalReferenceSignature: [CanonicalReferenceEntry]] = [:]
-
-    public init(
-        buffer: ByteBuffer,
-        typeResolver: TypeResolver,
-        trackRef: Bool,
-        compatible: Bool = false,
-        checkClassVersion: Bool = true,
-        maxCollectionSize: Int = 1_000_000,
-        maxBinarySize: Int = 64 * 1024 * 1024,
-        maxDepth: Int = 5,
-        compatibleTypeDefState: CompatibleTypeDefReadState = CompatibleTypeDefReadState(),
-        metaStringReadState: MetaStringReadState = MetaStringReadState()
-    ) {
-        self.buffer = buffer
-        self.typeResolver = typeResolver
-        self.trackRef = trackRef
-        self.compatible = compatible
-        self.checkClassVersion = checkClassVersion
-        self.maxCollectionSize = maxCollectionSize
-        self.maxBinarySize = maxBinarySize
-        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 > maxCollectionSize {
-            throw ForyError.invalidData(
-                "\(label) length \(length) exceeds configured maxCollectionSize \(maxCollectionSize)"
-            )
-        }
-    }
-
-    @inline(__always)
-    public func ensureBinaryLength(_ length: Int, label: String) throws {
-        if length < 0 {
-            throw ForyError.invalidData("\(label) size is negative")
-        }
-        if length > maxBinarySize {
-            throw ForyError.invalidData(
-                "\(label) size \(length) exceeds configured maxBinarySize \(maxBinarySize)"
-            )
-        }
-    }
-
-    @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))
-    }
-
-    public func bindPendingReference(_ value: Any) {
-        guard var last = pendingRefStack.popLast() else {
-            return
-        }
-        last.bound = true
-        refReader.storeRef(value, at: last.refID)
-        pendingRefStack.append(last)
-    }
-
-    public func finishPendingReferenceIfNeeded(_ value: Any) {
-        guard var last = pendingRefStack.popLast() else {
-            return
-        }
-        if !last.bound {
-            refReader.storeRef(value, at: last.refID)
-            last.bound = true
-        }
-    }
-
-    public func popPendingReference() {
-        _ = pendingRefStack.popLast()
-    }
-
-    public func readCompatibleTypeMeta() throws -> TypeMeta {
-        compatibleTypeDefStateUsed = true
-        let indexMarker = try buffer.readVarUInt32()
-        let isRef = (indexMarker & 1) == 1
-        let index = Int(indexMarker >> 1)
-        if isRef {
-            guard let typeMeta = compatibleTypeDefState.typeMeta(at: index) else {
-                throw ForyError.invalidData("unknown compatible type definition ref index \(index)")
-            }
-            return typeMeta
-        }
-        let typeMeta = try TypeMeta.decode(buffer)
-        try compatibleTypeDefState.storeTypeMeta(typeMeta, at: index)
-        return typeMeta
-    }
-
-    public func pushCompatibleTypeMeta<T: Serializer>(for type: T.Type, _ typeMeta: TypeMeta) {
-        let typeID = ObjectIdentifier(type)
-        pendingCompatibleTypeMeta[typeID] = [typeMeta]
-    }
-
-    public func consumeCompatibleTypeMeta<T: Serializer>(for type: T.Type) throws -> TypeMeta {
-        let typeID = ObjectIdentifier(type)
-        guard let stack = pendingCompatibleTypeMeta[typeID], let last = stack.last else {
-            throw ForyError.invalidData("missing compatible type metadata for \(type)")
-        }
-        return last
-    }
-
-    @inline(__always)
-    public func consumeCompatibleTypeMetaIfPresent<T: Serializer>(for type: T.Type) -> TypeMeta? {
-        let typeID = ObjectIdentifier(type)
-        return pendingCompatibleTypeMeta[typeID]?.last
-    }
-
-    public func setDynamicTypeInfo<T: Serializer>(for type: T.Type, _ typeInfo: DynamicTypeInfo) {
-        pendingDynamicTypeInfo[ObjectIdentifier(type)] = typeInfo
-    }
-
-    public func dynamicTypeInfo<T: Serializer>(for type: T.Type) -> DynamicTypeInfo? {
-        pendingDynamicTypeInfo[ObjectIdentifier(type)]
-    }
-
-    public func clearDynamicTypeInfo<T: Serializer>(for type: T.Type) {
-        pendingDynamicTypeInfo.removeValue(forKey: ObjectIdentifier(type))
-    }
-
-    public func canonicalizeNonTrackingReference<T>(
-        _ value: T,
-        start: Int,
-        end: Int
-    ) -> T {
-        guard trackRef else {
-            return value
-        }
-        guard end > start else {
-            return value
-        }
-        guard let object = value as AnyObject? else {
-            return value
-        }
-
-        let bytes = Array(buffer.storage[start..<end])
-        let (hashLo, hashHi) = MurmurHash3.x64_128(bytes, seed: 47)
-        let signature = CanonicalReferenceSignature(
-            typeID: ObjectIdentifier(type(of: object)),
-            hashLo: hashLo,
-            hashHi: hashHi,
-            length: bytes.count
-        )
-
-        if var bucket = canonicalReferenceCache[signature] {
-            for entry in bucket where entry.bytes == bytes {
-                if let shared = entry.object as? T {
-                    return shared
-                }
-            }
-            bucket.append(CanonicalReferenceEntry(bytes: bytes, object: object))
-            canonicalReferenceCache[signature] = bucket
-            return value
-        }
-
-        canonicalReferenceCache[signature] = [CanonicalReferenceEntry(bytes: bytes, object: object)]
-        return value
-    }
-
-    @inline(__always)
-    public func markMetaStringReadStateUsed() {
-        metaStringReadStateUsed = true
-    }
-
-    public func resetObjectState() {
-        if dynamicAnyDepth != 0 {
-            dynamicAnyDepth = 0
-        }
-        if trackRef {
-            refReader.reset()
-            if !pendingRefStack.isEmpty {
-                pendingRefStack.removeAll(keepingCapacity: true)
-            }
-        }
-        if compatible, !pendingCompatibleTypeMeta.isEmpty {
-            pendingCompatibleTypeMeta.removeAll(keepingCapacity: true)
-        }
-        if !pendingDynamicTypeInfo.isEmpty {
-            pendingDynamicTypeInfo.removeAll(keepingCapacity: true)
-        }
-        if trackRef, !canonicalReferenceCache.isEmpty {
-            canonicalReferenceCache.removeAll(keepingCapacity: true)
-        }
-    }
-
-    public func reset() {
-        resetObjectState()
-        if compatibleTypeDefStateUsed {
-            compatibleTypeDefState.reset()
-            compatibleTypeDefStateUsed = false
-        }
-        if metaStringReadStateUsed {
-            metaStringReadState.reset()
-            metaStringReadStateUsed = false
-        }
-    }
-}
-
-@inline(__always)
-private func writeAnyGlobal(
-    _ value: Any?,
-    context: WriteContext,
-    refMode: RefMode,
-    writeTypeInfo: Bool,
-    hasGenerics: Bool
-) throws {
-    try writeAny(
-        value,
-        context: context,
-        refMode: refMode,
-        writeTypeInfo: writeTypeInfo,
-        hasGenerics: hasGenerics
-    )
-}
-
-@inline(__always)
-private func writeAnyListGlobal(
-    _ value: [Any]?,
-    context: WriteContext,
-    refMode: RefMode,
-    writeTypeInfo: Bool,
-    hasGenerics: Bool
-) throws {
-    try writeAnyList(
-        value,
-        context: context,
-        refMode: refMode,
-        writeTypeInfo: writeTypeInfo,
-        hasGenerics: hasGenerics
-    )
-}
-
-@inline(__always)
-private func writeStringAnyMapGlobal(
-    _ value: [String: Any]?,
-    context: WriteContext,
-    refMode: RefMode,
-    writeTypeInfo: Bool,
-    hasGenerics: Bool
-) throws {
-    try writeStringAnyMap(
-        value,
-        context: context,
-        refMode: refMode,
-        writeTypeInfo: writeTypeInfo,
-        hasGenerics: hasGenerics
-    )
-}
-
-@inline(__always)
-private func writeInt32AnyMapGlobal(
-    _ value: [Int32: Any]?,
-    context: WriteContext,
-    refMode: RefMode,
-    writeTypeInfo: Bool,
-    hasGenerics: Bool
-) throws {
-    try writeInt32AnyMap(
-        value,
-        context: context,
-        refMode: refMode,
-        writeTypeInfo: writeTypeInfo,
-        hasGenerics: hasGenerics
-    )
-}
-
-@inline(__always)
-private func writeAnyHashableAnyMapGlobal(
-    _ value: [AnyHashable: Any]?,
-    context: WriteContext,
-    refMode: RefMode,
-    writeTypeInfo: Bool,
-    hasGenerics: Bool
-) throws {
-    try writeAnyHashableAnyMap(
-        value,
-        context: context,
-        refMode: refMode,
-        writeTypeInfo: writeTypeInfo,
-        hasGenerics: hasGenerics
-    )
-}
-
-@inline(__always)
-private func readAnyGlobal(
-    context: ReadContext,
-    refMode: RefMode,
-    readTypeInfo: Bool
-) throws -> Any? {
-    try readAny(
-        context: context,
-        refMode: refMode,
-        readTypeInfo: readTypeInfo
-    )
-}
-
-@inline(__always)
-private func readAnyListGlobal(
-    context: ReadContext,
-    refMode: RefMode,
-    readTypeInfo: Bool
-) throws -> [Any]? {
-    try readAnyList(
-        context: context,
-        refMode: refMode,
-        readTypeInfo: readTypeInfo
-    )
-}
-
-@inline(__always)
-private func readStringAnyMapGlobal(
-    context: ReadContext,
-    refMode: RefMode,
-    readTypeInfo: Bool
-) throws -> [String: Any]? {
-    try readStringAnyMap(
-        context: context,
-        refMode: refMode,
-        readTypeInfo: readTypeInfo
-    )
-}
-
-@inline(__always)
-private func readInt32AnyMapGlobal(
-    context: ReadContext,
-    refMode: RefMode,
-    readTypeInfo: Bool
-) throws -> [Int32: Any]? {
-    try readInt32AnyMap(
-        context: context,
-        refMode: refMode,
-        readTypeInfo: readTypeInfo
-    )
-}
-
-@inline(__always)
-private func readAnyHashableAnyMapGlobal(
-    context: ReadContext,
-    refMode: RefMode,
-    readTypeInfo: Bool
-) throws -> [AnyHashable: Any]? {
-    try readAnyHashableAnyMap(
-        context: context,
-        refMode: refMode,
-        readTypeInfo: readTypeInfo
-    )
-}
-
-public extension WriteContext {
-    func writeAny(
-        _ value: Any?,
-        refMode: RefMode,
-        writeTypeInfo: Bool = true,
-        hasGenerics: Bool = false
-    ) throws {
-        try writeAnyGlobal(
-            value,
-            context: self,
-            refMode: refMode,
-            writeTypeInfo: writeTypeInfo,
-            hasGenerics: hasGenerics
-        )
-    }
-
-    func writeAnyList(
-        _ value: [Any]?,
-        refMode: RefMode,
-        writeTypeInfo: Bool = false,
-        hasGenerics: Bool = true
-    ) throws {
-        try writeAnyListGlobal(
-            value,
-            context: self,
-            refMode: refMode,
-            writeTypeInfo: writeTypeInfo,
-            hasGenerics: hasGenerics
-        )
-    }
-
-    func writeStringAnyMap(
-        _ value: [String: Any]?,
-        refMode: RefMode,
-        writeTypeInfo: Bool = false,
-        hasGenerics: Bool = true
-    ) throws {
-        try writeStringAnyMapGlobal(
-            value,
-            context: self,
-            refMode: refMode,
-            writeTypeInfo: writeTypeInfo,
-            hasGenerics: hasGenerics
-        )
-    }
-
-    func writeInt32AnyMap(
-        _ value: [Int32: Any]?,
-        refMode: RefMode,
-        writeTypeInfo: Bool = false,
-        hasGenerics: Bool = true
-    ) throws {
-        try writeInt32AnyMapGlobal(
-            value,
-            context: self,
-            refMode: refMode,
-            writeTypeInfo: writeTypeInfo,
-            hasGenerics: hasGenerics
-        )
-    }
-
-    func writeAnyHashableAnyMap(
-        _ value: [AnyHashable: Any]?,
-        refMode: RefMode,
-        writeTypeInfo: Bool = false,
-        hasGenerics: Bool = true
-    ) throws {
-        try writeAnyHashableAnyMapGlobal(
-            value,
-            context: self,
-            refMode: refMode,
-            writeTypeInfo: writeTypeInfo,
-            hasGenerics: hasGenerics
-        )
-    }
-}
-
-public extension ReadContext {
-    func readAny(
-        refMode: RefMode,
-        readTypeInfo: Bool = true
-    ) throws -> Any? {
-        try readAnyGlobal(
-            context: self,
-            refMode: refMode,
-            readTypeInfo: readTypeInfo
-        )
-    }
-
-    func readAnyList(
-        refMode: RefMode,
-        readTypeInfo: Bool = false
-    ) throws -> [Any]? {
-        try readAnyListGlobal(
-            context: self,
-            refMode: refMode,
-            readTypeInfo: readTypeInfo
-        )
-    }
-
-    func readStringAnyMap(
-        refMode: RefMode,
-        readTypeInfo: Bool = false
-    ) throws -> [String: Any]? {
-        try readStringAnyMapGlobal(
-            context: self,
-            refMode: refMode,
-            readTypeInfo: readTypeInfo
-        )
-    }
-
-    func readInt32AnyMap(
-        refMode: RefMode,
-        readTypeInfo: Bool = false
-    ) throws -> [Int32: Any]? {
-        try readInt32AnyMapGlobal(
-            context: self,
-            refMode: refMode,
-            readTypeInfo: readTypeInfo
-        )
-    }
-
-    func readAnyHashableAnyMap(
-        refMode: RefMode,
-        readTypeInfo: Bool = false
-    ) throws -> [AnyHashable: Any]? {
-        try readAnyHashableAnyMapGlobal(
-            context: self,
-            refMode: refMode,
-            readTypeInfo: readTypeInfo
-        )
-    }
-}
diff --git a/swift/Sources/Fory/DateTimeSerializers.swift b/swift/Sources/Fory/DateTimeSerializers.swift
index 3fa502c15..ddd2ebd52 100644
--- a/swift/Sources/Fory/DateTimeSerializers.swift
+++ b/swift/Sources/Fory/DateTimeSerializers.swift
@@ -32,6 +32,14 @@ public struct ForyDate: Serializer, Equatable, Hashable {
         .date
     }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeInt32(daysSinceEpoch)
@@ -60,6 +68,14 @@ public struct ForyTimestamp: Serializer, Equatable, Hashable {
         .timestamp
     }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeInt64(seconds)
@@ -103,6 +119,14 @@ extension Duration: Serializer {
         .duration
     }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         let components = self.components
@@ -131,6 +155,14 @@ extension Date: Serializer {
         .timestamp
     }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         let ts = ForyTimestamp(date: self)
diff --git a/swift/Sources/Fory/FieldSkipper.swift b/swift/Sources/Fory/FieldSkipper.swift
index 12efc5a34..d61c6462d 100644
--- a/swift/Sources/Fory/FieldSkipper.swift
+++ b/swift/Sources/Fory/FieldSkipper.swift
@@ -17,72 +17,63 @@
 
 import Foundation
 
-public enum FieldSkipper {
-    public static func skipFieldValue(
-        context: ReadContext,
-        fieldType: TypeMetaFieldType
-    ) throws {
-        _ = try readFieldValue(
-            context: context,
+public extension ReadContext {
+    func skipFieldValue(_ fieldType: TypeMeta.FieldType) throws {
+        _ = try readSkippedFieldValue(
             fieldType: fieldType,
-            readTypeInfo: needsTypeInfoForField(fieldType.typeID)
+            readTypeInfo: needsTypeInfoForSkippedField(fieldType.typeID)
         )
     }
 
-    private static func needsTypeInfoForField(_ typeID: UInt32) -> Bool {
+    private func needsTypeInfoForSkippedField(_ 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,
+    private func readSkippedFieldValue(
+        fieldType: TypeMeta.FieldType,
+        typeInfo: TypeInfo? = nil,
         readTypeInfo: Bool
     ) throws -> Any? {
         let refMode = RefMode.from(nullable: fieldType.nullable, trackRef: fieldType.trackRef)
-        return try readValueWithRefMode(
-            context: context,
+        return try readSkippedValue(
             fieldType: fieldType,
-            runtimeTypeInfo: runtimeTypeInfo,
+            typeInfo: typeInfo,
             refMode: refMode,
             readTypeInfo: readTypeInfo
         )
     }
 
-    private static func readValueWithRefMode(
-        context: ReadContext,
-        fieldType: TypeMetaFieldType,
-        runtimeTypeInfo: DynamicTypeInfo?,
+    private func readSkippedValue(
+        fieldType: TypeMeta.FieldType,
+        typeInfo: TypeInfo?,
         refMode: RefMode,
         readTypeInfo: Bool
     ) throws -> Any? {
         switch refMode {
         case .none:
-            return try readFieldPayload(
-                context: context,
+            return try readSkippedFieldPayload(
                 fieldType: fieldType,
-                runtimeTypeInfo: runtimeTypeInfo,
+                typeInfo: typeInfo,
                 readTypeInfo: readTypeInfo
             )
         case .nullOnly:
-            let flag = try context.buffer.readInt8()
+            let flag = try buffer.readInt8()
             if flag == RefFlag.null.rawValue {
                 return nil
             }
             guard flag == RefFlag.notNullValue.rawValue else {
                 throw ForyError.invalidData("unexpected nullOnly flag \(flag)")
             }
-            return try readFieldPayload(
-                context: context,
+            return try readSkippedFieldPayload(
                 fieldType: fieldType,
-                runtimeTypeInfo: runtimeTypeInfo,
+                typeInfo: typeInfo,
                 readTypeInfo: readTypeInfo
             )
         case .tracking:
-            let rawFlag = try context.buffer.readInt8()
+            let rawFlag = try buffer.readInt8()
             guard let flag = RefFlag(rawValue: rawFlag) else {
                 throw ForyError.invalidData("unexpected tracking flag \(rawFlag)")
             }
@@ -91,41 +82,38 @@ public enum FieldSkipper {
             case .null:
                 return nil
             case .ref:
-                let refID = try context.buffer.readVarUInt32()
-                return try context.refReader.readRefValue(refID)
+                let refID = try buffer.readVarUInt32()
+                return try refReader.readRefValue(refID)
             case .refValue:
-                let refID = context.refReader.reserveRefID()
-                let value = try readFieldPayload(
-                    context: context,
+                let refID = refReader.reserveRefID()
+                let value = try readSkippedFieldPayload(
                     fieldType: fieldType,
-                    runtimeTypeInfo: runtimeTypeInfo,
+                    typeInfo: typeInfo,
                     readTypeInfo: readTypeInfo
                 )
-                context.refReader.storeRef(value, at: refID)
+                refReader.storeRef(value, at: refID)
                 return value
             case .notNullValue:
-                return try readFieldPayload(
-                    context: context,
+                return try readSkippedFieldPayload(
                     fieldType: fieldType,
-                    runtimeTypeInfo: runtimeTypeInfo,
+                    typeInfo: typeInfo,
                     readTypeInfo: readTypeInfo
                 )
             }
         }
     }
 
-    private static func readFieldPayload(
-        context: ReadContext,
-        fieldType: TypeMetaFieldType,
-        runtimeTypeInfo: DynamicTypeInfo?,
+    private func readSkippedFieldPayload(
+        fieldType: TypeMeta.FieldType,
+        typeInfo: TypeInfo?,
         readTypeInfo: Bool
     ) throws -> Any {
-        if let runtimeTypeInfo {
-            return try context.typeResolver.readDynamicValue(typeInfo: runtimeTypeInfo, context: context)
+        if let typeInfo {
+            return try readAnyValue(typeInfo: typeInfo)
         }
         if readTypeInfo {
-            let typeInfo = try context.typeResolver.readDynamicTypeInfo(context: context)
-            return try context.typeResolver.readDynamicValue(typeInfo: typeInfo, context: context)
+            let typeInfo = try self.readTypeInfo()
+            return try readAnyValue(typeInfo: typeInfo)
         }
 
         guard let resolvedTypeID = TypeId(rawValue: fieldType.typeID) else {
@@ -136,144 +124,140 @@ public enum FieldSkipper {
         case .none:
             return ForyAnyNullValue()
         case .bool:
-            return try Bool.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Bool.foryRead(self, refMode: .none, readTypeInfo: false)
         case .int8:
-            return try Int8.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Int8.foryRead(self, refMode: .none, readTypeInfo: false)
         case .int16:
-            return try Int16.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Int16.foryRead(self, refMode: .none, readTypeInfo: false)
         case .int32:
-            return try ForyInt32Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try ForyInt32Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
         case .varint32:
-            return try Int32.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Int32.foryRead(self, refMode: .none, readTypeInfo: false)
         case .int64:
-            return try ForyInt64Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try ForyInt64Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
         case .varint64:
-            return try Int64.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Int64.foryRead(self, refMode: .none, readTypeInfo: false)
         case .taggedInt64:
-            return try ForyInt64Tagged.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try ForyInt64Tagged.foryRead(self, refMode: .none, readTypeInfo: false)
         case .uint8:
-            return try UInt8.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try UInt8.foryRead(self, refMode: .none, readTypeInfo: false)
         case .uint16:
-            return try UInt16.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try UInt16.foryRead(self, refMode: .none, readTypeInfo: false)
         case .uint32:
-            return try ForyUInt32Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try ForyUInt32Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
         case .varUInt32:
-            return try UInt32.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try UInt32.foryRead(self, refMode: .none, readTypeInfo: false)
         case .uint64:
-            return try ForyUInt64Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try ForyUInt64Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
         case .varUInt64:
-            return try UInt64.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try UInt64.foryRead(self, refMode: .none, readTypeInfo: false)
         case .taggedUInt64:
-            return try ForyUInt64Tagged.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try ForyUInt64Tagged.foryRead(self, refMode: .none, readTypeInfo: false)
         case .float16:
-            return try Float16.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Float16.foryRead(self, refMode: .none, readTypeInfo: false)
         case .bfloat16:
-            return try BFloat16.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try BFloat16.foryRead(self, refMode: .none, readTypeInfo: false)
         case .float32:
-            return try Float.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Float.foryRead(self, refMode: .none, readTypeInfo: false)
         case .float64:
-            return try Double.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Double.foryRead(self, refMode: .none, readTypeInfo: false)
         case .string:
-            return try String.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try String.foryRead(self, refMode: .none, readTypeInfo: false)
         case .duration:
-            return try Duration.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Duration.foryRead(self, refMode: .none, readTypeInfo: false)
         case .timestamp:
-            return try Date.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Date.foryRead(self, refMode: .none, readTypeInfo: false)
         case .date:
-            return try ForyDate.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try ForyDate.foryRead(self, refMode: .none, readTypeInfo: false)
         case .binary, .uint8Array:
-            return try Data.foryRead(context, refMode: .none, readTypeInfo: false)
+            return try Data.foryRead(self, refMode: .none, readTypeInfo: false)
         case .boolArray:
-            return try [Bool].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Bool].foryRead(self, refMode: .none, readTypeInfo: false)
         case .int8Array:
-            return try [Int8].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Int8].foryRead(self, refMode: .none, readTypeInfo: false)
         case .int16Array:
-            return try [Int16].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Int16].foryRead(self, refMode: .none, readTypeInfo: false)
         case .int32Array:
-            return try [Int32].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Int32].foryRead(self, refMode: .none, readTypeInfo: false)
         case .int64Array:
-            return try [Int64].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Int64].foryRead(self, refMode: .none, readTypeInfo: false)
         case .uint16Array:
-            return try [UInt16].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [UInt16].foryRead(self, refMode: .none, readTypeInfo: false)
         case .uint32Array:
-            return try [UInt32].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [UInt32].foryRead(self, refMode: .none, readTypeInfo: false)
         case .uint64Array:
-            return try [UInt64].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [UInt64].foryRead(self, refMode: .none, readTypeInfo: false)
         case .float16Array:
-            return try [Float16].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Float16].foryRead(self, refMode: .none, readTypeInfo: false)
         case .bfloat16Array:
-            return try [BFloat16].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [BFloat16].foryRead(self, refMode: .none, readTypeInfo: false)
         case .float32Array:
-            return try [Float].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Float].foryRead(self, refMode: .none, readTypeInfo: false)
         case .float64Array:
-            return try [Double].foryRead(context, refMode: .none, readTypeInfo: false)
+            return try [Double].foryRead(self, refMode: .none, readTypeInfo: false)
         case .array, .list:
-            return try readCollection(context: context, fieldType: fieldType)
+            return try readSkippedCollection(fieldType: fieldType)
         case .set:
-            return try readSet(context: context, fieldType: fieldType)
+            return try readSkippedSet(fieldType: fieldType)
         case .map:
-            return try readMap(context: context, fieldType: fieldType)
+            return try readSkippedMap(fieldType: fieldType)
         case .union, .typedUnion, .namedUnion:
-            return try readUnion(context: context)
+            return try readSkippedUnion()
         case .enumType, .namedEnum:
-            return try context.buffer.readVarUInt32()
+            return try buffer.readVarUInt32()
         default:
             throw ForyError.invalidData("unsupported compatible field type id \(fieldType.typeID)")
         }
     }
 
-    private static func readCollection(
-        context: ReadContext,
-        fieldType: TypeMetaFieldType
+    private func readSkippedCollection(
+        fieldType: TypeMeta.FieldType
     ) 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")
+            ?? TypeMeta.FieldType(typeID: TypeId.unknown.rawValue, nullable: true)
+        let length = Int(try buffer.readVarUInt32())
+        try ensureCollectionLength(length, label: "compatible_collection")
         if length == 0 {
             return []
         }
 
-        let header = try context.buffer.readUInt8()
+        let header = try 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?
+        var typeInfo: TypeInfo?
         if sameType, !declared {
-            runtimeTypeInfo = try context.typeResolver.readDynamicTypeInfo(context: context)
+            typeInfo = try self.readTypeInfo()
         }
 
         for _ in 0..<length {
             if sameType {
                 if trackRef {
-                    _ = try readValueWithRefMode(
-                        context: context,
+                    _ = try readSkippedValue(
                         fieldType: elementFieldType,
-                        runtimeTypeInfo: runtimeTypeInfo,
+                        typeInfo: typeInfo,
                         refMode: .tracking,
                         readTypeInfo: false
                     )
                 } else if hasNull {
-                    let refFlag = try context.buffer.readInt8()
+                    let refFlag = try 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,
+                    _ = try readSkippedFieldPayload(
                         fieldType: elementFieldType,
-                        runtimeTypeInfo: runtimeTypeInfo,
+                        typeInfo: typeInfo,
                         readTypeInfo: false
                     )
                 } else {
-                    _ = try readFieldPayload(
-                        context: context,
+                    _ = try readSkippedFieldPayload(
                         fieldType: elementFieldType,
-                        runtimeTypeInfo: runtimeTypeInfo,
+                        typeInfo: typeInfo,
                         readTypeInfo: false
                     )
                 }
@@ -281,32 +265,29 @@ public enum FieldSkipper {
             }
 
             if trackRef {
-                _ = try readValueWithRefMode(
-                    context: context,
+                _ = try readSkippedValue(
                     fieldType: elementFieldType,
-                    runtimeTypeInfo: nil,
+                    typeInfo: nil,
                     refMode: .tracking,
                     readTypeInfo: true
                 )
             } else if hasNull {
-                let refFlag = try context.buffer.readInt8()
+                let refFlag = try 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,
+                _ = try readSkippedFieldPayload(
                     fieldType: elementFieldType,
-                    runtimeTypeInfo: nil,
+                    typeInfo: nil,
                     readTypeInfo: true
                 )
             } else {
-                _ = try readFieldPayload(
-                    context: context,
+                _ = try readSkippedFieldPayload(
                     fieldType: elementFieldType,
-                    runtimeTypeInfo: nil,
+                    typeInfo: nil,
                     readTypeInfo: true
                 )
             }
@@ -315,32 +296,30 @@ public enum FieldSkipper {
         return []
     }
 
-    private static func readSet(
-        context: ReadContext,
-        fieldType: TypeMetaFieldType
+    private func readSkippedSet(
+        fieldType: TypeMeta.FieldType
     ) throws -> Set<AnyHashable> {
-        _ = try readCollection(context: context, fieldType: fieldType)
+        _ = try readSkippedCollection(fieldType: fieldType)
         return []
     }
 
-    private static func readMap(
-        context: ReadContext,
-        fieldType: TypeMetaFieldType
+    private func readSkippedMap(
+        fieldType: TypeMeta.FieldType
     ) throws -> [AnyHashable: Any] {
         let keyType = fieldType.generics.first
-            ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: true)
+            ?? TypeMeta.FieldType(typeID: TypeId.unknown.rawValue, nullable: true)
         let valueType = fieldType.generics.dropFirst().first
-            ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: true)
+            ?? TypeMeta.FieldType(typeID: TypeId.unknown.rawValue, nullable: true)
 
-        let totalLength = Int(try context.buffer.readVarUInt32())
-        try context.ensureCollectionLength(totalLength, label: "compatible_map")
+        let totalLength = Int(try buffer.readVarUInt32())
+        try ensureCollectionLength(totalLength, label: "compatible_map")
         if totalLength == 0 {
             return [:]
         }
 
         var readCount = 0
         while readCount < totalLength {
-            let header = try context.buffer.readUInt8()
+            let header = try buffer.readUInt8()
             let trackKeyRef = (header & 0b0000_0001) != 0
             let keyNull = (header & 0b0000_0010) != 0
             let keyDeclared = (header & 0b0000_0100) != 0
@@ -355,11 +334,10 @@ public enum FieldSkipper {
             }
 
             if keyNull {
-                let valueRuntimeType = valueDeclared ? nil : try context.typeResolver.readDynamicTypeInfo(context: context)
-                _ = try readValueWithRefMode(
-                    context: context,
+                let valueTypeInfo = valueDeclared ? nil : try self.readTypeInfo()
+                _ = try readSkippedValue(
                     fieldType: valueType,
-                    runtimeTypeInfo: valueRuntimeType,
+                    typeInfo: valueTypeInfo,
                     refMode: trackValueRef ? .tracking : .none,
                     readTypeInfo: false
                 )
@@ -368,11 +346,10 @@ public enum FieldSkipper {
             }
 
             if valueNull {
-                let keyRuntimeType = keyDeclared ? nil : try context.typeResolver.readDynamicTypeInfo(context: context)
-                _ = try readValueWithRefMode(
-                    context: context,
+                let keyTypeInfo = keyDeclared ? nil : try self.readTypeInfo()
+                _ = try readSkippedValue(
                     fieldType: keyType,
-                    runtimeTypeInfo: keyRuntimeType,
+                    typeInfo: keyTypeInfo,
                     refMode: trackKeyRef ? .tracking : .none,
                     readTypeInfo: false
                 )
@@ -380,7 +357,7 @@ public enum FieldSkipper {
                 continue
             }
 
-            let chunkSize = Int(try context.buffer.readUInt8())
+            let chunkSize = Int(try buffer.readUInt8())
             if chunkSize <= 0 {
                 throw ForyError.invalidData("invalid map chunk size \(chunkSize)")
             }
@@ -388,21 +365,19 @@ public enum FieldSkipper {
                 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)
+            let keyTypeInfo = keyDeclared ? nil : try self.readTypeInfo()
+            let valueTypeInfo = valueDeclared ? nil : try self.readTypeInfo()
 
             for _ in 0..<chunkSize {
-                _ = try readValueWithRefMode(
-                    context: context,
+                _ = try readSkippedValue(
                     fieldType: keyType,
-                    runtimeTypeInfo: keyRuntimeType,
+                    typeInfo: keyTypeInfo,
                     refMode: trackKeyRef ? .tracking : .none,
                     readTypeInfo: false
                 )
-                _ = try readValueWithRefMode(
-                    context: context,
+                _ = try readSkippedValue(
                     fieldType: valueType,
-                    runtimeTypeInfo: valueRuntimeType,
+                    typeInfo: valueTypeInfo,
                     refMode: trackValueRef ? .tracking : .none,
                     readTypeInfo: false
                 )
@@ -413,8 +388,8 @@ public enum FieldSkipper {
         return [:]
     }
 
-    private static func readUnion(context: ReadContext) throws -> Any {
-        _ = try context.buffer.readVarUInt32()
-        return try context.readAny(refMode: .tracking, readTypeInfo: true) ?? ForyAnyNullValue()
+    private func readSkippedUnion() throws -> Any {
+        _ = try buffer.readVarUInt32()
+        return try readAny(refMode: .tracking, readTypeInfo: true) ?? ForyAnyNullValue()
     }
 }
diff --git a/swift/Sources/Fory/FlatMap.swift b/swift/Sources/Fory/FlatMap.swift
new file mode 100644
index 000000000..aa32c4566
--- /dev/null
+++ b/swift/Sources/Fory/FlatMap.swift
@@ -0,0 +1,273 @@
+// 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.
+
+private let uint64MapEmptyKey = UInt64.max
+private let uint64MapDefaultLoadFactor = 0.5
+private let uint64MapGoldenRatio: UInt64 = 0x9E3779B97F4A7C15
+
+/// Internal open-addressed UInt64-key map for runtime caches in Fory Swift
+/// (for example type metadata caches in resolver/read/write contexts).
+/// This is not part of the public API surface.
+final class UInt64Map<Value> {
+    private struct Slot {
+        var key: UInt64
+        var value: Value?
+    }
+
+    private var entries: UnsafeMutablePointer<Slot>
+    private var tableCapacity: Int
+    private var mask: Int
+    private var shift: Int
+    private var size = 0
+    private let loadFactor: Double
+    private var growThreshold: Int
+
+    private var hasMaxKey = false
+    private var maxKeyValue: Value?
+
+    init(initialCapacity: Int = 2, loadFactor: Double = uint64MapDefaultLoadFactor) {
+        self.loadFactor = loadFactor
+        let capacity = Self.nextPowerOfTwo(max(initialCapacity, 2))
+        tableCapacity = capacity
+        entries = UnsafeMutablePointer<Slot>.allocate(capacity: capacity)
+        entries.initialize(
+            repeating: Slot(key: uint64MapEmptyKey, value: nil),
+            count: capacity
+        )
+        mask = capacity - 1
+        shift = UInt64.bitWidth - UInt64(capacity).trailingZeroBitCount
+        growThreshold = Int(Double(capacity) * loadFactor)
+    }
+
+    deinit {
+        entries.deinitialize(count: tableCapacity)
+        entries.deallocate()
+    }
+
+    var count: Int {
+        size
+    }
+
+    var capacity: Int {
+        tableCapacity
+    }
+
+    var isEmpty: Bool {
+        size == 0
+    }
+
+    @inline(__always)
+    func value(for key: UInt64) -> Value? {
+        if key == uint64MapEmptyKey {
+            return hasMaxKey ? maxKeyValue : nil
+        }
+
+        var index = place(key)
+        while true {
+            let slot = entries[index]
+            if slot.key == key {
+                return slot.value
+            }
+            if slot.key == uint64MapEmptyKey {
+                return nil
+            }
+            index = (index + 1) & mask
+        }
+    }
+
+    @inline(__always)
+    func set(_ value: Value, for key: UInt64) {
+        if key == uint64MapEmptyKey {
+            if !hasMaxKey {
+                hasMaxKey = true
+                size += 1
+            }
+            maxKeyValue = value
+            return
+        }
+
+        if size >= growThreshold {
+            grow()
+        }
+
+        let index = findSlotForInsert(key)
+        if entries[index].key == uint64MapEmptyKey {
+            entries[index].key = key
+            size += 1
+        }
+        entries[index].value = value
+    }
+
+    @inline(__always)
+    func putIfAbsent(_ value: Value, for key: UInt64) -> (value: Value, inserted: Bool) {
+        if key == uint64MapEmptyKey {
+            if hasMaxKey, let maxKeyValue {
+                return (maxKeyValue, false)
+            }
+            hasMaxKey = true
+            maxKeyValue = value
+            size += 1
+            return (value, true)
+        }
+
+        if size >= growThreshold {
+            grow()
+        }
+
+        let index = findSlotForInsert(key)
+        if entries[index].key == uint64MapEmptyKey {
+            entries[index].key = key
+            entries[index].value = value
+            size += 1
+            return (value, true)
+        }
+
+        guard let existingValue = entries[index].value else {
+            fatalError("corrupted UInt64Map state: occupied slot has nil value")
+        }
+        return (existingValue, false)
+    }
+
+    @discardableResult
+    func removeValue(for key: UInt64) -> Value? {
+        if key == uint64MapEmptyKey {
+            guard hasMaxKey else {
+                return nil
+            }
+            hasMaxKey = false
+            size -= 1
+            let removed = maxKeyValue
+            maxKeyValue = nil
+            return removed
+        }
+
+        var index = place(key)
+        while true {
+            let slot = entries[index]
+            if slot.key == key {
+                let removed = slot.value
+                removeEntry(at: index)
+                return removed
+            }
+            if slot.key == uint64MapEmptyKey {
+                return nil
+            }
+            index = (index + 1) & mask
+        }
+    }
+
+    func clear() {
+        if !isEmpty {
+            for index in 0 ..< tableCapacity {
+                entries[index].key = uint64MapEmptyKey
+                entries[index].value = nil
+            }
+            hasMaxKey = false
+            maxKeyValue = nil
+            size = 0
+        }
+    }
+
+    @inline(__always)
+    private func findSlotForInsert(_ key: UInt64) -> Int {
+        var index = place(key)
+        while true {
+            let slotKey = entries[index].key
+            if slotKey == uint64MapEmptyKey || slotKey == key {
+                return index
+            }
+            index = (index + 1) & mask
+        }
+    }
+
+    @inline(__always)
+    private func place(_ key: UInt64) -> Int {
+        Int((key &* uint64MapGoldenRatio) >> shift)
+    }
+
+    private func grow() {
+        let oldEntries = entries
+        let oldCapacity = tableCapacity
+        let newCapacity = oldCapacity << 1
+        let newEntries = UnsafeMutablePointer<Slot>.allocate(capacity: newCapacity)
+        newEntries.initialize(
+            repeating: Slot(key: uint64MapEmptyKey, value: nil),
+            count: newCapacity
+        )
+
+        entries = newEntries
+        tableCapacity = newCapacity
+        mask = newCapacity - 1
+        shift = UInt64.bitWidth - UInt64(newCapacity).trailingZeroBitCount
+        growThreshold = Int(Double(newCapacity) * loadFactor)
+        size = hasMaxKey ? 1 : 0
+
+        for index in 0 ..< oldCapacity {
+            let oldSlot = oldEntries[index]
+            if oldSlot.key != uint64MapEmptyKey {
+                let newIndex = findSlotForInsert(oldSlot.key)
+                entries[newIndex] = oldSlot
+                size += 1
+            }
+        }
+
+        oldEntries.deinitialize(count: oldCapacity)
+        oldEntries.deallocate()
+    }
+
+    private func removeEntry(at index: Int) {
+        var hole = index
+        var cursor = (hole + 1) & mask
+
+        while entries[cursor].key != uint64MapEmptyKey {
+            let idealSlot = place(entries[cursor].key)
+            if shouldMoveEntry(idealSlot: idealSlot, candidateSlot: cursor, emptySlot: hole) {
+                entries[hole] = entries[cursor]
+                hole = cursor
+            }
+            cursor = (cursor + 1) & mask
+        }
+
+        entries[hole].key = uint64MapEmptyKey
+        entries[hole].value = nil
+        size -= 1
+    }
+
+    @inline(__always)
+    private func shouldMoveEntry(idealSlot: Int, candidateSlot: Int, emptySlot: Int) -> Bool {
+        if emptySlot <= candidateSlot {
+            return idealSlot <= emptySlot || idealSlot > candidateSlot
+        }
+        return idealSlot <= emptySlot && idealSlot > candidateSlot
+    }
+
+    private static func nextPowerOfTwo(_ value: Int) -> Int {
+        if value <= 1 {
+            return 1
+        }
+        var valueBits = UInt64(value - 1)
+        valueBits |= valueBits >> 1
+        valueBits |= valueBits >> 2
+        valueBits |= valueBits >> 4
+        valueBits |= valueBits >> 8
+        valueBits |= valueBits >> 16
+        if UInt64.bitWidth > 32 {
+            valueBits |= valueBits >> 32
+        }
+        return Int(valueBits + 1)
+    }
+}
diff --git a/swift/Sources/Fory/Fory.swift b/swift/Sources/Fory/Fory.swift
index 8d7e90f17..6f7a7b6b8 100644
--- a/swift/Sources/Fory/Fory.swift
+++ b/swift/Sources/Fory/Fory.swift
@@ -43,109 +43,39 @@ public struct ForyConfig {
         self.maxBinarySize = maxBinarySize
         self.maxDepth = maxDepth
     }
-}
-
-private final class ForyRuntimeContext {
-    let writeBuffer: ByteBuffer
-    let writeContext: WriteContext
-    let readBuffer: ByteBuffer
-    let readContext: ReadContext
-
-    var writeInUse = false
-    var readInUse = false
-
-    var lastReadDataAddress: UnsafeRawPointer?
-    var lastReadDataCount: Int = -1
-
-    init(typeResolver: TypeResolver, config: ForyConfig) {
-        writeBuffer = ByteBuffer()
-        writeContext = WriteContext(
-            buffer: writeBuffer,
-            typeResolver: typeResolver,
-            trackRef: config.trackRef,
-            compatible: config.compatible,
-            checkClassVersion: config.checkClassVersion,
-            maxDepth: config.maxDepth,
-            compatibleTypeDefState: CompatibleTypeDefWriteState(),
-            metaStringWriteState: MetaStringWriteState()
-        )
 
-        readBuffer = ByteBuffer()
-        readContext = ReadContext(
-            buffer: readBuffer,
-            typeResolver: typeResolver,
-            trackRef: config.trackRef,
-            compatible: config.compatible,
-            checkClassVersion: config.checkClassVersion,
-            maxCollectionSize: config.maxCollectionSize,
-            maxBinarySize: config.maxBinarySize,
-            maxDepth: config.maxDepth,
-            compatibleTypeDefState: CompatibleTypeDefReadState(),
-            metaStringReadState: MetaStringReadState()
+    static func resolved(
+        xlang: Bool = true,
+        trackRef: Bool = false,
+        compatible: Bool = false,
+        checkClassVersion: Bool? = nil,
+        maxCollectionSize: Int = 1_000_000,
+        maxBinarySize: Int = 64 * 1024 * 1024,
+        maxDepth: Int = 5
+    ) -> ForyConfig {
+        let effectiveCheckClassVersion = checkClassVersion ?? (xlang && !compatible)
+        return ForyConfig(
+            xlang: xlang,
+            trackRef: trackRef,
+            compatible: compatible,
+            checkClassVersion: effectiveCheckClassVersion,
+            maxCollectionSize: maxCollectionSize,
+            maxBinarySize: maxBinarySize,
+            maxDepth: maxDepth
         )
     }
 }
 
-private final class ForyThreadContextCache {
-    private var cachedID: UInt64 = .max
-    private var cachedContext: ForyRuntimeContext?
-    private var others: [UInt64: ForyRuntimeContext] = [:]
-
-    @inline(__always)
-    func getOrCreate(id: UInt64, create: () -> ForyRuntimeContext) -> ForyRuntimeContext {
-        if cachedID == id, let cachedContext {
-            return cachedContext
-        }
-
-        if let cachedContext {
-            others[cachedID] = cachedContext
-        }
-
-        let context = others.removeValue(forKey: id) ?? create()
-        cachedID = id
-        cachedContext = context
-        return context
-    }
-}
-
-private final class ForyThreadContextStore: @unchecked Sendable {
-    private let key: pthread_key_t
-
-    init() {
-        var localKey = pthread_key_t()
-        let createResult = pthread_key_create(&localKey) { rawPointer in
-            Unmanaged<ForyThreadContextCache>.fromOpaque(rawPointer).release()
-        }
-        precondition(createResult == 0, "failed to create pthread TLS key")
-        key = localKey
-    }
-
-    deinit {
-        pthread_key_delete(key)
-    }
-
-    @inline(__always)
-    func get() -> ForyThreadContextCache {
-        if let rawPointer = pthread_getspecific(key) {
-            return Unmanaged<ForyThreadContextCache>.fromOpaque(rawPointer).takeUnretainedValue()
-        }
-
-        let cache = ForyThreadContextCache()
-        let setResult = pthread_setspecific(key, Unmanaged.passRetained(cache).toOpaque())
-        precondition(setResult == 0, "failed to set pthread TLS value")
-        return cache
-    }
-}
-
+/// Single-threaded Fory runtime.
+///
+/// Reuse one `Fory` per thread for the fastest path. The runtime keeps one
+/// reusable read/write context pair and must not be used concurrently from
+/// multiple threads.
 public final class Fory {
     public let config: ForyConfig
-    public let typeResolver: TypeResolver
-
-    private let instanceID: UInt64
-
-    private static let threadContextStore = ForyThreadContextStore()
-    private static let instanceIDLock = NSLock()
-    nonisolated(unsafe) private static var nextInstanceID: UInt64 = 0
+    let typeResolver: TypeResolver
+    private let writeContext: WriteContext
+    private let readContext: ReadContext
 
     public init(
         xlang: Bool = true,
@@ -156,18 +86,35 @@ public final class Fory {
         maxBinarySize: Int = 64 * 1024 * 1024,
         maxDepth: Int = 5
     ) {
-        let effectiveCheckClassVersion = checkClassVersion ?? (xlang && !compatible)
-        self.config = ForyConfig(
+        self.config = ForyConfig.resolved(
             xlang: xlang,
             trackRef: trackRef,
             compatible: compatible,
-            checkClassVersion: effectiveCheckClassVersion,
+            checkClassVersion: checkClassVersion,
             maxCollectionSize: maxCollectionSize,
             maxBinarySize: maxBinarySize,
             maxDepth: maxDepth
         )
-        self.typeResolver = TypeResolver()
-        self.instanceID = Self.allocateInstanceID()
+        self.typeResolver = TypeResolver(trackRef: self.config.trackRef)
+        self.writeContext = WriteContext(
+            buffer: ByteBuffer(),
+            typeResolver: typeResolver,
+            trackRef: self.config.trackRef,
+            compatible: self.config.compatible,
+            checkClassVersion: self.config.checkClassVersion,
+            maxDepth: self.config.maxDepth,
+            metaStringWriteState: MetaStringWriteState()
+        )
+        self.readContext = ReadContext(
+            buffer: ByteBuffer(),
+            typeResolver: typeResolver,
+            trackRef: self.config.trackRef,
+            compatible: self.config.compatible,
+            checkClassVersion: self.config.checkClassVersion,
+            maxCollectionSize: self.config.maxCollectionSize,
+            maxBinarySize: self.config.maxBinarySize,
+            maxDepth: self.config.maxDepth
+        )
     }
 
     public convenience init(config: ForyConfig) {
@@ -195,35 +142,44 @@ public final class Fory {
     }
 
     public func serialize<T: Serializer>(_ value: T) throws -> Data {
-        try serializeRoot(isNone: value.foryIsNone) { context in
-            if useRootDataFastPath {
-                try value.foryWriteData(context, hasGenerics: false)
-            } else {
-                try value.foryWrite(context, refMode: rootRefMode, writeTypeInfo: shouldWriteRootTypeInfo, hasGenerics: false)
-            }
+        let context = writeContext
+        context.buffer.clear()
+        defer {
+            context.reset()
+        }
+
+        writeHead(buffer: context.buffer, isNone: value.foryIsNone)
+        if !value.foryIsNone {
+            try writeRootTypedValue(value, context: context)
         }
+        return context.buffer.copyToData()
     }
 
     public func deserialize<T: Serializer>(_ data: Data, as _: T.Type = T.self) throws -> T {
-        try deserializeRoot(
-            data: data,
-            nilValue: T.foryDefault()
-        ) { context in
-            if useRootDataFastPath {
-                return try T.foryReadData(context)
+        try withReusableReadContext(data: data) { context in
+            if try readHead(buffer: context.buffer) {
+                return T.foryDefault()
             }
-            return try T.foryRead(context, refMode: rootRefMode, readTypeInfo: shouldWriteRootTypeInfo)
+            let value: T = try readRootTypedValue(context: context)
+            if context.buffer.remaining != 0 {
+                throw ForyError.invalidData("unexpected trailing bytes at root: \(context.buffer.remaining)")
+            }
+            return value
         }
     }
 
     public func serialize<T: Serializer>(_ value: T, to buffer: inout Data) throws {
-        try appendSerializedRoot(to: &buffer, isNone: value.foryIsNone) { context in
-            if useRootDataFastPath {
-                try value.foryWriteData(context, hasGenerics: false)
-            } else {
-                try value.foryWrite(context, refMode: rootRefMode, writeTypeInfo: shouldWriteRootTypeInfo, hasGenerics: false)
-            }
+        let context = writeContext
+        context.buffer.clear()
+        defer {
+            context.reset()
+        }
+
+        writeHead(buffer: context.buffer, isNone: value.foryIsNone)
+        if !value.foryIsNone {
+            try writeRootTypedValue(value, context: context)
         }
+        buffer.append(contentsOf: context.buffer.storage.prefix(context.buffer.count))
     }
 
     public func deserialize<T: Serializer>(from buffer: ByteBuffer, as _: T.Type = T.self) throws -> T {
@@ -231,10 +187,7 @@ public final class Fory {
             from: buffer,
             nilValue: T.foryDefault()
         ) { context in
-            if useRootDataFastPath {
-                return try T.foryReadData(context)
-            }
-            return try T.foryRead(context, refMode: rootRefMode, readTypeInfo: shouldWriteRootTypeInfo)
+            try readRootTypedValue(context: context)
         }
     }
 
@@ -497,7 +450,9 @@ public final class Fory {
         }
     }
 
-    public func writeHead(buffer: ByteBuffer, isNone: Bool) {
+    @inlinable
+    @inline(__always)
+    func writeHead(buffer: ByteBuffer, isNone: Bool) {
         var bitmap: UInt8 = 0
         if config.xlang {
             bitmap |= ForyHeaderFlag.isXlang
@@ -508,7 +463,9 @@ public final class Fory {
         buffer.writeUInt8(bitmap)
     }
 
-    public func readHead(buffer: ByteBuffer) throws -> Bool {
+    @inlinable
+    @inline(__always)
+    func readHead(buffer: ByteBuffer) throws -> Bool {
         let bitmap = try buffer.readUInt8()
         let peerIsXlang = (bitmap & ForyHeaderFlag.isXlang) != 0
         if peerIsXlang != config.xlang {
@@ -517,137 +474,46 @@ public final class Fory {
         return (bitmap & ForyHeaderFlag.isNull) != 0
     }
 
-    private static func allocateInstanceID() -> UInt64 {
-        instanceIDLock.lock()
-        defer { instanceIDLock.unlock() }
-        let id = nextInstanceID
-        nextInstanceID &+= 1
-        return id
-    }
-
     @inline(__always)
     private var refMode: RefMode {
         config.trackRef ? .tracking : .nullOnly
     }
 
-    @inline(__always)
-    private var shouldWriteRootTypeInfo: Bool {
-        config.xlang || config.compatible
-    }
-
-    @inline(__always)
-    private var rootRefMode: RefMode {
-        if config.trackRef {
-            return .tracking
-        }
-        return shouldWriteRootTypeInfo ? .nullOnly : .none
-    }
-
-    @inline(__always)
-    private var useRootDataFastPath: Bool {
-        !shouldWriteRootTypeInfo && rootRefMode == .none
-    }
-
-    @inline(__always)
-    private func makeWriteContext(buffer: ByteBuffer) -> WriteContext {
-        WriteContext(
-            buffer: buffer,
-            typeResolver: typeResolver,
-            trackRef: config.trackRef,
-            compatible: config.compatible,
-            checkClassVersion: config.checkClassVersion,
-            maxDepth: config.maxDepth,
-            compatibleTypeDefState: CompatibleTypeDefWriteState(),
-            metaStringWriteState: MetaStringWriteState()
+    private func writeRootTypedValue<T: Serializer>(
+        _ value: T,
+        context: WriteContext
+    ) throws {
+        let writeTypeInfo = config.xlang || config.compatible
+        try value.foryWrite(
+            context,
+            refMode: config.trackRef ? .tracking : (writeTypeInfo ? .nullOnly : .none),
+            writeTypeInfo: writeTypeInfo,
+            hasGenerics: false
         )
     }
 
     @inline(__always)
-    private func makeReadContext(buffer: ByteBuffer) -> ReadContext {
-        ReadContext(
-            buffer: buffer,
-            typeResolver: typeResolver,
-            trackRef: config.trackRef,
-            compatible: config.compatible,
-            checkClassVersion: config.checkClassVersion,
-            maxCollectionSize: config.maxCollectionSize,
-            maxBinarySize: config.maxBinarySize,
-            maxDepth: config.maxDepth,
-            compatibleTypeDefState: CompatibleTypeDefReadState(),
-            metaStringReadState: MetaStringReadState()
+    private func readRootTypedValue<T: Serializer>(
+        context: ReadContext
+    ) throws -> T {
+        let readTypeInfo = config.xlang || config.compatible
+        return try T.foryRead(
+            context,
+            refMode: config.trackRef ? .tracking : (readTypeInfo ? .nullOnly : .none),
+            readTypeInfo: readTypeInfo
         )
     }
 
     @inline(__always)
-    private func runtimeContext() -> ForyRuntimeContext {
-        let cache = threadContextCache()
-        return cache.getOrCreate(id: instanceID) {
-            ForyRuntimeContext(typeResolver: typeResolver, config: config)
-        }
-    }
-
-    @inline(__always)
-    private func threadContextCache() -> ForyThreadContextCache {
-        Self.threadContextStore.get()
-    }
-
-    @inline(__always)
-    private func withReusableWriteContext<R>(
-        _ body: (WriteContext) throws -> R
-    ) rethrows -> R {
-        let runtimeContext = runtimeContext()
-
-        if runtimeContext.writeInUse {
-            let temporaryBuffer = ByteBuffer()
-            let temporaryContext = makeWriteContext(buffer: temporaryBuffer)
-            defer { temporaryContext.reset() }
-            return try body(temporaryContext)
-        }
-
-        runtimeContext.writeInUse = true
-        runtimeContext.writeBuffer.clear()
-        defer {
-            runtimeContext.writeContext.reset()
-            runtimeContext.writeInUse = false
-        }
-        return try body(runtimeContext.writeContext)
-    }
-
-    @inline(__always)
-    private func withReusableReadContext<R>(
+    func withReusableReadContext<R>(
         data: Data,
         _ body: (ReadContext) throws -> R
     ) rethrows -> R {
-        let runtimeContext = runtimeContext()
-
-        if runtimeContext.readInUse {
-            let temporaryBuffer = ByteBuffer(data: data)
-            let temporaryContext = makeReadContext(buffer: temporaryBuffer)
-            defer { temporaryContext.reset() }
-            return try body(temporaryContext)
-        }
-
-        runtimeContext.readInUse = true
-        runtimeContext.readBuffer.replace(with: data)
-        data.withUnsafeBytes { rawBytes in
-            runtimeContext.lastReadDataAddress = rawBytes.baseAddress
-            runtimeContext.lastReadDataCount = rawBytes.count
-        }
+        readContext.buffer.replace(with: data)
         defer {
-            runtimeContext.readContext.reset()
-            runtimeContext.readInUse = false
+            readContext.reset()
         }
-        return try body(runtimeContext.readContext)
-    }
-
-    @inline(__always)
-    private func withTemporaryReadContext<R>(
-        buffer: ByteBuffer,
-        _ body: (ReadContext) throws -> R
-    ) rethrows -> R {
-        let context = makeReadContext(buffer: buffer)
-        defer { context.reset() }
-        return try body(context)
+        return try body(readContext)
     }
 
     @inline(__always)
@@ -655,13 +521,16 @@ public final class Fory {
         isNone: Bool,
         _ body: (WriteContext) throws -> Void
     ) throws -> Data {
-        try withReusableWriteContext { context in
-            writeHead(buffer: context.buffer, isNone: isNone)
-            if !isNone {
-                try body(context)
-            }
-            return context.buffer.toData()
+        let context = writeContext
+        context.buffer.clear()
+        defer {
+            context.reset()
         }
+        writeHead(buffer: context.buffer, isNone: isNone)
+        if !isNone {
+            try body(context)
+        }
+        return context.buffer.copyToData()
     }
 
     @inline(__always)
@@ -670,13 +539,16 @@ public final class Fory {
         isNone: Bool,
         _ body: (WriteContext) throws -> Void
     ) throws {
-        try withReusableWriteContext { context in
-            writeHead(buffer: context.buffer, isNone: isNone)
-            if !isNone {
-                try body(context)
-            }
-            output.append(contentsOf: context.buffer.storage)
+        let context = writeContext
+        context.buffer.clear()
+        defer {
+            context.reset()
+        }
+        writeHead(buffer: context.buffer, isNone: isNone)
+        if !isNone {
+            try body(context)
         }
+        output.append(contentsOf: context.buffer.storage.prefix(context.buffer.count))
     }
 
     @inline(__always)
@@ -703,11 +575,14 @@ public final class Fory {
         nilValue: @autoclosure () -> R,
         _ body: (ReadContext) throws -> R
     ) throws -> R {
-        try withTemporaryReadContext(buffer: buffer) { context in
-            if try readHead(buffer: buffer) {
-                return nilValue()
-            }
-            return try body(context)
+        readContext.buffer.swapState(with: buffer)
+        defer {
+            readContext.buffer.swapState(with: buffer)
+            readContext.reset()
+        }
+        if try readHead(buffer: readContext.buffer) {
+            return nilValue()
         }
+        return try body(readContext)
     }
 }
diff --git a/swift/Sources/Fory/MacroDeclarations.swift b/swift/Sources/Fory/MacroDeclarations.swift
index 5a705bc3a..19b979cb9 100644
--- a/swift/Sources/Fory/MacroDeclarations.swift
+++ b/swift/Sources/Fory/MacroDeclarations.swift
@@ -18,18 +18,21 @@
 @attached(
     member,
     names: named(staticTypeId),
-    named(isReferenceTrackableType),
+    named(isRefType),
     named(__forySchemaHash),
     named(__forySchemaHashTrackRefDisabled),
     named(__forySchemaHashTrackRefEnabled),
-    named(foryCompatibleTypeMetaFields),
-    named(__foryCompatibleTypeMetaFieldsTrackRefDisabled),
-    named(__foryCompatibleTypeMetaFieldsTrackRefEnabled),
+    named(foryFieldsInfo),
+    named(__foryFieldsInfoTrackRefDisabled),
+    named(__foryFieldsInfoTrackRefEnabled),
     named(foryDefault),
     named(foryWrite),
     named(foryRead),
     named(foryWriteData),
-    named(foryReadData)
+    named(foryReadData),
+    named(foryReadCompatibleData),
+    named(__foryReadDataImpl),
+    named(__foryReadCompatibleDataImpl)
 )
 @attached(extension, conformances: Serializer)
 public macro ForyObject() = #externalMacro(module: "ForyMacro", type: "ForyObjectMacro")
diff --git a/swift/Sources/Fory/MetaString.swift b/swift/Sources/Fory/MetaString.swift
index 72dabec5e..3a1b61361 100644
--- a/swift/Sources/Fory/MetaString.swift
+++ b/swift/Sources/Fory/MetaString.swift
@@ -27,7 +27,7 @@ public enum MetaStringEncoding: UInt8, CaseIterable, Sendable {
     case allToLowerSpecial = 4
 }
 
-public struct MetaString: Equatable, Hashable, Sendable {
+public final class MetaString: Equatable, Hashable, @unchecked Sendable {
     public let value: String
     public let encoding: MetaStringEncoding
     public let specialChar1: Character
@@ -68,6 +68,24 @@ public struct MetaString: Equatable, Hashable, Sendable {
         }
         return emptyMetaString
     }
+
+    public static func == (lhs: MetaString, rhs: MetaString) -> Bool {
+        lhs.value == rhs.value &&
+            lhs.encoding == rhs.encoding &&
+            lhs.specialChar1 == rhs.specialChar1 &&
+            lhs.specialChar2 == rhs.specialChar2 &&
+            lhs.bytes == rhs.bytes &&
+            lhs.stripLastChar == rhs.stripLastChar
+    }
+
+    public func hash(into hasher: inout Hasher) {
+        hasher.combine(value)
+        hasher.combine(encoding)
+        hasher.combine(specialChar1)
+        hasher.combine(specialChar2)
+        hasher.combine(bytes)
+        hasher.combine(stripLastChar)
+    }
 }
 
 public struct MetaStringEncoder: Sendable {
@@ -447,3 +465,121 @@ public struct MetaStringDecoder: Sendable {
         return out
     }
 }
+
+@inline(__always)
+func writeMetaString(
+    context: WriteContext,
+    value: MetaString,
+    encodings: [MetaStringEncoding],
+    encoder: MetaStringEncoder
+) throws {
+    let normalized: MetaString
+    if encodings.contains(value.encoding) {
+        normalized = value
+    } else {
+        normalized = try encoder.encode(value.value, allowedEncodings: encodings)
+    }
+
+    guard encodings.contains(normalized.encoding) else {
+        throw ForyError.encodingError("failed to normalize meta string encoding")
+    }
+
+    context.markMetaStringWriteStateUsed()
+    let bytes = normalized.bytes
+    let assignment = context.metaStringWriteState.assignIndexIfAbsent(for: normalized)
+    if assignment.isNew {
+        context.buffer.writeVarUInt32(UInt32(bytes.count) << 1)
+        if bytes.count > 16 {
+            context.buffer.writeInt64(Int64(bitPattern: metaStringHash(normalized)))
+        } else if !bytes.isEmpty {
+            context.buffer.writeUInt8(normalized.encoding.rawValue)
+        }
+        context.buffer.writeBytes(bytes)
+    } else {
+        context.buffer.writeVarUInt32(((assignment.index + 1) << 1) | 1)
+    }
+}
+
+@inline(__always)
+func readMetaString(
+    context: ReadContext,
+    decoder: MetaStringDecoder,
+    encodings: [MetaStringEncoding]
+) throws -> MetaString {
+    let header = try context.buffer.readVarUInt32()
+    let length = Int(header >> 1)
+    let isRef = (header & 1) == 1
+    if isRef {
+        let index = length - 1
+        guard let cached = context.getReadMetaString(at: index) else {
+            throw ForyError.invalidData("unknown meta string ref index \(index)")
+        }
+        return cached
+    }
+
+    let value: MetaString
+    if length == 0 {
+        value = MetaString.empty(
+            specialChar1: decoder.specialChar1,
+            specialChar2: decoder.specialChar2
+        )
+    } else {
+        let encoding: MetaStringEncoding
+        if length > 16 {
+            let hash = try context.buffer.readInt64()
+            let rawEncoding = UInt8(truncatingIfNeeded: hash & 0xFF)
+            guard let resolved = MetaStringEncoding(rawValue: rawEncoding) else {
+                throw ForyError.invalidData("invalid meta string encoding \(rawEncoding)")
+            }
+            encoding = resolved
+        } else {
+            let rawEncoding = try context.buffer.readUInt8()
+            guard let resolved = MetaStringEncoding(rawValue: rawEncoding) else {
+                throw ForyError.invalidData("invalid meta string encoding \(rawEncoding)")
+            }
+            encoding = resolved
+        }
+        guard encodings.contains(encoding) else {
+            throw ForyError.invalidData("meta string encoding \(encoding) not allowed in this context")
+        }
+        let bytes = try context.buffer.readBytes(count: length)
+        value = try decoder.decode(bytes: bytes, encoding: encoding)
+    }
+    context.appendReadMetaString(value)
+    return value
+}
+
+@inline(__always)
+func readMetaString(
+    buffer: ByteBuffer,
+    decoder: MetaStringDecoder,
+    encodings: [MetaStringEncoding]
+) throws -> MetaString {
+    let header = try buffer.readUInt8()
+    let encodingIndex = Int(header & 0b11)
+    guard encodingIndex < encodings.count else {
+        throw ForyError.invalidData("invalid meta string encoding index")
+    }
+
+    var length = Int(header >> 2)
+    if length >= 0b11_1111 {
+        length = 0b11_1111 + Int(try buffer.readVarUInt32())
+    }
+    let bytes = try buffer.readBytes(count: length)
+    return try decoder.decode(bytes: bytes, encoding: encodings[encodingIndex])
+}
+
+@inline(__always)
+func metaStringHash(_ metaString: MetaString) -> UInt64 {
+    var hash = Int64(bitPattern: MurmurHash3.x64_128(metaString.bytes, seed: 47).0)
+    if hash != Int64.min {
+        hash = Swift.abs(hash)
+    }
+    var result = UInt64(bitPattern: hash)
+    if result == 0 {
+        result &+= 256
+    }
+    result &= 0xffffffffffffff00
+    result |= UInt64(metaString.encoding.rawValue & 0xFF)
+    return result
+}
diff --git a/swift/Sources/Fory/OptionalSerializer.swift b/swift/Sources/Fory/OptionalSerializer.swift
index 70f38bcf7..9a504da84 100644
--- a/swift/Sources/Fory/OptionalSerializer.swift
+++ b/swift/Sources/Fory/OptionalSerializer.swift
@@ -30,8 +30,8 @@ extension Optional: Serializer where Wrapped: Serializer {
         true
     }
 
-    public static var isReferenceTrackableType: Bool {
-        Wrapped.isReferenceTrackableType
+    public static var isRefType: Bool {
+        Wrapped.isRefType
     }
 
     public var foryIsNone: Bool {
@@ -49,11 +49,11 @@ extension Optional: Serializer where Wrapped: Serializer {
         .some(try Wrapped.foryReadData(context))
     }
 
-    public static func foryWriteTypeInfo(_ context: WriteContext) throws {
-        try Wrapped.foryWriteTypeInfo(context)
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        try Wrapped.foryWriteStaticTypeInfo(context)
     }
 
-    public static func foryReadTypeInfo(_ context: ReadContext) throws {
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
         try Wrapped.foryReadTypeInfo(context)
     }
 
@@ -90,22 +90,35 @@ extension Optional: Serializer where Wrapped: Serializer {
         refMode: RefMode,
         readTypeInfo: Bool
     ) throws -> Wrapped? {
+        let typeInfo = readTypeInfo ? nil : context.getTypeInfo(for: Self.self)
         switch refMode {
         case .none:
-            return .some(try Wrapped.foryRead(context, refMode: .none, readTypeInfo: readTypeInfo))
+            return .some(
+                try context.withTypeInfo(typeInfo, for: Wrapped.self) {
+                    try Wrapped.foryRead(context, refMode: .none, readTypeInfo: readTypeInfo)
+                }
+            )
         case .nullOnly:
             let refFlag = try context.buffer.readInt8()
             if refFlag == RefFlag.null.rawValue {
                 return nil
             }
-            return .some(try Wrapped.foryRead(context, refMode: .none, readTypeInfo: readTypeInfo))
+            return .some(
+                try context.withTypeInfo(typeInfo, for: Wrapped.self) {
+                    try Wrapped.foryRead(context, refMode: .none, readTypeInfo: readTypeInfo)
+                }
+            )
         case .tracking:
             let refFlag = try context.buffer.readInt8()
             if refFlag == RefFlag.null.rawValue {
                 return nil
             }
             context.buffer.moveBack(1)
-            return .some(try Wrapped.foryRead(context, refMode: .tracking, readTypeInfo: readTypeInfo))
+            return .some(
+                try context.withTypeInfo(typeInfo, for: Wrapped.self) {
+                    try Wrapped.foryRead(context, refMode: .tracking, readTypeInfo: readTypeInfo)
+                }
+            )
         }
     }
 }
diff --git a/swift/Sources/Fory/PrimitiveSerializers.swift b/swift/Sources/Fory/PrimitiveSerializers.swift
index 3a6ef3fb4..162d340fd 100644
--- a/swift/Sources/Fory/PrimitiveSerializers.swift
+++ b/swift/Sources/Fory/PrimitiveSerializers.swift
@@ -22,6 +22,14 @@ extension Bool: Serializer {
 
     public static func foryDefault() -> Bool { false }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeUInt8(self ? 1 : 0)
     }
@@ -36,6 +44,14 @@ extension Int8: Serializer {
 
     public static func foryDefault() -> Int8 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeInt8(self)
     }
@@ -50,6 +66,14 @@ extension Int16: Serializer {
 
     public static func foryDefault() -> Int16 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeInt16(self)
     }
@@ -64,6 +88,14 @@ extension Int32: Serializer {
 
     public static func foryDefault() -> Int32 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeVarInt32(self)
     }
@@ -78,6 +110,14 @@ extension Int64: Serializer {
 
     public static func foryDefault() -> Int64 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeVarInt64(self)
     }
@@ -92,6 +132,14 @@ extension UInt8: Serializer {
 
     public static func foryDefault() -> UInt8 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeUInt8(self)
     }
@@ -106,6 +154,14 @@ extension UInt16: Serializer {
 
     public static func foryDefault() -> UInt16 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeUInt16(self)
     }
@@ -120,6 +176,14 @@ extension UInt32: Serializer {
 
     public static func foryDefault() -> UInt32 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeVarUInt32(self)
     }
@@ -134,6 +198,14 @@ extension UInt64: Serializer {
 
     public static func foryDefault() -> UInt64 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeVarUInt64(self)
     }
@@ -152,6 +224,14 @@ public struct ForyInt32Fixed: Serializer, Equatable {
     public static func foryDefault() -> ForyInt32Fixed { .init() }
     public static var staticTypeId: TypeId { .int32 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeInt32(rawValue)
@@ -171,6 +251,14 @@ public struct ForyInt64Fixed: Serializer, Equatable {
     public static func foryDefault() -> ForyInt64Fixed { .init() }
     public static var staticTypeId: TypeId { .int64 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeInt64(rawValue)
@@ -190,6 +278,14 @@ public struct ForyInt64Tagged: Serializer, Equatable {
     public static func foryDefault() -> ForyInt64Tagged { .init() }
     public static var staticTypeId: TypeId { .taggedInt64 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeTaggedInt64(rawValue)
@@ -209,6 +305,14 @@ public struct ForyUInt32Fixed: Serializer, Equatable {
     public static func foryDefault() -> ForyUInt32Fixed { .init() }
     public static var staticTypeId: TypeId { .uint32 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeUInt32(rawValue)
@@ -228,6 +332,14 @@ public struct ForyUInt64Fixed: Serializer, Equatable {
     public static func foryDefault() -> ForyUInt64Fixed { .init() }
     public static var staticTypeId: TypeId { .uint64 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeUInt64(rawValue)
@@ -247,6 +359,14 @@ public struct ForyUInt64Tagged: Serializer, Equatable {
     public static func foryDefault() -> ForyUInt64Tagged { .init() }
     public static var staticTypeId: TypeId { .taggedUInt64 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeTaggedUInt64(rawValue)
@@ -263,6 +383,14 @@ extension Int: Serializer {
 
     public static func foryDefault() -> Int { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeVarInt64(Int64(self))
     }
@@ -277,6 +405,14 @@ extension UInt: Serializer {
 
     public static func foryDefault() -> UInt { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeVarUInt64(UInt64(self))
     }
@@ -292,6 +428,14 @@ extension Float: Serializer {
 
     public static func foryDefault() -> Float { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeFloat32(self)
     }
@@ -306,6 +450,14 @@ extension Double: Serializer {
 
     public static func foryDefault() -> Double { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         context.buffer.writeFloat64(self)
     }
@@ -325,6 +477,14 @@ public struct BFloat16: Serializer, Equatable, Hashable, Sendable {
     public static func foryDefault() -> BFloat16 { .init() }
     public static var staticTypeId: TypeId { .bfloat16 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeUInt16(rawValue)
@@ -340,6 +500,14 @@ extension Float16: Serializer {
 
     public static func foryDefault() -> Float16 { 0 }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         _ = hasGenerics
         context.buffer.writeUInt16(bitPattern)
@@ -370,9 +538,28 @@ extension String: Serializer {
 
     public static func foryDefault() -> String { "" }
 
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try readBuiltinTypeInfo(context, staticTypeId)
+    }
+
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
         let utf8Bytes = self.utf8
         let header = (UInt64(utf8Bytes.count) << 2) | StringEncoding.utf8.rawValue
+        if utf8Bytes.withContiguousStorageIfAvailable({ contiguousBytes in
+            let totalBytes = UnsafeUtil.varUInt64Size(header) + contiguousBytes.count
+            UnsafeUtil.writeRegion(buffer: context.buffer, exactCount: totalBytes) { base in
+                var index = UnsafeUtil.writeVarUInt64(header, to: base, index: 0)
+                index = UnsafeUtil.copyBytes(contiguousBytes, to: base, index: index)
+                assert(index == totalBytes)
+            }
+            return true
+        }) != nil {
+            return
+        }
         context.buffer.writeVarUInt36Small(header)
         context.buffer.writeBytes(utf8Bytes)
     }
@@ -414,7 +601,11 @@ extension Data: Serializer {
 
     public static func foryDefault() -> Data { Data() }
 
-    public static func foryReadTypeInfo(_ context: ReadContext) throws {
+    public static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
+        writeBuiltinTypeInfo(context, staticTypeId)
+    }
+
+    public static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
         let rawTypeID = try context.buffer.readVarUInt32()
         guard let typeID = TypeId(rawValue: rawTypeID) else {
             throw ForyError.invalidData("unknown type id \(rawTypeID)")
@@ -422,6 +613,7 @@ extension Data: Serializer {
         if typeID != .binary && typeID != .uint8Array {
             throw ForyError.typeMismatch(expected: TypeId.binary.rawValue, actual: rawTypeID)
         }
+        return nil
     }
 
     public func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
diff --git a/swift/Sources/Fory/ReadContext.swift b/swift/Sources/Fory/ReadContext.swift
new file mode 100644
index 000000000..dd6188678
--- /dev/null
+++ b/swift/Sources/Fory/ReadContext.swift
@@ -0,0 +1,633 @@
+// 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.
+
+import Foundation
+
+private let typeMetaSizeMask = 0xFF
+
+public final class ReadContext {
+    public let buffer: ByteBuffer
+    let typeResolver: TypeResolver
+    public let trackRef: Bool
+    public let compatible: Bool
+    public let checkClassVersion: Bool
+    public let maxCollectionSize: Int
+    public let maxBinarySize: Int
+    public let maxDepth: Int
+    public let refReader: RefReader
+    private let compatibleTypeDefTypeInfos = ReusableArray<TypeInfo?>(defaultValue: nil, reserve: 2)
+    private let metaStrings = ReusableArray<MetaString?>(defaultValue: nil, reserve: 16)
+    private var dynamicAnyDepth = 0
+
+    private var typeInfoStack = UInt64Map<TypeInfo>(initialCapacity: 8)
+    private var typeInfoScopeStack: [(typeKey: UInt64, previousTypeInfo: TypeInfo?)] = []
+    private var lastTypeInfo = TypeInfo.uncached
+
+    init(
+        buffer: ByteBuffer,
+        typeResolver: TypeResolver,
+        trackRef: Bool,
+        compatible: Bool = false,
+        checkClassVersion: Bool = true,
+        maxCollectionSize: Int = 1_000_000,
+        maxBinarySize: Int = 64 * 1024 * 1024,
+        maxDepth: Int = 5
+    ) {
+        self.buffer = buffer
+        self.typeResolver = typeResolver
+        self.trackRef = trackRef
+        self.compatible = compatible
+        self.checkClassVersion = checkClassVersion
+        self.maxCollectionSize = maxCollectionSize
+        self.maxBinarySize = maxBinarySize
+        self.maxDepth = maxDepth
+        self.refReader = RefReader()
+    }
+
+    @inline(__always)
+    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)
+    func leaveDynamicAnyDepth() {
+        if dynamicAnyDepth > 0 {
+            dynamicAnyDepth -= 1
+        }
+    }
+
+    @inline(__always)
+    func ensureCollectionLength(_ length: Int, label: String) throws {
+        if length < 0 {
+            throw ForyError.invalidData("\(label) length is negative")
+        }
+        if length > maxCollectionSize {
+            throw ForyError.invalidData(
+                "\(label) length \(length) exceeds configured maxCollectionSize \(maxCollectionSize)"
+            )
+        }
+    }
+
+    @inline(__always)
+    func ensureBinaryLength(_ length: Int, label: String) throws {
+        if length < 0 {
+            throw ForyError.invalidData("\(label) size is negative")
+        }
+        if length > maxBinarySize {
+            throw ForyError.invalidData(
+                "\(label) size \(length) exceeds configured maxBinarySize \(maxBinarySize)"
+            )
+        }
+    }
+
+    @inline(__always)
+    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"
+            )
+        }
+    }
+
+    @inline(__always)
+    func typeInfo<T: Serializer>(for type: T.Type) throws -> TypeInfo {
+        let typeID = ObjectIdentifier(type)
+        if lastTypeInfo.swiftTypeID == typeID {
+            return lastTypeInfo
+        }
+        let info = try typeResolver.requireTypeInfo(for: type)
+        lastTypeInfo = info
+        return info
+    }
+
+    @inline(__always)
+    func readStaticTypeInfo(_ typeID: TypeId) throws -> TypeInfo? {
+        let rawTypeID = UInt32(try buffer.readUInt8())
+        guard let actualTypeID = TypeId(rawValue: rawTypeID) else {
+            throw ForyError.invalidData("unknown type id \(rawTypeID)")
+        }
+        if actualTypeID != typeID {
+            throw ForyError.typeMismatch(expected: typeID.rawValue, actual: rawTypeID)
+        }
+        return nil
+    }
+
+    func readTypeInfo() throws -> TypeInfo {
+        let rawTypeID = UInt32(try buffer.readUInt8())
+        guard let wireTypeID = TypeId(rawValue: rawTypeID) else {
+            throw ForyError.invalidData("unknown dynamic type id \(rawTypeID)")
+        }
+
+        switch wireTypeID {
+        case .compatibleStruct, .namedCompatibleStruct:
+            return try readCompatibleTypeInfo()
+        case .namedStruct, .namedEnum, .namedExt, .namedUnion:
+            if compatible {
+                return try readCompatibleTypeInfo()
+            }
+            let namespace = try readMetaString(
+                context: self,
+                decoder: .namespace,
+                encodings: namespaceMetaStringEncodings
+            )
+            let typeName = try readMetaString(
+                context: self,
+                decoder: .typeName,
+                encodings: typeNameMetaStringEncodings
+            )
+            return try typeResolver.requireTypeInfo(namespace: namespace.value, typeName: typeName.value)
+        case .structType, .enumType, .ext, .typedUnion, .union:
+            let userTypeID = try buffer.readVarUInt32()
+            return try typeResolver.requireTypeInfo(userTypeID: userTypeID)
+        default:
+            return typeResolver.builtinTypeInfo(for: wireTypeID)
+        }
+    }
+
+    func readTypeInfo<T: Serializer>(for type: T.Type) throws -> TypeInfo? {
+        let rawTypeID = UInt32(try buffer.readUInt8())
+        guard let typeID = TypeId(rawValue: rawTypeID) else {
+            throw ForyError.invalidData("unknown type id \(rawTypeID)")
+        }
+
+        guard T.staticTypeId.isUserTypeKind else {
+            if typeID != T.staticTypeId {
+                throw ForyError.typeMismatch(expected: T.staticTypeId.rawValue, actual: rawTypeID)
+            }
+            return nil
+        }
+
+        let localTypeInfo = try typeInfo(for: type)
+        let expectedWireTypeID = localTypeInfo.wireTypeID(compatible: compatible)
+        if !isAllowedRegisteredWireTypeID(
+            typeID,
+            declaredTypeID: localTypeInfo.typeID,
+            registerByName: localTypeInfo.registerByName,
+            compatible: compatible
+        ) {
+            throw ForyError.typeMismatch(expected: expectedWireTypeID.rawValue, actual: rawTypeID)
+        }
+
+        switch typeID {
+        case .compatibleStruct, .namedCompatibleStruct:
+            return try readCompatibleTypeInfoIfNeeded(
+                for: localTypeInfo,
+                wireTypeID: typeID
+            )
+        case .namedEnum, .namedStruct, .namedExt, .namedUnion:
+            if compatible {
+                let remoteTypeInfo = try readCompatibleTypeInfoIfNeeded(
+                    for: localTypeInfo,
+                    wireTypeID: typeID
+                )
+                if typeID == .namedStruct, let remoteTypeInfo {
+                    return remoteTypeInfo
+                }
+            } else {
+                let namespace = try readMetaString(
+                    context: self,
+                    decoder: .namespace,
+                    encodings: namespaceMetaStringEncodings
+                )
+                let typeName = try readMetaString(
+                    context: self,
+                    decoder: .typeName,
+                    encodings: typeNameMetaStringEncodings
+                )
+                guard localTypeInfo.registerByName else {
+                    throw ForyError.invalidData("received name-registered type info for id-registered local type")
+                }
+                if namespace.value != localTypeInfo.namespace.value ||
+                    typeName.value != localTypeInfo.typeName.value {
+                    let expectedTypeName = "\(localTypeInfo.namespace.value)::\(localTypeInfo.typeName.value)"
+                    let actualTypeName = "\(namespace.value)::\(typeName.value)"
+                    throw ForyError.invalidData(
+                        "type name mismatch: expected \(expectedTypeName), got \(actualTypeName)"
+                    )
+                }
+            }
+        default:
+            if !localTypeInfo.registerByName && registeredWireTypeNeedsUserTypeID(typeID) {
+                guard let localUserTypeID = localTypeInfo.userTypeID else {
+                    throw ForyError.invalidData("missing user type id for id-registered type")
+                }
+                let remoteUserTypeID = try buffer.readVarUInt32()
+                if remoteUserTypeID != localUserTypeID {
+                    throw ForyError.typeMismatch(expected: localUserTypeID, actual: remoteUserTypeID)
+                }
+            }
+        }
+        return nil
+    }
+
+    @inline(__always)
+    private func readCompatibleTypeInfoIfNeeded(
+        for localTypeInfo: TypeInfo,
+        wireTypeID: TypeId
+    ) throws -> TypeInfo? {
+        let buffer = self.buffer
+        let compatibleTypeDefTypeInfos = self.compatibleTypeDefTypeInfos
+        if !checkClassVersion,
+           compatibleTypeDefTypeInfos.isEmpty,
+           !localTypeInfo.typeDefHasUserTypeFields,
+           let localTypeDefHeader = localTypeInfo.typeDefHeader {
+            let typeMetaStart = buffer.getCursor()
+            let indexMarker = try buffer.readVarUInt32()
+            if indexMarker == 0 {
+                let header = try buffer.readUInt64()
+                var bodySize = Int(header & UInt64(typeMetaSizeMask))
+                if bodySize == typeMetaSizeMask {
+                    bodySize += Int(try buffer.readVarUInt32())
+                }
+                if header == localTypeDefHeader {
+                    compatibleTypeDefTypeInfos.push(localTypeInfo)
+                    try buffer.skip(bodySize)
+                    return nil
+                }
+            }
+            buffer.setCursor(typeMetaStart)
+        }
+        return try readCompatibleTypeInfo(
+            for: localTypeInfo,
+            wireTypeID: wireTypeID
+        )
+    }
+
+    private func readCompatibleTypeInfo() throws -> TypeInfo {
+        let buffer = self.buffer
+        let compatibleTypeDefTypeInfos = self.compatibleTypeDefTypeInfos
+        let indexMarker = try buffer.readVarUInt32()
+        let isRef = (indexMarker & 1) == 1
+        let index = Int(indexMarker >> 1)
+        if isRef {
+            guard let typeInfo = compatibleTypeDefTypeInfos.get(index) else {
+                throw ForyError.invalidData("unknown compatible type definition ref index \(index)")
+            }
+            return typeInfo
+        }
+
+        let typeMetaStart = buffer.getCursor()
+        let header = try buffer.readUInt64()
+        var bodySize = Int(header & UInt64(typeMetaSizeMask))
+        if bodySize == typeMetaSizeMask {
+            bodySize += Int(try buffer.readVarUInt32())
+        }
+        if let cached = typeResolver.getTypeInfo(forHeader: header) {
+            try buffer.skip(bodySize)
+            compatibleTypeDefTypeInfos.push(cached)
+            return cached
+        }
+
+        buffer.setCursor(typeMetaStart)
+        let decoded = try TypeMeta.decode(buffer)
+        let cachedTypeInfo = try typeResolver.cacheTypeInfo(decoded, forHeader: header)
+        compatibleTypeDefTypeInfos.push(cachedTypeInfo)
+        return cachedTypeInfo
+    }
+
+    @inline(__always)
+    private func readCompatibleTypeInfo(
+        for localTypeInfo: TypeInfo,
+        wireTypeID: TypeId
+    ) throws -> TypeInfo {
+        let buffer = self.buffer
+        let compatibleTypeDefTypeInfos = self.compatibleTypeDefTypeInfos
+        let remoteTypeInfo: TypeInfo
+        if compatibleTypeDefTypeInfos.isEmpty,
+           let localTypeDefHeader = localTypeInfo.typeDefHeader {
+            let typeMetaStart = buffer.getCursor()
+            let indexMarker = try buffer.readVarUInt32()
+            if indexMarker != 0 {
+                buffer.setCursor(typeMetaStart)
+                remoteTypeInfo = try readCompatibleTypeInfo()
+            } else {
+                let header = try buffer.readUInt64()
+                var bodySize = Int(header & UInt64(typeMetaSizeMask))
+                if bodySize == typeMetaSizeMask {
+                    bodySize += Int(try buffer.readVarUInt32())
+                }
+
+                if header == localTypeDefHeader {
+                    compatibleTypeDefTypeInfos.push(localTypeInfo)
+                    try buffer.skip(bodySize)
+                    return localTypeInfo
+                }
+
+                buffer.setCursor(typeMetaStart)
+                remoteTypeInfo = try readCompatibleTypeInfo()
+            }
+        } else {
+            remoteTypeInfo = try readCompatibleTypeInfo()
+        }
+        guard let remoteTypeMeta = remoteTypeInfo.compatibleTypeMeta else {
+            throw ForyError.invalidData("compatible type metadata is required")
+        }
+        if let localTypeMeta = localTypeInfo.typeMeta,
+           remoteTypeMeta === localTypeMeta {
+            return localTypeInfo
+        }
+        if remoteTypeMeta.registerByName {
+            guard localTypeInfo.registerByName else {
+                throw ForyError.invalidData("received name-registered compatible metadata for id-registered local type")
+            }
+            if remoteTypeMeta.namespace.value != localTypeInfo.namespace.value {
+                throw ForyError.invalidData(
+                    "namespace mismatch: expected \(localTypeInfo.namespace.value), got \(remoteTypeMeta.namespace.value)"
+                )
+            }
+            if remoteTypeMeta.typeName.value != localTypeInfo.typeName.value {
+                throw ForyError.invalidData(
+                    "type name mismatch: expected \(localTypeInfo.typeName.value), got \(remoteTypeMeta.typeName.value)"
+                )
+            }
+        } else {
+            guard !localTypeInfo.registerByName else {
+                throw ForyError.invalidData("received id-registered compatible metadata for name-registered local type")
+            }
+            guard let remoteUserTypeID = remoteTypeMeta.userTypeID else {
+                throw ForyError.invalidData("missing user type id in compatible type metadata")
+            }
+            guard let localUserTypeID = localTypeInfo.userTypeID else {
+                throw ForyError.invalidData("missing local user type id metadata for id-registered type")
+            }
+            if remoteUserTypeID != localUserTypeID {
+                throw ForyError.typeMismatch(expected: localUserTypeID, actual: remoteUserTypeID)
+            }
+        }
+
+        if let remoteTypeID = remoteTypeMeta.typeID,
+           let remoteWireTypeID = TypeId(rawValue: remoteTypeID),
+           !isAllowedRegisteredWireTypeID(
+               remoteWireTypeID,
+               declaredTypeID: localTypeInfo.typeID,
+               registerByName: localTypeInfo.registerByName,
+               compatible: compatible
+           ) {
+            throw ForyError.typeMismatch(expected: wireTypeID.rawValue, actual: remoteTypeID)
+        }
+        return remoteTypeInfo
+    }
+
+    func readAnyValue(typeInfo: TypeInfo) throws -> Any {
+        try enterDynamicAnyDepth()
+        defer { leaveDynamicAnyDepth() }
+
+        let value: Any
+        switch typeInfo.typeID {
+        case .bool:
+            value = try Bool.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int8:
+            value = try Int8.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int16:
+            value = try Int16.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int32:
+            value = try ForyInt32Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .varint32:
+            value = try Int32.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int64:
+            value = try ForyInt64Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .varint64:
+            value = try Int64.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .taggedInt64:
+            value = try ForyInt64Tagged.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .uint8:
+            value = try UInt8.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .uint16:
+            value = try UInt16.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .uint32:
+            value = try ForyUInt32Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .varUInt32:
+            value = try UInt32.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .uint64:
+            value = try ForyUInt64Fixed.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .varUInt64:
+            value = try UInt64.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .taggedUInt64:
+            value = try ForyUInt64Tagged.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .float16:
+            value = try Float16.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .bfloat16:
+            value = try BFloat16.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .float32:
+            value = try Float.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .float64:
+            value = try Double.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .string:
+            value = try String.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .duration:
+            value = try Duration.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .timestamp:
+            value = try Date.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .date:
+            value = try ForyDate.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .binary, .uint8Array:
+            value = try Data.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .boolArray:
+            value = try [Bool].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int8Array:
+            value = try [Int8].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int16Array:
+            value = try [Int16].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int32Array:
+            value = try [Int32].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .int64Array:
+            value = try [Int64].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .uint16Array:
+            value = try [UInt16].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .uint32Array:
+            value = try [UInt32].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .uint64Array:
+            value = try [UInt64].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .float16Array:
+            value = try [Float16].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .bfloat16Array:
+            value = try [BFloat16].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .float32Array:
+            value = try [Float].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .float64Array:
+            value = try [Double].foryRead(self, refMode: .none, readTypeInfo: false)
+        case .array, .list:
+            value = try readAnyList(refMode: .none) ?? []
+        case .set:
+            value = try Set<AnyHashable>.foryRead(self, refMode: .none, readTypeInfo: false)
+        case .map:
+            value = try readDynamicAnyMapValue(context: self)
+        case .none:
+            value = ForyAnyNullValue()
+        default:
+            if typeInfo.typeID.isUserTypeKind {
+                value = try typeInfo.read(self)
+            } else {
+                throw ForyError.invalidData("unsupported dynamic type id \(typeInfo.typeID)")
+            }
+        }
+        return value
+    }
+
+    @inline(__always)
+    func getTypeInfo<T: Serializer>(for type: T.Type) -> TypeInfo? {
+        typeInfoStack.value(for: UInt64(UInt(bitPattern: ObjectIdentifier(type))))
+    }
+
+    func withTypeInfo<T: Serializer, R>(
+        _ typeInfo: TypeInfo?,
+        for type: T.Type,
+        _ body: () throws -> R
+    ) rethrows -> R {
+        guard let typeInfo else {
+            return try body()
+        }
+
+        let typeKey = UInt64(UInt(bitPattern: ObjectIdentifier(type)))
+        let previousTypeInfo = typeInfoStack.value(for: typeKey)
+        typeInfoScopeStack.append((typeKey: typeKey, previousTypeInfo: previousTypeInfo))
+        typeInfoStack.set(typeInfo, for: typeKey)
+        defer {
+            if let scope = typeInfoScopeStack.popLast() {
+                if let previousTypeInfo = scope.previousTypeInfo {
+                    typeInfoStack.set(previousTypeInfo, for: scope.typeKey)
+                } else {
+                    _ = typeInfoStack.removeValue(for: scope.typeKey)
+                }
+            } else {
+                assertionFailure("type info scope stack underflow")
+            }
+        }
+        return try body()
+    }
+
+    @inline(__always)
+    func getReadMetaString(at index: Int) -> MetaString? {
+        metaStrings.get(index)
+    }
+
+    @inline(__always)
+    func appendReadMetaString(_ value: MetaString) {
+        metaStrings.push(value)
+    }
+
+    func reset() {
+        if dynamicAnyDepth != 0 {
+            dynamicAnyDepth = 0
+        }
+        if trackRef {
+            refReader.reset()
+        }
+        if !typeInfoStack.isEmpty {
+            typeInfoStack.clear()
+        }
+        if !typeInfoScopeStack.isEmpty {
+            typeInfoScopeStack.removeAll(keepingCapacity: true)
+        }
+        compatibleTypeDefTypeInfos.reset()
+        metaStrings.reset()
+    }
+}
+
+public extension ReadContext {
+    func readAny(
+        refMode: RefMode,
+        readTypeInfo: Bool = true
+    ) throws -> Any? {
+        try DynamicAnyValue.foryRead(self, refMode: refMode, readTypeInfo: readTypeInfo).anyValue()
+    }
+
+    func readAnyList(
+        refMode: RefMode,
+        readTypeInfo: Bool = false
+    ) throws -> [Any]? {
+        let wrapped: [DynamicAnyValue]? = try [DynamicAnyValue]?.foryRead(
+            self,
+            refMode: refMode,
+            readTypeInfo: readTypeInfo
+        )
+        return wrapped?.map { $0.anyValueForCollection() }
+    }
+
+    func readStringAnyMap(
+        refMode: RefMode,
+        readTypeInfo: Bool = false
+    ) throws -> [String: Any]? {
+        let wrapped: [String: DynamicAnyValue]? = try [String: DynamicAnyValue]?.foryRead(
+            self,
+            refMode: refMode,
+            readTypeInfo: readTypeInfo
+        )
+        guard let wrapped else {
+            return nil
+        }
+        var map: [String: Any] = [:]
+        map.reserveCapacity(wrapped.count)
+        for pair in wrapped {
+            map[pair.key] = pair.value.anyValueForCollection()
+        }
+        return map
+    }
+
+    func readInt32AnyMap(
+        refMode: RefMode,
+        readTypeInfo: Bool = false
+    ) throws -> [Int32: Any]? {
+        let wrapped: [Int32: DynamicAnyValue]? = try [Int32: DynamicAnyValue]?.foryRead(
+            self,
+            refMode: refMode,
+            readTypeInfo: readTypeInfo
+        )
+        guard let wrapped else {
+            return nil
+        }
+        var map: [Int32: Any] = [:]
+        map.reserveCapacity(wrapped.count)
+        for pair in wrapped {
+            map[pair.key] = pair.value.anyValueForCollection()
+        }
+        return map
+    }
+
+    func readAnyHashableAnyMap(
+        refMode: RefMode,
+        readTypeInfo: Bool = false
+    ) throws -> [AnyHashable: Any]? {
+        let wrapped: [AnyHashable: DynamicAnyValue]? = try [AnyHashable: DynamicAnyValue]?.foryRead(
+            self,
+            refMode: refMode,
+            readTypeInfo: readTypeInfo
+        )
+        guard let wrapped else {
+            return nil
+        }
+        var map: [AnyHashable: Any] = [:]
+        map.reserveCapacity(wrapped.count)
+        for pair in wrapped {
+            map[pair.key] = pair.value.anyValueForCollection()
+        }
+        return map
+    }
+}
diff --git a/swift/Sources/Fory/RefResolver.swift b/swift/Sources/Fory/RefResolver.swift
index c3321f2f4..f7d0823af 100644
--- a/swift/Sources/Fory/RefResolver.swift
+++ b/swift/Sources/Fory/RefResolver.swift
@@ -23,7 +23,7 @@ public final class RefWriter {
 
     public init() {}
 
-    public func tryWriteReference(buffer: ByteBuffer, object: AnyObject) -> Bool {
+    public func tryWriteRef(buffer: ByteBuffer, object: AnyObject) -> Bool {
         let objectID = ObjectIdentifier(object)
         if let refID = refs[objectID] {
             buffer.writeInt8(RefFlag.ref.rawValue)
@@ -36,12 +36,6 @@ public final class RefWriter {
         return false
     }
 
-    public func reserveRefID() -> UInt32 {
-        let id = nextRefID
-        nextRefID &+= 1
-        return id
-    }
-
     public func reset() {
         if !refs.isEmpty {
             refs.removeAll(keepingCapacity: true)
diff --git a/swift/Sources/Fory/Serializer.swift b/swift/Sources/Fory/Serializer.swift
index e2d281b8f..81621210f 100644
--- a/swift/Sources/Fory/Serializer.swift
+++ b/swift/Sources/Fory/Serializer.swift
@@ -17,23 +17,14 @@
 
 import Foundation
 
-private struct CompatibleTypeMetaCacheKey: Hashable {
-    let swiftType: ObjectIdentifier
-    let wireTypeID: TypeId
-    let trackRef: Bool
-    let registerByName: Bool
-    let userTypeID: UInt32?
-    let namespace: MetaString?
-    let typeName: MetaString
+@inline(__always)
+func writeBuiltinTypeInfo(_ context: WriteContext, _ typeID: TypeId) {
+    context.writeStaticTypeInfo(typeID)
 }
 
-private struct CompatibleTypeMetaCacheEntry {
-    let encodedTypeMeta: [UInt8]
-}
-
-private enum CompatibleTypeMetaCache {
-    nonisolated(unsafe) static var values: [CompatibleTypeMetaCacheKey: CompatibleTypeMetaCacheEntry] = [:]
-    static let lock = NSLock()
+@inline(__always)
+func readBuiltinTypeInfo(_ context: ReadContext, _ typeID: TypeId) throws -> TypeInfo? {
+    try context.readStaticTypeInfo(typeID)
 }
 
 public protocol Serializer {
@@ -41,7 +32,7 @@ public protocol Serializer {
     static var staticTypeId: TypeId { get }
 
     static var isNullableType: Bool { get }
-    static var isReferenceTrackableType: Bool { get }
+    static var isRefType: Bool { get }
 
     var foryIsNone: Bool { get }
 
@@ -61,9 +52,10 @@ public protocol Serializer {
         readTypeInfo: Bool
     ) throws -> Self
 
-    static func foryWriteTypeInfo(_ context: WriteContext) throws
-    static func foryReadTypeInfo(_ context: ReadContext) throws
-    static func foryCompatibleTypeMetaFields(trackRef: Bool) -> [TypeMetaFieldInfo]
+    static func foryWriteStaticTypeInfo(_ context: WriteContext) throws
+    static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo?
+    static func foryReadCompatibleData(_ context: ReadContext, remoteTypeInfo: TypeInfo) throws -> Self
+    static func foryFieldsInfo(trackRef: Bool) -> [TypeMeta.FieldInfo]
     func foryWriteTypeInfo(_ context: WriteContext) throws
 }
 
@@ -72,19 +64,56 @@ public extension Serializer {
     static var isNullableType: Bool { false }
 
     @inlinable
-    static var isReferenceTrackableType: Bool { false }
+    static var isRefType: Bool { false }
 
     @inlinable
     var foryIsNone: Bool { false }
 
     @inlinable
-    static func foryCompatibleTypeMetaFields(trackRef _: Bool) -> [TypeMetaFieldInfo] {
+    func foryWriteTypeInfo(_ context: WriteContext) throws {
+        try Self.foryWriteStaticTypeInfo(context)
+    }
+
+    @inlinable
+    static func foryFieldsInfo(trackRef _: Bool) -> [TypeMeta.FieldInfo] {
         []
     }
 
     @inlinable
-    func foryWriteTypeInfo(_ context: WriteContext) throws {
-        try Self.foryWriteTypeInfo(context)
+    static func foryReadCompatibleData(_ context: ReadContext, remoteTypeInfo _: TypeInfo) throws -> Self {
+        try foryReadData(context)
+    }
+}
+
+public extension Serializer {
+    static func foryReadPayload(
+        _ context: ReadContext,
+        readTypeInfo: Bool
+    ) throws -> Self {
+        try Self.foryReadPayload(
+            context,
+            readTypeInfo: readTypeInfo,
+            readData: { try Self.foryReadData(context) },
+            readCompatibleData: { remoteTypeInfo in
+                try Self.foryReadCompatibleData(context, remoteTypeInfo: remoteTypeInfo)
+            }
+        )
+    }
+
+    static func foryReadPayload(
+        _ context: ReadContext,
+        readTypeInfo: Bool,
+        readData: () throws -> Self,
+        readCompatibleData: (TypeInfo) throws -> Self
+    ) throws -> Self {
+        if readTypeInfo {
+            if let remoteTypeInfo = try Self.foryReadTypeInfo(context) {
+                return try readCompatibleData(remoteTypeInfo)
+            }
+        } else if let remoteTypeInfo = context.getTypeInfo(for: Self.self) {
+            return try readCompatibleData(remoteTypeInfo)
+        }
+        return try readData()
     }
 
     @inlinable
@@ -95,8 +124,8 @@ public extension Serializer {
         hasGenerics: Bool
     ) throws {
         if refMode != .none {
-            if refMode == .tracking, Self.isReferenceTrackableType, let object = self as AnyObject? {
-                if context.refWriter.tryWriteReference(buffer: context.buffer, object: object) {
+            if refMode == .tracking, Self.isRefType, let object = self as AnyObject? {
+                if context.refWriter.tryWriteRef(buffer: context.buffer, object: object) {
                     return
                 }
             } else {
@@ -105,7 +134,7 @@ public extension Serializer {
         }
 
         if writeTypeInfo {
-            try Self.foryWriteTypeInfo(context)
+            try Self.foryWriteStaticTypeInfo(context)
         }
 
         try foryWriteData(context, hasGenerics: hasGenerics)
@@ -117,12 +146,37 @@ public extension Serializer {
         refMode: RefMode,
         readTypeInfo: Bool
     ) throws -> Self {
-        if refMode != .none {
+        switch refMode {
+        case .none:
+            return try Self.foryReadPayload(context, readTypeInfo: readTypeInfo)
+        case .nullOnly:
+            let rawFlag = try context.buffer.readInt8()
+            switch rawFlag {
+            case RefFlag.null.rawValue:
+                return Self.foryDefault()
+            case RefFlag.notNullValue.rawValue:
+                return try Self.foryReadPayload(context, readTypeInfo: readTypeInfo)
+            case RefFlag.refValue.rawValue:
+                if context.trackRef {
+                    let reservedRefID = context.refReader.reserveRefID()
+                    let value = try Self.foryReadPayload(context, readTypeInfo: readTypeInfo)
+                    if let object = value as AnyObject? {
+                        context.refReader.storeRef(object, at: reservedRefID)
+                    }
+                    return value
+                }
+                return try Self.foryReadPayload(context, readTypeInfo: readTypeInfo)
+            case RefFlag.ref.rawValue:
+                let refID = try context.buffer.readVarUInt32()
+                return try context.refReader.readRef(refID, as: Self.self)
+            default:
+                throw ForyError.refError("invalid ref flag \(rawFlag)")
+            }
+        case .tracking:
             let rawFlag = try context.buffer.readInt8()
             guard let flag = RefFlag(rawValue: rawFlag) else {
                 throw ForyError.refError("invalid ref flag \(rawFlag)")
             }
-
             switch flag {
             case .null:
                 return Self.foryDefault()
@@ -130,81 +184,56 @@ public extension Serializer {
                 let refID = try context.buffer.readVarUInt32()
                 return try context.refReader.readRef(refID, as: Self.self)
             case .refValue:
-                let reservedRefID = context.refReader.reserveRefID()
-                context.pushPendingReference(reservedRefID)
-                if readTypeInfo {
-                    try Self.foryReadTypeInfo(context)
+                let reservedRefID = context.trackRef ? context.refReader.reserveRefID() : nil
+                let value = try Self.foryReadPayload(context, readTypeInfo: readTypeInfo)
+                if let reservedRefID, let object = value as AnyObject? {
+                    context.refReader.storeRef(object, at: reservedRefID)
                 }
-                let value = try Self.foryReadData(context)
-                context.finishPendingReferenceIfNeeded(value)
-                context.popPendingReference()
                 return value
             case .notNullValue:
-                break
+                return try Self.foryReadPayload(context, readTypeInfo: readTypeInfo)
             }
         }
-
-        if readTypeInfo {
-            try Self.foryReadTypeInfo(context)
-        }
-        return try Self.foryReadData(context)
     }
 
-    static func foryWriteTypeInfo(_ context: WriteContext) throws {
+    static func foryWriteStaticTypeInfo(_ context: WriteContext) throws {
         guard staticTypeId.isUserTypeKind else {
             context.buffer.writeUInt8(UInt8(truncatingIfNeeded: staticTypeId.rawValue))
             return
         }
 
-        let info = try context.typeResolver.requireRegisteredTypeInfo(for: Self.self)
-        let wireTypeID = resolveWireTypeID(
-            declaredKind: info.kind,
-            registerByName: info.registerByName,
-            compatible: context.compatible
-        )
+        let typeInfo = try context.typeInfo(for: Self.self)
+        let wireTypeID = typeInfo.wireTypeID(compatible: context.compatible)
         context.buffer.writeUInt8(UInt8(truncatingIfNeeded: wireTypeID.rawValue))
         switch wireTypeID {
         case .compatibleStruct, .namedCompatibleStruct:
-            let cachedTypeMeta = try compatibleTypeMetaEntry(
-                info: info,
-                wireTypeID: wireTypeID,
-                trackRef: context.trackRef
-            )
-            try context.writeCompatibleTypeMeta(
-                for: Self.self,
-                encodedTypeMeta: cachedTypeMeta.encodedTypeMeta
-            )
+            guard typeInfo.typeDefBytes != nil else {
+                throw ForyError.invalidData("missing compatible type definition for \(typeInfo.typeID)")
+            }
+            context.writeTypeMeta(typeInfo)
         case .namedEnum, .namedStruct, .namedExt, .namedUnion:
             if context.compatible {
-                let cachedTypeMeta = try compatibleTypeMetaEntry(
-                    info: info,
-                    wireTypeID: wireTypeID,
-                    trackRef: context.trackRef
-                )
-                try context.writeCompatibleTypeMeta(
-                    for: Self.self,
-                    encodedTypeMeta: cachedTypeMeta.encodedTypeMeta
-                )
-            } else {
-                guard let namespace = info.namespace else {
-                    throw ForyError.invalidData("missing namespace metadata for name-registered type")
+                guard typeInfo.typeDefBytes != nil else {
+                    throw ForyError.invalidData("missing compatible type definition for \(typeInfo.typeID)")
                 }
+                context.writeTypeMeta(typeInfo)
+            } else {
                 try writeMetaString(
                     context: context,
-                    value: namespace,
+                    value: typeInfo.namespace,
                     encodings: namespaceMetaStringEncodings,
                     encoder: .namespace
                 )
                 try writeMetaString(
                     context: context,
-                    value: info.typeName,
+                    value: typeInfo.typeName,
                     encodings: typeNameMetaStringEncodings,
                     encoder: .typeName
                 )
             }
         default:
-            if !info.registerByName && wireTypeNeedsUserTypeID(wireTypeID) {
-                guard let userTypeID = info.userTypeID else {
+            if !typeInfo.registerByName && registeredWireTypeNeedsUserTypeID(wireTypeID) {
+                guard let userTypeID = typeInfo.userTypeID else {
                     throw ForyError.invalidData("missing user type id for id-registered type")
                 }
                 context.buffer.writeVarUInt32(userTypeID)
@@ -212,393 +241,8 @@ public extension Serializer {
         }
     }
 
-    static func foryReadTypeInfo(_ context: ReadContext) throws {
-        let rawTypeID = try context.buffer.readVarUInt32()
-        guard let typeID = TypeId(rawValue: rawTypeID) else {
-            throw ForyError.invalidData("unknown type id \(rawTypeID)")
-        }
-
-        guard staticTypeId.isUserTypeKind else {
-            if typeID != staticTypeId {
-                throw ForyError.typeMismatch(expected: staticTypeId.rawValue, actual: rawTypeID)
-            }
-            return
-        }
-
-        let info = try context.typeResolver.requireRegisteredTypeInfo(for: Self.self)
-        let allowed = allowedWireTypeIDs(
-            declaredKind: info.kind,
-            registerByName: info.registerByName,
-            compatible: context.compatible
-        )
-        if !allowed.contains(typeID) {
-            if let expected = allowed.first {
-                throw ForyError.typeMismatch(expected: expected.rawValue, actual: rawTypeID)
-            }
-            throw ForyError.invalidData("no expected wire type ids for \(info.kind)")
-        }
-
-        switch typeID {
-        case .compatibleStruct, .namedCompatibleStruct:
-            let remoteTypeMeta = try context.readCompatibleTypeMeta()
-            try validateCompatibleTypeMeta(
-                remoteTypeMeta,
-                localInfo: info,
-                expectedWireTypes: allowed,
-                actualWireTypeID: typeID
-            )
-            context.pushCompatibleTypeMeta(for: Self.self, remoteTypeMeta)
-        case .namedEnum, .namedStruct, .namedExt, .namedUnion:
-            if context.compatible {
-                let remoteTypeMeta = try context.readCompatibleTypeMeta()
-                try validateCompatibleTypeMeta(
-                    remoteTypeMeta,
-                    localInfo: info,
-                    expectedWireTypes: allowed,
-                    actualWireTypeID: typeID
-                )
-                if typeID == .namedStruct {
-                    context.pushCompatibleTypeMeta(for: Self.self, remoteTypeMeta)
-                }
-            } else {
-                let namespace = try readMetaString(
-                    context: context,
-                    decoder: .namespace,
-                    encodings: namespaceMetaStringEncodings
-                )
-                let typeName = try readMetaString(
-                    context: context,
-                    decoder: .typeName,
-                    encodings: typeNameMetaStringEncodings
-                )
-                guard info.registerByName else {
-                    throw ForyError.invalidData("received name-registered type info for id-registered local type")
-                }
-                guard let localNamespace = info.namespace else {
-                    throw ForyError.invalidData("missing local namespace metadata for name-registered type")
-                }
-                if namespace.value != localNamespace.value || typeName.value != info.typeName.value {
-                    throw ForyError.invalidData(
-                        "type name mismatch: expected \(localNamespace.value)::\(info.typeName.value), got \(namespace.value)::\(typeName.value)"
-                    )
-                }
-            }
-        default:
-            if !info.registerByName && wireTypeNeedsUserTypeID(typeID) {
-                guard let localUserTypeID = info.userTypeID else {
-                    throw ForyError.invalidData("missing user type id for id-registered type")
-                }
-                let remoteUserTypeID = try context.buffer.readVarUInt32()
-                if remoteUserTypeID != localUserTypeID {
-                    throw ForyError.typeMismatch(expected: localUserTypeID, actual: remoteUserTypeID)
-                }
-            }
-        }
-    }
-
-    private static func normalizeBaseKind(_ kind: TypeId) -> TypeId {
-        switch kind {
-        case .namedEnum:
-            return .enumType
-        case .compatibleStruct, .namedCompatibleStruct, .namedStruct:
-            return .structType
-        case .namedExt:
-            return .ext
-        case .namedUnion, .union:
-            return .typedUnion
-        default:
-            return kind
-        }
+    static func foryReadTypeInfo(_ context: ReadContext) throws -> TypeInfo? {
+        try context.readTypeInfo(for: Self.self)
     }
 
-    private static func namedKind(for baseKind: TypeId, compatible: Bool) -> TypeId {
-        switch baseKind {
-        case .structType:
-            return compatible ? .namedCompatibleStruct : .namedStruct
-        case .enumType:
-            return .namedEnum
-        case .ext:
-            return .namedExt
-        case .typedUnion:
-            return .namedUnion
-        default:
-            return baseKind
-        }
-    }
-
-    private static func idKind(for baseKind: TypeId, compatible: Bool) -> TypeId {
-        switch baseKind {
-        case .structType:
-            return compatible ? .compatibleStruct : .structType
-        default:
-            return baseKind
-        }
-    }
-
-    private static func resolveWireTypeID(
-        declaredKind: TypeId,
-        registerByName: Bool,
-        compatible: Bool
-    ) -> TypeId {
-        let baseKind = normalizeBaseKind(declaredKind)
-        if registerByName {
-            return namedKind(for: baseKind, compatible: compatible)
-        }
-        return idKind(for: baseKind, compatible: compatible)
-    }
-
-    private static func allowedWireTypeIDs(
-        declaredKind: TypeId,
-        registerByName: Bool,
-        compatible: Bool
-    ) -> Set<TypeId> {
-        let baseKind = normalizeBaseKind(declaredKind)
-        let expected = resolveWireTypeID(
-            declaredKind: declaredKind,
-            registerByName: registerByName,
-            compatible: compatible
-        )
-        var allowed: Set<TypeId> = [expected]
-        if baseKind == .structType, compatible {
-            // Be permissive across peers while struct compatibility converges.
-            allowed.insert(.compatibleStruct)
-            allowed.insert(.namedCompatibleStruct)
-            allowed.insert(.structType)
-            allowed.insert(.namedStruct)
-        }
-        if baseKind == .typedUnion {
-            allowed.insert(.union)
-            if registerByName {
-                allowed.insert(.namedUnion)
-            }
-        }
-        return allowed
-    }
-
-    private static func wireTypeNeedsUserTypeID(_ typeID: TypeId) -> Bool {
-        switch typeID {
-        case .enumType, .structType, .ext, .typedUnion, .union:
-            return true
-        default:
-            return false
-        }
-    }
-
-    private static func compatibleTypeMetaEntry(
-        info: RegisteredTypeInfo,
-        wireTypeID: TypeId,
-        trackRef: Bool
-    ) throws -> CompatibleTypeMetaCacheEntry {
-        let cacheKey = CompatibleTypeMetaCacheKey(
-            swiftType: ObjectIdentifier(Self.self),
-            wireTypeID: wireTypeID,
-            trackRef: trackRef,
-            registerByName: info.registerByName,
-            userTypeID: info.userTypeID,
-            namespace: info.namespace,
-            typeName: info.typeName
-        )
-
-        CompatibleTypeMetaCache.lock.lock()
-        if let cached = CompatibleTypeMetaCache.values[cacheKey] {
-            CompatibleTypeMetaCache.lock.unlock()
-            return cached
-        }
-        CompatibleTypeMetaCache.lock.unlock()
-
-        let typeMeta = try buildCompatibleTypeMeta(
-            info: info,
-            wireTypeID: wireTypeID,
-            trackRef: trackRef
-        )
-        let cacheEntry = CompatibleTypeMetaCacheEntry(
-            encodedTypeMeta: try typeMeta.encode()
-        )
-
-        CompatibleTypeMetaCache.lock.lock()
-        if let cached = CompatibleTypeMetaCache.values[cacheKey] {
-            CompatibleTypeMetaCache.lock.unlock()
-            return cached
-        }
-        CompatibleTypeMetaCache.values[cacheKey] = cacheEntry
-        CompatibleTypeMetaCache.lock.unlock()
-        return cacheEntry
-    }
-
-    private static func buildCompatibleTypeMeta(
-        info: RegisteredTypeInfo,
-        wireTypeID: TypeId,
-        trackRef: Bool
-    ) throws -> TypeMeta {
-        let fields = foryCompatibleTypeMetaFields(trackRef: trackRef)
-        let hasFieldsMeta = !fields.isEmpty
-        if info.registerByName {
-            guard let namespace = info.namespace else {
-                throw ForyError.invalidData("missing namespace metadata for name-registered type")
-            }
-            return try TypeMeta(
-                typeID: wireTypeID.rawValue,
-                userTypeID: nil,
-                namespace: namespace,
-                typeName: info.typeName,
-                registerByName: true,
-                fields: fields,
-                hasFieldsMeta: hasFieldsMeta
-            )
-        }
-
-        guard let userTypeID = info.userTypeID else {
-            throw ForyError.invalidData("missing user type id metadata for id-registered type")
-        }
-        return try TypeMeta(
-            typeID: wireTypeID.rawValue,
-            userTypeID: userTypeID,
-            namespace: MetaString.empty(specialChar1: ".", specialChar2: "_"),
-            typeName: MetaString.empty(specialChar1: "$", specialChar2: "_"),
-            registerByName: false,
-            fields: fields,
-            hasFieldsMeta: hasFieldsMeta
-        )
-    }
-
-    private static func validateCompatibleTypeMeta(
-        _ remoteTypeMeta: TypeMeta,
-        localInfo: RegisteredTypeInfo,
-        expectedWireTypes: Set<TypeId>,
-        actualWireTypeID: TypeId
-    ) throws {
-        if remoteTypeMeta.registerByName {
-            guard localInfo.registerByName else {
-                throw ForyError.invalidData("received name-registered compatible metadata for id-registered local type")
-            }
-            guard let localNamespace = localInfo.namespace else {
-                throw ForyError.invalidData("missing local namespace metadata for name-registered type")
-            }
-            if remoteTypeMeta.namespace.value != localNamespace.value {
-                throw ForyError.invalidData(
-                    "namespace mismatch: expected \(localNamespace.value), got \(remoteTypeMeta.namespace.value)"
-                )
-            }
-            if remoteTypeMeta.typeName.value != localInfo.typeName.value {
-                throw ForyError.invalidData(
-                    "type name mismatch: expected \(localInfo.typeName.value), got \(remoteTypeMeta.typeName.value)"
-                )
-            }
-        } else {
-            guard !localInfo.registerByName else {
-                throw ForyError.invalidData("received id-registered compatible metadata for name-registered local type")
-            }
-            guard let remoteUserTypeID = remoteTypeMeta.userTypeID else {
-                throw ForyError.invalidData("missing user type id in compatible type metadata")
-            }
-            guard let localUserTypeID = localInfo.userTypeID else {
-                throw ForyError.invalidData("missing local user type id metadata for id-registered type")
-            }
-            if remoteUserTypeID != localUserTypeID {
-                throw ForyError.typeMismatch(expected: localUserTypeID, actual: remoteUserTypeID)
-            }
-        }
-
-        if let remoteTypeID = remoteTypeMeta.typeID,
-           let remoteWireTypeID = TypeId(rawValue: remoteTypeID),
-           !expectedWireTypes.contains(remoteWireTypeID) {
-            throw ForyError.typeMismatch(expected: actualWireTypeID.rawValue, actual: remoteTypeID)
-        }
-    }
-
-    private static func writeMetaString(
-        context: WriteContext,
-        value: MetaString,
-        encodings: [MetaStringEncoding],
-        encoder: MetaStringEncoder
-    ) throws {
-        let normalized: MetaString
-        if encodings.contains(value.encoding) {
-            normalized = value
-        } else {
-            normalized = try encoder.encode(value.value, allowedEncodings: encodings)
-        }
-
-        guard encodings.contains(normalized.encoding) else {
-            throw ForyError.encodingError("failed to normalize meta string encoding")
-        }
-
-        context.markMetaStringWriteStateUsed()
-        let bytes = normalized.bytes
-        let assignment = context.metaStringWriteState.assignIndexIfAbsent(for: normalized)
-        if assignment.isNew {
-            context.buffer.writeVarUInt32(UInt32(bytes.count) << 1)
-            if bytes.count > 16 {
-                context.buffer.writeInt64(Int64(bitPattern: javaMetaStringHash(metaString: normalized)))
-            } else if !bytes.isEmpty {
-                context.buffer.writeUInt8(normalized.encoding.rawValue)
-            }
-            context.buffer.writeBytes(bytes)
-        } else {
-            context.buffer.writeVarUInt32(((assignment.index + 1) << 1) | 1)
-        }
-    }
-
-    private static func readMetaString(
-        context: ReadContext,
-        decoder: MetaStringDecoder,
-        encodings: [MetaStringEncoding]
-    ) throws -> MetaString {
-        context.markMetaStringReadStateUsed()
-        let header = try context.buffer.readVarUInt32()
-        let length = Int(header >> 1)
-        let isRef = (header & 1) == 1
-        if isRef {
-            let index = length - 1
-            guard let cached = context.metaStringReadState.value(at: index) else {
-                throw ForyError.invalidData("unknown meta string ref index \(index)")
-            }
-            return cached
-        }
-
-        let value: MetaString
-        if length == 0 {
-            value = MetaString.empty(
-                specialChar1: decoder.specialChar1,
-                specialChar2: decoder.specialChar2
-            )
-        } else {
-            let encoding: MetaStringEncoding
-            if length > 16 {
-                let hash = try context.buffer.readInt64()
-                let rawEncoding = UInt8(truncatingIfNeeded: hash & 0xFF)
-                guard let resolved = MetaStringEncoding(rawValue: rawEncoding) else {
-                    throw ForyError.invalidData("invalid meta string encoding \(rawEncoding)")
-                }
-                encoding = resolved
-            } else {
-                let rawEncoding = try context.buffer.readUInt8()
-                guard let resolved = MetaStringEncoding(rawValue: rawEncoding) else {
-                    throw ForyError.invalidData("invalid meta string encoding \(rawEncoding)")
-                }
-                encoding = resolved
-            }
-            guard encodings.contains(encoding) else {
-                throw ForyError.invalidData("meta string encoding \(encoding) not allowed in this context")
-            }
-            let bytes = try context.buffer.readBytes(count: length)
-            value = try decoder.decode(bytes: bytes, encoding: encoding)
-        }
-        context.metaStringReadState.append(value)
-        return value
-    }
-
-    private static func javaMetaStringHash(metaString: MetaString) -> UInt64 {
-        var hash = Int64(bitPattern: MurmurHash3.x64_128(metaString.bytes, seed: 47).0)
-        if hash != Int64.min {
-            hash = Swift.abs(hash)
-        }
-        var result = UInt64(bitPattern: hash)
-        if result == 0 {
-            result &+= 256
-        }
-        result &= 0xffffffffffffff00
-        result |= UInt64(metaString.encoding.rawValue & 0xFF)
-        return result
-    }
 }
diff --git a/swift/Sources/Fory/TypeMeta.swift b/swift/Sources/Fory/TypeMeta.swift
index 4e4585aa0..78cb17d0c 100644
--- a/swift/Sources/Fory/TypeMeta.swift
+++ b/swift/Sources/Fory/TypeMeta.swift
@@ -48,135 +48,157 @@ public let fieldNameMetaStringEncodings: [MetaStringEncoding] = [
     .lowerUpperDigitSpecial
 ]
 
-public struct TypeMetaFieldType: Equatable, Sendable {
-    public var typeID: UInt32
-    public var nullable: Bool
-    public var trackRef: Bool
-    public var generics: [TypeMetaFieldType]
-
-    public init(
-        typeID: UInt32,
-        nullable: Bool,
-        trackRef: Bool = false,
-        generics: [TypeMetaFieldType] = []
-    ) {
-        self.typeID = typeID
-        self.nullable = nullable
-        self.trackRef = trackRef
-        self.generics = generics
-    }
-
-    fileprivate func write(
-        _ buffer: ByteBuffer,
-        writeFlags: Bool,
-        nullableOverride: Bool? = nil
-    ) {
-        if writeFlags {
-            var header = typeID << 2
-            if nullableOverride ?? nullable {
-                header |= 0b10
+public final class TypeMeta: Equatable, @unchecked Sendable {
+
+    public struct FieldType: Equatable, Sendable {
+        public var typeID: UInt32
+        public var nullable: Bool
+        public var trackRef: Bool
+        public var generics: [FieldType]
+
+        public init(
+            typeID: UInt32,
+            nullable: Bool,
+            trackRef: Bool = false,
+            generics: [FieldType] = []
+        ) {
+            self.typeID = typeID
+            self.nullable = nullable
+            self.trackRef = trackRef
+            self.generics = generics
+        }
+
+        fileprivate func write(
+            _ buffer: ByteBuffer,
+            writeFlags: Bool,
+            nullableOverride: Bool? = nil
+        ) {
+            if writeFlags {
+                var header = typeID << 2
+                if nullableOverride ?? nullable {
+                    header |= 0b10
+                }
+                if trackRef {
+                    header |= 0b1
+                }
+                buffer.writeVarUInt32(header)
+            } else {
+                buffer.writeUInt8(UInt8(truncatingIfNeeded: typeID))
             }
-            if trackRef {
-                header |= 0b1
+
+            if typeID == TypeId.list.rawValue || typeID == TypeId.set.rawValue {
+                let element = generics.first ?? FieldType(typeID: TypeId.unknown.rawValue, nullable: true)
+                element.write(buffer, writeFlags: true, nullableOverride: element.nullable)
+            } else if typeID == TypeId.map.rawValue {
+                let key = generics.first ?? FieldType(typeID: TypeId.unknown.rawValue, nullable: true)
+                let value = generics.dropFirst().first ?? FieldType(typeID: TypeId.unknown.rawValue, nullable: true)
+                key.write(buffer, writeFlags: true, nullableOverride: key.nullable)
+                value.write(buffer, writeFlags: true, nullableOverride: value.nullable)
             }
-            buffer.writeVarUInt32(header)
-        } else {
-            buffer.writeUInt8(UInt8(truncatingIfNeeded: typeID))
         }
 
-        if typeID == TypeId.list.rawValue || typeID == TypeId.set.rawValue {
-            let element = generics.first ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: true)
-            element.write(buffer, writeFlags: true, nullableOverride: element.nullable)
-        } else if typeID == TypeId.map.rawValue {
-            let key = generics.first ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: true)
-            let value = generics.dropFirst().first ?? TypeMetaFieldType(typeID: TypeId.unknown.rawValue, nullable: true)
-            key.write(buffer, writeFlags: true, nullableOverride: key.nullable)
-            value.write(buffer, writeFlags: true, nullableOverride: value.nullable)
-        }
-    }
+        fileprivate static func read(
+            _ buffer: ByteBuffer,
+            readFlags: Bool,
+            nullable: Bool? = nil,
+            trackRef: Bool? = nil
+        ) throws -> FieldType {
+            let header: UInt32
+            if readFlags {
+                header = try buffer.readVarUInt32()
+            } else {
+                header = UInt32(try buffer.readUInt8())
+            }
 
-    fileprivate static func read(
-        _ buffer: ByteBuffer,
-        readFlags: Bool,
-        nullable: Bool? = nil,
-        trackRef: Bool? = nil
-    ) throws -> TypeMetaFieldType {
-        let header: UInt32
-        if readFlags {
-            header = try buffer.readVarUInt32()
-        } else {
-            header = UInt32(try buffer.readUInt8())
-        }
+            let typeID: UInt32
+            let resolvedNullable: Bool
+            let resolvedTrackRef: Bool
 
-        let typeID: UInt32
-        let resolvedNullable: Bool
-        let resolvedTrackRef: Bool
+            if readFlags {
+                typeID = header >> 2
+                resolvedNullable = (header & 0b10) != 0
+                resolvedTrackRef = (header & 0b1) != 0
+            } else {
+                typeID = header
+                resolvedNullable = nullable ?? false
+                resolvedTrackRef = trackRef ?? false
+            }
 
-        if readFlags {
-            typeID = header >> 2
-            resolvedNullable = (header & 0b10) != 0
-            resolvedTrackRef = (header & 0b1) != 0
-        } else {
-            typeID = header
-            resolvedNullable = nullable ?? false
-            resolvedTrackRef = trackRef ?? false
-        }
+            if typeID == TypeId.list.rawValue || typeID == TypeId.set.rawValue {
+                let element = try read(buffer, readFlags: true)
+                return FieldType(
+                    typeID: typeID,
+                    nullable: resolvedNullable,
+                    trackRef: resolvedTrackRef,
+                    generics: [element]
+                )
+            }
+            if typeID == TypeId.map.rawValue {
+                let key = try read(buffer, readFlags: true)
+                let value = try read(buffer, readFlags: true)
+                return FieldType(
+                    typeID: typeID,
+                    nullable: resolvedNullable,
+                    trackRef: resolvedTrackRef,
+                    generics: [key, value]
+                )
+            }
 
-        if typeID == TypeId.list.rawValue || typeID == TypeId.set.rawValue {
-            let element = try read(buffer, readFlags: true)
-            return TypeMetaFieldType(
+            return FieldType(
                 typeID: typeID,
                 nullable: resolvedNullable,
                 trackRef: resolvedTrackRef,
-                generics: [element]
+                generics: []
             )
         }
-        if typeID == TypeId.map.rawValue {
-            let key = try read(buffer, readFlags: true)
-            let value = try read(buffer, readFlags: true)
-            return TypeMetaFieldType(
-                typeID: typeID,
-                nullable: resolvedNullable,
-                trackRef: resolvedTrackRef,
-                generics: [key, value]
-            )
-        }
-
-        return TypeMetaFieldType(
-            typeID: typeID,
-            nullable: resolvedNullable,
-            trackRef: resolvedTrackRef,
-            generics: []
-        )
     }
-}
-
-public struct TypeMetaFieldInfo: Equatable, Sendable {
-    public var fieldID: Int16?
-    public var fieldName: String
-    public var fieldType: TypeMetaFieldType
 
-    public init(fieldID: Int16?, fieldName: String, fieldType: TypeMetaFieldType) {
-        self.fieldID = fieldID
-        self.fieldName = fieldName
-        self.fieldType = fieldType
-    }
+    public struct FieldInfo: Equatable, Sendable {
+        public var fieldID: Int16?
+        public var fieldName: String
+        public var fieldType: FieldType
 
-    fileprivate func write(_ buffer: ByteBuffer) throws {
-        var header: UInt8 = 0
-        if fieldType.trackRef {
-            header |= 0b1
-        }
-        if fieldType.nullable {
-            header |= 0b10
+        public init(fieldID: Int16?, fieldName: String, fieldType: FieldType) {
+            self.fieldID = fieldID
+            self.fieldName = fieldName
+            self.fieldType = fieldType
         }
 
-        if let fieldID {
-            if fieldID < 0 {
-                throw ForyError.encodingError("negative field id is invalid")
+        fileprivate func write(_ buffer: ByteBuffer) throws {
+            var header: UInt8 = 0
+            if fieldType.trackRef {
+                header |= 0b1
+            }
+            if fieldType.nullable {
+                header |= 0b10
+            }
+
+            if let fieldID {
+                if fieldID < 0 {
+                    throw ForyError.encodingError("negative field id is invalid")
+                }
+                let size = Int(fieldID)
+                header |= UInt8(0b11 << 6)
+                if size >= fieldNameSizeThreshold {
+                    header |= 0b0011_1100
+                    buffer.writeUInt8(header)
+                    buffer.writeVarUInt32(UInt32(size - fieldNameSizeThreshold))
+                } else {
+                    header |= UInt8(size << 2)
+                    buffer.writeUInt8(header)
+                }
+                fieldType.write(buffer, writeFlags: false)
+                return
             }
-            let size = Int(fieldID)
-            header |= UInt8(0b11 << 6)
+
+            let snakeName = lowerCamelToLowerUnderscore(fieldName)
+            let encoded = try MetaStringEncoder.fieldName.encode(snakeName, allowedEncodings: fieldNameMetaStringEncodings)
+            guard let encodingIndex = fieldNameMetaStringEncodings.firstIndex(of: encoded.encoding) else {
+                throw ForyError.encodingError("unsupported field name encoding")
+            }
+
+            let size = encoded.bytes.count - 1
+            header |= UInt8(encodingIndex << 6)
             if size >= fieldNameSizeThreshold {
                 header |= 0b0011_1100
                 buffer.writeUInt8(header)
@@ -185,77 +207,56 @@ public struct TypeMetaFieldInfo: Equatable, Sendable {
                 header |= UInt8(size << 2)
                 buffer.writeUInt8(header)
             }
-            fieldType.write(buffer, writeFlags: false)
-            return
-        }
-
-        let snakeName = lowerCamelToLowerUnderscore(fieldName)
-        let encoded = try MetaStringEncoder.fieldName.encode(snakeName, allowedEncodings: fieldNameMetaStringEncodings)
-        guard let encodingIndex = fieldNameMetaStringEncodings.firstIndex(of: encoded.encoding) else {
-            throw ForyError.encodingError("unsupported field name encoding")
-        }
 
-        let size = encoded.bytes.count - 1
-        header |= UInt8(encodingIndex << 6)
-        if size >= fieldNameSizeThreshold {
-            header |= 0b0011_1100
-            buffer.writeUInt8(header)
-            buffer.writeVarUInt32(UInt32(size - fieldNameSizeThreshold))
-        } else {
-            header |= UInt8(size << 2)
-            buffer.writeUInt8(header)
+            fieldType.write(buffer, writeFlags: false)
+            buffer.writeBytes(encoded.bytes)
         }
 
-        fieldType.write(buffer, writeFlags: false)
-        buffer.writeBytes(encoded.bytes)
-    }
+        fileprivate static func read(_ buffer: ByteBuffer) throws -> FieldInfo {
+            let header = try buffer.readUInt8()
+            let encodingFlags = Int((header >> 6) & 0b11)
+            var size = Int((header >> 2) & 0b1111)
+            if size == fieldNameSizeThreshold {
+                size += Int(try buffer.readVarUInt32())
+            }
+            size += 1
+
+            let nullable = (header & 0b10) != 0
+            let trackRef = (header & 0b1) != 0
+            let fieldType = try FieldType.read(
+                buffer,
+                readFlags: false,
+                nullable: nullable,
+                trackRef: trackRef
+            )
 
-    fileprivate static func read(_ buffer: ByteBuffer) throws -> TypeMetaFieldInfo {
-        let header = try buffer.readUInt8()
-        let encodingFlags = Int((header >> 6) & 0b11)
-        var size = Int((header >> 2) & 0b1111)
-        if size == fieldNameSizeThreshold {
-            size += Int(try buffer.readVarUInt32())
-        }
-        size += 1
-
-        let nullable = (header & 0b10) != 0
-        let trackRef = (header & 0b1) != 0
-        let fieldType = try TypeMetaFieldType.read(
-            buffer,
-            readFlags: false,
-            nullable: nullable,
-            trackRef: trackRef
-        )
+            if encodingFlags == 3 {
+                let fieldID = Int16(size - 1)
+                return FieldInfo(
+                    fieldID: fieldID,
+                    fieldName: "$tag\(fieldID)",
+                    fieldType: fieldType
+                )
+            }
 
-        if encodingFlags == 3 {
-            let fieldID = Int16(size - 1)
-            return TypeMetaFieldInfo(
-                fieldID: fieldID,
-                fieldName: "$tag\(fieldID)",
-                fieldType: fieldType
-            )
-        }
+            guard encodingFlags < fieldNameMetaStringEncodings.count else {
+                throw ForyError.invalidData("invalid field name encoding id")
+            }
+            let nameBytes = try buffer.readBytes(count: size)
+            let name = try MetaStringDecoder.fieldName
+                .decode(bytes: nameBytes, encoding: fieldNameMetaStringEncodings[encodingFlags])
+                .value
 
-        guard encodingFlags < fieldNameMetaStringEncodings.count else {
-            throw ForyError.invalidData("invalid field name encoding id")
+            return FieldInfo(fieldID: nil, fieldName: name, fieldType: fieldType)
         }
-        let nameBytes = try buffer.readBytes(count: size)
-        let name = try MetaStringDecoder.fieldName
-            .decode(bytes: nameBytes, encoding: fieldNameMetaStringEncodings[encodingFlags])
-            .value
-
-        return TypeMetaFieldInfo(fieldID: nil, fieldName: name, fieldType: fieldType)
     }
-}
 
-public struct TypeMeta: Equatable, Sendable {
     public let typeID: UInt32?
     public let userTypeID: UInt32?
     public let namespace: MetaString
     public let typeName: MetaString
     public let registerByName: Bool
-    public let fields: [TypeMetaFieldInfo]
+    public let fields: [FieldInfo]
     public let hasFieldsMeta: Bool
     public let compressed: Bool
     public let headerHash: UInt64
@@ -266,7 +267,7 @@ public struct TypeMeta: Equatable, Sendable {
         namespace: MetaString,
         typeName: MetaString,
         registerByName: Bool,
-        fields: [TypeMetaFieldInfo],
+        fields: [FieldInfo],
         hasFieldsMeta: Bool = true,
         compressed: Bool = false,
         headerHash: UInt64 = 0
@@ -295,6 +296,18 @@ public struct TypeMeta: Equatable, Sendable {
         self.headerHash = headerHash
     }
 
+    public static func == (lhs: TypeMeta, rhs: TypeMeta) -> Bool {
+        lhs.typeID == rhs.typeID &&
+            lhs.userTypeID == rhs.userTypeID &&
+            lhs.namespace == rhs.namespace &&
+            lhs.typeName == rhs.typeName &&
+            lhs.registerByName == rhs.registerByName &&
+            lhs.fields == rhs.fields &&
+            lhs.hasFieldsMeta == rhs.hasFieldsMeta &&
+            lhs.compressed == rhs.compressed &&
+            lhs.headerHash == rhs.headerHash
+    }
+
     public func encode() throws -> [UInt8] {
         if compressed {
             throw ForyError.encodingError("compressed TypeMeta is not supported yet")
@@ -321,7 +334,7 @@ public struct TypeMeta: Equatable, Sendable {
             buffer.writeVarUInt32(UInt32(body.count - Int(typeMetaSizeMask)))
         }
         buffer.writeBytes(body)
-        return buffer.storage
+        return Array(buffer.storage.prefix(buffer.count))
     }
 
     public static func decode(_ bytes: [UInt8]) throws -> TypeMeta {
@@ -371,7 +384,7 @@ public struct TypeMeta: Equatable, Sendable {
             typeName = MetaString.empty(specialChar1: "$", specialChar2: "_")
         }
 
-        var fieldInfos: [TypeMetaFieldInfo] = []
+        var fieldInfos: [FieldInfo] = []
         if numFields > bodyReader.remaining {
             throw ForyError.invalidData(
                 "type meta field count \(numFields) exceeds remaining bytes \(bodyReader.remaining)"
@@ -379,7 +392,7 @@ public struct TypeMeta: Equatable, Sendable {
         }
         fieldInfos.reserveCapacity(numFields)
         for _ in 0..<numFields {
-            fieldInfos.append(try TypeMetaFieldInfo.read(bodyReader))
+            fieldInfos.append(try FieldInfo.read(bodyReader))
         }
 
         if bodyReader.remaining != 0 {
@@ -430,7 +443,7 @@ public struct TypeMeta: Equatable, Sendable {
             try field.write(buffer)
         }
 
-        return buffer.storage
+        return Array(buffer.storage.prefix(buffer.count))
     }
 
     private static func writeName(
@@ -485,6 +498,134 @@ public struct TypeMeta: Equatable, Sendable {
         let bytes = try buffer.readBytes(count: length)
         return try decoder.decode(bytes: bytes, encoding: encodings[encodingIndex])
     }
+
+    func assigningFieldIDs(from localTypeMeta: TypeMeta) throws -> TypeMeta {
+        guard !fields.isEmpty else {
+            return self
+        }
+
+        let localFields = localTypeMeta.fields
+        guard !localFields.isEmpty else {
+            return self
+        }
+
+        var fieldIndexByName: [String: (Int, FieldInfo)] = [:]
+        var fieldIndexByID: [Int16: (Int, FieldInfo)] = [:]
+        fieldIndexByName.reserveCapacity(localFields.count)
+        fieldIndexByID.reserveCapacity(localFields.count)
+
+        for (index, localField) in localFields.enumerated() {
+            fieldIndexByName[toSnakeCase(localField.fieldName)] = (index, localField)
+            if let fieldID = localField.fieldID, fieldID >= 0 {
+                fieldIndexByID[fieldID] = (index, localField)
+            }
+        }
+
+        var resolvedFields = fields
+        var changed = false
+        var usedLocalFields = Array(repeating: false, count: localFields.count)
+
+        for index in resolvedFields.indices {
+            let field = resolvedFields[index]
+
+            var localMatch: (Int, FieldInfo)?
+            if let fieldID = field.fieldID, fieldID >= 0 {
+                localMatch = fieldIndexByID[fieldID]
+            }
+
+            if localMatch == nil {
+                if let candidate = fieldIndexByName[toSnakeCase(field.fieldName)],
+                   Self.isCompatibleFieldType(field.fieldType, candidate.1.fieldType) {
+                    localMatch = candidate
+                }
+            }
+
+            if localMatch == nil {
+                for localIndex in localFields.indices where !usedLocalFields[localIndex] {
+                    if Self.isCompatibleFieldType(field.fieldType, localFields[localIndex].fieldType) {
+                        localMatch = (localIndex, localFields[localIndex])
+                        break
+                    }
+                }
+            }
+
+            guard let (sortedIndex, _) = localMatch,
+                  sortedIndex <= Int(Int16.max) else {
+                if field.fieldID != -1 {
+                    resolvedFields[index].fieldID = -1
+                    changed = true
+                }
+                continue
+            }
+
+            let resolvedFieldID = Int16(sortedIndex)
+            if field.fieldID != resolvedFieldID {
+                resolvedFields[index].fieldID = resolvedFieldID
+                changed = true
+            }
+            usedLocalFields[sortedIndex] = true
+        }
+
+        guard changed else {
+            return self
+        }
+
+        return try TypeMeta(
+            typeID: typeID,
+            userTypeID: userTypeID,
+            namespace: namespace,
+            typeName: typeName,
+            registerByName: registerByName,
+            fields: resolvedFields,
+            hasFieldsMeta: hasFieldsMeta,
+            compressed: compressed,
+            headerHash: headerHash
+        )
+    }
+
+    private static func isCompatibleFieldType(
+        _ remoteType: FieldType,
+        _ localType: FieldType
+    ) -> Bool {
+        if normalizeCompatibleTypeIDForComparison(remoteType.typeID) != normalizeCompatibleTypeIDForComparison(localType.typeID) {
+            return false
+        }
+        if remoteType.generics.count != localType.generics.count {
+            return false
+        }
+        for (remoteGeneric, localGeneric) in zip(remoteType.generics, localType.generics)
+        where !isCompatibleFieldType(remoteGeneric, localGeneric) {
+            return false
+        }
+        return true
+    }
+
+    private static func normalizeCompatibleTypeIDForComparison(_ typeID: UInt32) -> UInt32 {
+        switch typeID {
+        case TypeId.structType.rawValue,
+             TypeId.compatibleStruct.rawValue,
+             TypeId.namedStruct.rawValue,
+             TypeId.namedCompatibleStruct.rawValue,
+             TypeId.unknown.rawValue:
+            return TypeId.structType.rawValue
+        case TypeId.enumType.rawValue,
+             TypeId.namedEnum.rawValue:
+            return TypeId.enumType.rawValue
+        case TypeId.ext.rawValue,
+             TypeId.namedExt.rawValue:
+            return TypeId.ext.rawValue
+        case TypeId.binary.rawValue,
+             TypeId.int8Array.rawValue,
+             TypeId.uint8Array.rawValue:
+            return TypeId.binary.rawValue
+        case TypeId.union.rawValue,
+             TypeId.typedUnion.rawValue,
+             TypeId.namedUnion.rawValue:
+            return TypeId.union.rawValue
+        default:
+            return typeID
+        }
+    }
 }
 
 private func lowerCamelToLowerUnderscore(_ name: String) -> String {
@@ -513,3 +654,30 @@ private func lowerCamelToLowerUnderscore(_ name: String) -> String {
 
     return result
 }
+
+private func toSnakeCase(_ name: String) -> String {
+    if name.isEmpty {
+        return name
+    }
+
+    let chars = Array(name)
+    var result = String()
+    result.reserveCapacity(name.count + 4)
+
+    for (index, char) in chars.enumerated() {
+        if char.isUppercase {
+            if index > 0 {
+                let prevUpper = chars[index - 1].isUppercase
+                let nextUpperOrEnd = (index + 1 >= chars.count) || chars[index + 1].isUppercase
+                if !prevUpper || !nextUpperOrEnd {
+                    result.append("_")
+                }
+            }
+            result.append(char.lowercased())
+        } else {
+            result.append(char)
+        }
+    }
+
+    return result
+}
diff --git a/swift/Sources/Fory/TypeResolver.swift b/swift/Sources/Fory/TypeResolver.swift
index 1726ba2bf..dc734180c 100644
--- a/swift/Sources/Fory/TypeResolver.swift
+++ b/swift/Sources/Fory/TypeResolver.swift
@@ -17,25 +17,326 @@
 
 import Foundation
 
-public struct RegisteredTypeInfo: Equatable {
-    public let userTypeID: UInt32?
-    public let kind: TypeId
-    public let registerByName: Bool
-    public let namespace: MetaString?
-    public let typeName: MetaString
-
-    public init(
+@inline(__always)
+func normalizeRegisteredTypeID(_ typeID: TypeId) -> TypeId {
+    switch typeID {
+    case .namedEnum:
+        return .enumType
+    case .compatibleStruct, .namedCompatibleStruct, .namedStruct:
+        return .structType
+    case .namedExt:
+        return .ext
+    case .namedUnion, .union:
+        return .typedUnion
+    default:
+        return typeID
+    }
+}
+
+@inline(__always)
+func namedRegisteredTypeID(for baseTypeID: TypeId, compatible: Bool) -> TypeId {
+    switch baseTypeID {
+    case .structType:
+        return compatible ? .namedCompatibleStruct : .namedStruct
+    case .enumType:
+        return .namedEnum
+    case .ext:
+        return .namedExt
+    case .typedUnion:
+        return .namedUnion
+    default:
+        return baseTypeID
+    }
+}
+
+@inline(__always)
+func idRegisteredTypeID(for baseTypeID: TypeId, compatible: Bool) -> TypeId {
+    switch baseTypeID {
+    case .structType:
+        return compatible ? .compatibleStruct : .structType
+    default:
+        return baseTypeID
+    }
+}
+
+@inline(__always)
+func resolveRegisteredWireTypeID(
+    declaredTypeID: TypeId,
+    registerByName: Bool,
+    compatible: Bool
+) -> TypeId {
+    let baseTypeID = normalizeRegisteredTypeID(declaredTypeID)
+    if registerByName {
+        return namedRegisteredTypeID(for: baseTypeID, compatible: compatible)
+    }
+    return idRegisteredTypeID(for: baseTypeID, compatible: compatible)
+}
+
+@inline(__always)
+func isAllowedRegisteredWireTypeID(
+    _ wireTypeID: TypeId,
+    declaredTypeID: TypeId,
+    registerByName: Bool,
+    compatible: Bool
+) -> Bool {
+    let baseTypeID = normalizeRegisteredTypeID(declaredTypeID)
+    let expected = resolveRegisteredWireTypeID(
+        declaredTypeID: declaredTypeID,
+        registerByName: registerByName,
+        compatible: compatible
+    )
+    if wireTypeID == expected {
+        return true
+    }
+    if baseTypeID == .structType, compatible {
+        return wireTypeID == .compatibleStruct ||
+            wireTypeID == .namedCompatibleStruct ||
+            wireTypeID == .structType ||
+            wireTypeID == .namedStruct
+    }
+    if baseTypeID == .typedUnion {
+        return wireTypeID == .union || (registerByName && wireTypeID == .namedUnion)
+    }
+    return false
+}
+
+@inline(__always)
+func registeredWireTypeNeedsUserTypeID(_ wireTypeID: TypeId) -> Bool {
+    switch wireTypeID {
+    case .enumType, .structType, .ext, .typedUnion, .union:
+        return true
+    default:
+        return false
+    }
+}
+
+@inline(__always)
+private func encodedTypeDefHeader(_ bytes: [UInt8]) throws -> UInt64 {
+    guard bytes.count >= 8 else {
+        throw ForyError.invalidData("encoded compatible type metadata must include an 8-byte header")
+    }
+    let buffer = ByteBuffer(bytes: bytes)
+    return try buffer.readUInt64()
+}
+
+@inline(__always)
+private func encodedTypeDefHeaderHash(_ bytes: [UInt8]) throws -> UInt64 {
+    guard bytes.count >= 8 else {
+        throw ForyError.invalidData("encoded compatible type metadata must include an 8-byte header")
+    }
+    let buffer = ByteBuffer(bytes: bytes)
+    let header = try buffer.readUInt64()
+    return header >> 14
+}
+
+private func fieldNeedsTypeInfo(_ fieldType: TypeMeta.FieldType) -> Bool {
+    if let typeID = TypeId(rawValue: fieldType.typeID),
+       TypeId.needsTypeInfoForField(typeID) {
+        return true
+    }
+    return fieldType.generics.contains { fieldNeedsTypeInfo($0) }
+}
+
+private func encodedTypeDefHasUserTypeFields(_ fields: [TypeMeta.FieldInfo]) -> Bool {
+    fields.contains { fieldNeedsTypeInfo($0.fieldType) }
+}
+
+public final class TypeInfo: @unchecked Sendable {
+    static let uncached = TypeInfo(typeID: .unknown)
+
+    let swiftTypeID: ObjectIdentifier
+    let typeID: TypeId
+    let userTypeID: UInt32?
+    let registerByName: Bool
+    let namespace: MetaString
+    let typeName: MetaString
+    let typeMeta: TypeMeta?
+    public let compatibleTypeMeta: TypeMeta?
+    let typeDefBytes: [UInt8]?
+    let firstTypeDefBytes: [UInt8]?
+    let typeDefHeader: UInt64?
+    public let typeDefHeaderHash: UInt64?
+    public let typeDefHasUserTypeFields: Bool
+
+    private let reader: (ReadContext) throws -> Any
+    private let compatibleReader: (ReadContext, TypeInfo) throws -> Any
+    private let nativeWireTypeID: TypeId
+    private let compatibleWireTypeID: TypeId
+
+    init(
+        swiftTypeID: ObjectIdentifier,
+        typeID: TypeId,
         userTypeID: UInt32?,
-        kind: TypeId,
         registerByName: Bool,
-        namespace: MetaString?,
-        typeName: MetaString
+        namespace: MetaString,
+        typeName: MetaString,
+        typeMeta: TypeMeta? = nil,
+        compatibleTypeMeta: TypeMeta? = nil,
+        typeDefBytes: [UInt8]? = nil,
+        firstTypeDefBytes: [UInt8]? = nil,
+        typeDefHeader: UInt64? = nil,
+        typeDefHeaderHash: UInt64? = nil,
+        typeDefHasUserTypeFields: Bool = true,
+        reader: @escaping (ReadContext) throws -> Any,
+        compatibleReader: @escaping (ReadContext, TypeInfo) throws -> Any
     ) {
+        self.swiftTypeID = swiftTypeID
+        self.typeID = typeID
         self.userTypeID = userTypeID
-        self.kind = kind
         self.registerByName = registerByName
         self.namespace = namespace
         self.typeName = typeName
+        self.typeMeta = typeMeta
+        self.compatibleTypeMeta = compatibleTypeMeta ?? typeMeta
+        self.typeDefBytes = typeDefBytes
+        self.firstTypeDefBytes = firstTypeDefBytes
+        self.typeDefHeader = typeDefHeader
+        self.typeDefHeaderHash = typeDefHeaderHash
+        self.typeDefHasUserTypeFields = typeDefHasUserTypeFields
+        self.reader = reader
+        self.compatibleReader = compatibleReader
+        nativeWireTypeID = resolveRegisteredWireTypeID(
+            declaredTypeID: typeID,
+            registerByName: registerByName,
+            compatible: false
+        )
+        compatibleWireTypeID = resolveRegisteredWireTypeID(
+            declaredTypeID: typeID,
+            registerByName: registerByName,
+            compatible: true
+        )
+    }
+
+    convenience init(
+        swiftTypeID: ObjectIdentifier,
+        typeID: TypeId,
+        userTypeID: UInt32?,
+        registerByName: Bool,
+        namespace: MetaString,
+        typeName: MetaString,
+        fields: [TypeMeta.FieldInfo],
+        reader: @escaping (ReadContext) throws -> Any,
+        compatibleReader: @escaping (ReadContext, TypeInfo) throws -> Any
+    ) throws {
+        let compatibleWireTypeID = resolveRegisteredWireTypeID(
+            declaredTypeID: typeID,
+            registerByName: registerByName,
+            compatible: true
+        )
+        let typeMeta = try TypeMeta(
+            typeID: registerByName ? nil : compatibleWireTypeID.rawValue,
+            userTypeID: registerByName ? nil : userTypeID,
+            namespace: namespace,
+            typeName: typeName,
+            registerByName: registerByName,
+            fields: fields,
+            hasFieldsMeta: !fields.isEmpty
+        )
+        let typeDefBytes = try typeMeta.encode()
+        var firstTypeDefBytes = [UInt8]()
+        firstTypeDefBytes.reserveCapacity(typeDefBytes.count + 1)
+        firstTypeDefBytes.append(0)
+        firstTypeDefBytes.append(contentsOf: typeDefBytes)
+        let typeDefHeader = try encodedTypeDefHeader(typeDefBytes)
+        let typeDefHeaderHash = try encodedTypeDefHeaderHash(typeDefBytes)
+        let canonicalTypeMeta = try TypeMeta(
+            typeID: registerByName ? nil : compatibleWireTypeID.rawValue,
+            userTypeID: registerByName ? nil : userTypeID,
+            namespace: namespace,
+            typeName: typeName,
+            registerByName: registerByName,
+            fields: fields,
+            hasFieldsMeta: !fields.isEmpty,
+            headerHash: typeDefHeaderHash
+        )
+        self.init(
+            swiftTypeID: swiftTypeID,
+            typeID: typeID,
+            userTypeID: userTypeID,
+            registerByName: registerByName,
+            namespace: namespace,
+            typeName: typeName,
+            typeMeta: canonicalTypeMeta,
+            compatibleTypeMeta: canonicalTypeMeta,
+            typeDefBytes: typeDefBytes,
+            firstTypeDefBytes: firstTypeDefBytes,
+            typeDefHeader: typeDefHeader,
+            typeDefHeaderHash: typeDefHeaderHash,
+            typeDefHasUserTypeFields: encodedTypeDefHasUserTypeFields(fields),
+            reader: reader,
+            compatibleReader: compatibleReader
+        )
+    }
+
+    convenience init(typeID: TypeId) {
+        self.init(
+            swiftTypeID: ObjectIdentifier(TypeInfo.self),
+            typeID: typeID,
+            userTypeID: nil,
+            registerByName: false,
+            namespace: MetaString.empty(specialChar1: ".", specialChar2: "_"),
+            typeName: MetaString.empty(specialChar1: "$", specialChar2: "_"),
+            reader: { _ in
+                throw ForyError.invalidData("dynamic type \(typeID) uses runtime-only decode path")
+            },
+            compatibleReader: { _, _ in
+                throw ForyError.invalidData("dynamic compatible type \(typeID) uses runtime-only decode path")
+            }
+        )
+    }
+
+    convenience init(dynamic typeInfo: TypeInfo, compatibleTypeMeta: TypeMeta) {
+        self.init(
+            swiftTypeID: typeInfo.swiftTypeID,
+            typeID: typeInfo.typeID,
+            userTypeID: typeInfo.userTypeID,
+            registerByName: typeInfo.registerByName,
+            namespace: typeInfo.namespace,
+            typeName: typeInfo.typeName,
+            typeMeta: typeInfo.typeMeta,
+            compatibleTypeMeta: compatibleTypeMeta,
+            typeDefBytes: typeInfo.typeDefBytes,
+            firstTypeDefBytes: typeInfo.firstTypeDefBytes,
+            typeDefHeader: typeInfo.typeDefHeader,
+            typeDefHeaderHash: typeInfo.typeDefHeaderHash,
+            typeDefHasUserTypeFields: typeInfo.typeDefHasUserTypeFields,
+            reader: typeInfo.reader,
+            compatibleReader: typeInfo.compatibleReader
+        )
+    }
+
+    @inline(__always)
+    func matches(
+        typeID: TypeId,
+        userTypeID: UInt32?,
+        registerByName: Bool,
+        namespace: String,
+        typeName: String
+    ) -> Bool {
+        self.typeID == typeID &&
+            self.userTypeID == userTypeID &&
+            self.registerByName == registerByName &&
+            self.namespace.value == namespace &&
+            self.typeName.value == typeName
+    }
+
+    @inline(__always)
+    func wireTypeID(compatible: Bool) -> TypeId {
+        compatible ? compatibleWireTypeID : nativeWireTypeID
+    }
+
+    @inline(__always)
+    func read(_ context: ReadContext, typeInfo: TypeInfo? = nil) throws -> Any {
+        if let typeInfo {
+            return try compatibleReader(context, typeInfo)
+        }
+        if context.compatible {
+            return try compatibleReader(context, self)
+        }
+        if compatibleTypeMeta !== typeMeta {
+            return try compatibleReader(context, self)
+        }
+        return try reader(context)
     }
 }
 
@@ -44,28 +345,20 @@ private struct TypeNameKey: Hashable {
     let typeName: String
 }
 
-private enum DynamicRegistrationMode {
-    case idOnly
-    case nameOnly
-    case mixed
-}
+final class TypeResolver {
+    private let trackRef: Bool
 
-private struct TypeReader {
-    let swiftType: ObjectIdentifier
-    let kind: TypeId
-    let reader: (ReadContext) throws -> Any
-    let compatibleReader: (ReadContext, TypeMeta) throws -> Any
-}
+    private var bySwiftType = UInt64Map<TypeInfo>(initialCapacity: 64)
+    private var byUserTypeID = UInt64Map<TypeInfo>(initialCapacity: 64)
+    private var byTypeName: [TypeNameKey: TypeInfo] = [:]
+    private var builtinTypeInfoByID: [TypeInfo?] = []
+    private var typeInfoByHeader = UInt64Map<TypeInfo>(initialCapacity: 64)
 
-public final class TypeResolver {
-    private var bySwiftType: [ObjectIdentifier: RegisteredTypeInfo] = [:]
-    private var byUserTypeID: [UInt32: TypeReader] = [:]
-    private var byTypeName: [TypeNameKey: TypeReader] = [:]
-    private var registrationModeByKind: [TypeId: DynamicRegistrationMode] = [:]
-
-    public init() {}
+    init(trackRef: Bool = false) {
+        self.trackRef = trackRef
+    }
 
-    public func register<T: Serializer>(_ type: T.Type, id: UInt32) {
+    func register<T: Serializer>(_ type: T.Type, id: UInt32) {
         do {
             try registerByID(type, id: id)
         } catch {
@@ -74,34 +367,40 @@ public final class TypeResolver {
     }
 
     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(
+        let swiftTypeID = ObjectIdentifier(type)
+        try validateIDRegistration(key: swiftTypeID, type: type, id: id)
+
+        let typeInfo = try TypeInfo(
+            swiftTypeID: swiftTypeID,
+            typeID: T.staticTypeId,
             userTypeID: id,
-            kind: T.staticTypeId,
             registerByName: false,
-            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,
+            namespace: MetaString.empty(specialChar1: ".", specialChar2: "_"),
+            typeName: MetaString.empty(specialChar1: "$", specialChar2: "_"),
+            fields: T.foryFieldsInfo(trackRef: trackRef),
             reader: { context in
                 try T.foryRead(context, refMode: .none, readTypeInfo: false)
             },
-            compatibleReader: { context, typeMeta in
-                context.pushCompatibleTypeMeta(for: T.self, typeMeta)
-                return try T.foryRead(context, refMode: .none, readTypeInfo: false)
+            compatibleReader: { context, remoteTypeInfo in
+                try T.foryReadCompatibleData(context, remoteTypeInfo: remoteTypeInfo)
             }
         )
+
+        if let existing = bySwiftType.value(for: UInt64(UInt(bitPattern: swiftTypeID))),
+           existing.matches(
+               typeID: T.staticTypeId,
+               userTypeID: id,
+               registerByName: false,
+               namespace: "",
+               typeName: ""
+           ) {
+            return
+        }
+
+        try store(typeInfo, for: swiftTypeID, userTypeID: id)
     }
 
-    public func register<T: Serializer>(_ type: T.Type, namespace: String, typeName: String) throws {
+    func register<T: Serializer>(_ type: T.Type, namespace: String, typeName: String) throws {
         let namespaceMeta = try MetaStringEncoder.namespace.encode(
             namespace,
             allowedEncodings: namespaceMetaStringEncodings
@@ -110,39 +409,45 @@ public final class TypeResolver {
             typeName,
             allowedEncodings: typeNameMetaStringEncodings
         )
-        let key = ObjectIdentifier(type)
+        let swiftTypeID = ObjectIdentifier(type)
         try validateNameRegistration(
-            key: key,
+            key: swiftTypeID,
             type: type,
             namespace: namespace,
             typeName: typeName
         )
-        let info = RegisteredTypeInfo(
+
+        let typeInfo = try TypeInfo(
+            swiftTypeID: swiftTypeID,
+            typeID: T.staticTypeId,
             userTypeID: nil,
-            kind: T.staticTypeId,
             registerByName: true,
             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,
+            typeName: typeNameMeta,
+            fields: T.foryFieldsInfo(trackRef: trackRef),
             reader: { context in
                 try T.foryRead(context, refMode: .none, readTypeInfo: false)
             },
-            compatibleReader: { context, typeMeta in
-                context.pushCompatibleTypeMeta(for: T.self, typeMeta)
-                return try T.foryRead(context, refMode: .none, readTypeInfo: false)
+            compatibleReader: { context, remoteTypeInfo in
+                try T.foryReadCompatibleData(context, remoteTypeInfo: remoteTypeInfo)
             }
         )
+
+        if let existing = bySwiftType.value(for: UInt64(UInt(bitPattern: swiftTypeID))),
+           existing.matches(
+               typeID: T.staticTypeId,
+               userTypeID: nil,
+               registerByName: true,
+               namespace: namespace,
+               typeName: typeName
+           ) {
+            return
+        }
+
+        try store(typeInfo, for: swiftTypeID, typeNameKey: TypeNameKey(namespace: namespace, typeName: typeName))
     }
 
-    public func register<T: Serializer>(_ type: T.Type, name: String) throws {
+    func register<T: Serializer>(_ type: T.Type, name: String) throws {
         let parts = name.components(separatedBy: ".")
         if parts.count <= 1 {
             try register(type, namespace: "", typeName: name)
@@ -154,301 +459,93 @@ public final class TypeResolver {
         try register(type, namespace: resolvedNamespace, typeName: resolvedTypeName)
     }
 
-    public func registeredTypeInfo<T: Serializer>(for type: T.Type) -> RegisteredTypeInfo? {
-        bySwiftType[ObjectIdentifier(type)]
-    }
-
-    public func registeredTypeInfo(for type: any Serializer.Type) -> RegisteredTypeInfo? {
-        bySwiftType[ObjectIdentifier(type)]
-    }
-
-    public func requireRegisteredTypeInfo<T: Serializer>(for type: T.Type) throws -> RegisteredTypeInfo {
-        if let info = bySwiftType[ObjectIdentifier(type)] {
+    func requireTypeInfo<T: Serializer>(for type: T.Type) throws -> TypeInfo {
+        if let info = bySwiftType.value(for: UInt64(UInt(bitPattern: ObjectIdentifier(type)))) {
             return info
         }
         throw ForyError.typeNotRegistered("\(type) is not registered")
     }
 
-    public func readByUserTypeID(_ userTypeID: UInt32, context: ReadContext) throws -> Any {
-        try readByUserTypeID(userTypeID, context: context, compatibleTypeMeta: nil)
+    @inline(__always)
+    func getTypeInfo(forHeader header: UInt64) -> TypeInfo? {
+        typeInfoByHeader.value(for: header)
     }
 
-    public func readByUserTypeID(
-        _ userTypeID: UInt32,
-        context: ReadContext,
-        compatibleTypeMeta: TypeMeta?
-    ) throws -> Any {
-        guard let entry = byUserTypeID[userTypeID] else {
-            throw ForyError.typeNotRegistered("user_type_id=\(userTypeID)")
-        }
-        if let compatibleTypeMeta {
-            return try entry.compatibleReader(context, compatibleTypeMeta)
+    @inline(__always)
+    func cacheTypeInfo(_ typeMeta: TypeMeta, forHeader header: UInt64) throws -> TypeInfo {
+        if let cached = typeInfoByHeader.value(for: header) {
+            return cached
         }
-        return try entry.reader(context)
-    }
-
-    public func readByTypeName(namespace: String, typeName: String, context: ReadContext) throws -> Any {
-        try readByTypeName(namespace: namespace, typeName: typeName, context: context, compatibleTypeMeta: nil)
-    }
-
-    public func readByTypeName(
-        namespace: String,
-        typeName: String,
-        context: ReadContext,
-        compatibleTypeMeta: TypeMeta?
-    ) throws -> Any {
-        guard let entry = byTypeName[TypeNameKey(namespace: namespace, typeName: typeName)] else {
-            throw ForyError.typeNotRegistered("namespace=\(namespace), type=\(typeName)")
+        let localTypeInfo = try requireTypeInfo(for: typeMeta)
+        if header == localTypeInfo.typeDefHeader {
+            typeInfoByHeader.set(localTypeInfo, for: header)
+            return localTypeInfo
         }
-        if let compatibleTypeMeta {
-            return try entry.compatibleReader(context, compatibleTypeMeta)
+        let canonicalTypeMeta: TypeMeta
+        if let localTypeMeta = localTypeInfo.typeMeta,
+           let remapped = try? typeMeta.assigningFieldIDs(from: localTypeMeta) {
+            canonicalTypeMeta = remapped
+        } else {
+            canonicalTypeMeta = typeMeta
         }
-        return try entry.reader(context)
+        let typeInfo = TypeInfo(dynamic: localTypeInfo, compatibleTypeMeta: canonicalTypeMeta)
+        typeInfoByHeader.set(typeInfo, for: header)
+        return typeInfo
     }
 
-    public func readDynamicTypeInfo(context: ReadContext) throws -> DynamicTypeInfo {
-        let rawTypeID = try context.buffer.readVarUInt32()
-        guard let wireTypeID = TypeId(rawValue: rawTypeID) else {
-            throw ForyError.invalidData("unknown dynamic type id \(rawTypeID)")
+    private func store(
+        _ typeInfo: TypeInfo,
+        for swiftTypeID: ObjectIdentifier,
+        userTypeID: UInt32? = nil,
+        typeNameKey: TypeNameKey? = nil
+    ) throws {
+        bySwiftType.set(typeInfo, for: UInt64(UInt(bitPattern: swiftTypeID)))
+        if let userTypeID {
+            byUserTypeID.set(typeInfo, for: UInt64(userTypeID))
         }
-
-        switch wireTypeID {
-        case .compatibleStruct, .namedCompatibleStruct:
-            let typeMeta = try context.readCompatibleTypeMeta()
-            if typeMeta.registerByName {
-                return DynamicTypeInfo(
-                    wireTypeID: wireTypeID,
-                    userTypeID: nil,
-                    namespace: typeMeta.namespace,
-                    typeName: typeMeta.typeName,
+        if let typeNameKey {
+            byTypeName[typeNameKey] = typeInfo
+        }
+        if let typeMeta = typeInfo.typeMeta,
+           let typeDefHeader = typeInfo.typeDefHeader {
+            typeInfoByHeader.set(
+                TypeInfo(
+                    dynamic: typeInfo,
                     compatibleTypeMeta: typeMeta
-                )
-            }
-            return DynamicTypeInfo(
-                wireTypeID: wireTypeID,
-                userTypeID: typeMeta.userTypeID,
-                namespace: nil,
-                typeName: nil,
-                compatibleTypeMeta: typeMeta
-            )
-        case .namedStruct, .namedEnum, .namedExt, .namedUnion:
-            let namespace = try Self.readMetaString(
-                buffer: context.buffer,
-                decoder: .namespace,
-                encodings: namespaceMetaStringEncodings
-            )
-            let typeName = try Self.readMetaString(
-                buffer: context.buffer,
-                decoder: .typeName,
-                encodings: typeNameMetaStringEncodings
-            )
-            return DynamicTypeInfo(
-                wireTypeID: wireTypeID,
-                userTypeID: nil,
-                namespace: namespace,
-                typeName: typeName,
-                compatibleTypeMeta: nil
-            )
-        case .structType, .enumType, .ext, .typedUnion, .union:
-            let registrationKind: TypeId = wireTypeID == .union ? .typedUnion : wireTypeID
-            switch try dynamicRegistrationMode(for: registrationKind) {
-            case .idOnly:
-                return DynamicTypeInfo(
-                    wireTypeID: wireTypeID,
-                    userTypeID: try context.buffer.readVarUInt32(),
-                    namespace: nil,
-                    typeName: nil,
-                    compatibleTypeMeta: nil
-                )
-            case .nameOnly:
-                let namespace = try Self.readMetaString(
-                    buffer: context.buffer,
-                    decoder: .namespace,
-                    encodings: namespaceMetaStringEncodings
-                )
-                let typeName = try Self.readMetaString(
-                    buffer: context.buffer,
-                    decoder: .typeName,
-                    encodings: typeNameMetaStringEncodings
-                )
-                return DynamicTypeInfo(
-                    wireTypeID: wireTypeID,
-                    userTypeID: nil,
-                    namespace: namespace,
-                    typeName: typeName,
-                    compatibleTypeMeta: nil
-                )
-            case .mixed:
-                // 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(
-                wireTypeID: wireTypeID,
-                userTypeID: nil,
-                namespace: nil,
-                typeName: nil,
-                compatibleTypeMeta: nil
+                ),
+                for: typeDefHeader
             )
         }
     }
 
-    public func readDynamicValue(typeInfo: DynamicTypeInfo, context: ReadContext) throws -> Any {
-        try context.enterDynamicAnyDepth()
-        defer { context.leaveDynamicAnyDepth() }
-
-        let value: Any
-        switch typeInfo.wireTypeID {
-        case .bool:
-            value = try Bool.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int8:
-            value = try Int8.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int16:
-            value = try Int16.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int32:
-            value = try ForyInt32Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .varint32:
-            value = try Int32.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int64:
-            value = try ForyInt64Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .varint64:
-            value = try Int64.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .taggedInt64:
-            value = try ForyInt64Tagged.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .uint8:
-            value = try UInt8.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .uint16:
-            value = try UInt16.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .uint32:
-            value = try ForyUInt32Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .varUInt32:
-            value = try UInt32.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .uint64:
-            value = try ForyUInt64Fixed.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .varUInt64:
-            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:
-            value = try ForyDate.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .binary, .uint8Array:
-            value = try Data.foryRead(context, refMode: .none, readTypeInfo: false)
-        case .boolArray:
-            value = try [Bool].foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int8Array:
-            value = try [Int8].foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int16Array:
-            value = try [Int16].foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int32Array:
-            value = try [Int32].foryRead(context, refMode: .none, readTypeInfo: false)
-        case .int64Array:
-            value = try [Int64].foryRead(context, refMode: .none, readTypeInfo: false)
-        case .uint16Array:
-            value = try [UInt16].foryRead(context, refMode: .none, readTypeInfo: false)
-        case .uint32Array:
-            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 .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, .union:
-            if let userTypeID = typeInfo.userTypeID {
-                value = try readByUserTypeID(userTypeID, context: context)
-            } else if let namespace = typeInfo.namespace, let typeName = typeInfo.typeName {
-                value = try readByTypeName(
-                    namespace: namespace.value,
-                    typeName: typeName.value,
-                    context: context
-                )
-            } else {
-                throw ForyError.invalidData("missing dynamic registration info for \(typeInfo.wireTypeID)")
-            }
-        case .namedStruct, .namedEnum, .namedExt, .namedUnion:
-            guard let namespace = typeInfo.namespace, let typeName = typeInfo.typeName else {
-                throw ForyError.invalidData("missing dynamic type name for \(typeInfo.wireTypeID)")
-            }
-            value = try readByTypeName(
-                namespace: namespace.value,
-                typeName: typeName.value,
-                context: context
-            )
-        case .compatibleStruct, .namedCompatibleStruct:
-            guard let compatibleTypeMeta = typeInfo.compatibleTypeMeta else {
-                throw ForyError.invalidData("missing compatible type meta for \(typeInfo.wireTypeID)")
-            }
-            if compatibleTypeMeta.registerByName {
-                value = try readByTypeName(
-                    namespace: compatibleTypeMeta.namespace.value,
-                    typeName: compatibleTypeMeta.typeName.value,
-                    context: context,
-                    compatibleTypeMeta: compatibleTypeMeta
-                )
-            } else {
-                guard let userTypeID = compatibleTypeMeta.userTypeID else {
-                    throw ForyError.invalidData("missing user type id in compatible dynamic type meta")
-                }
-                value = try readByUserTypeID(
-                    userTypeID,
-                    context: context,
-                    compatibleTypeMeta: compatibleTypeMeta
-                )
-            }
-        case .none:
-            value = ForyAnyNullValue()
-        default:
-            throw ForyError.invalidData("unsupported dynamic type id \(typeInfo.wireTypeID)")
+    @inline(__always)
+    func builtinTypeInfo(for typeID: TypeId) -> TypeInfo {
+        let index = Int(typeID.rawValue)
+        if index < builtinTypeInfoByID.count, let cached = builtinTypeInfoByID[index] {
+            return cached
         }
-        return value
+        let info = TypeInfo(typeID: typeID)
+        if index >= builtinTypeInfoByID.count {
+            builtinTypeInfoByID.append(contentsOf: repeatElement(nil, count: index - builtinTypeInfoByID.count + 1))
+        }
+        builtinTypeInfoByID[index] = info
+        return info
     }
 
-    private func markRegistrationMode(kind: TypeId, registerByName: Bool) {
-        let mode: DynamicRegistrationMode = registerByName ? .nameOnly : .idOnly
-        guard let existing = registrationModeByKind[kind] else {
-            registrationModeByKind[kind] = mode
-            return
-        }
-        if existing != mode {
-            registrationModeByKind[kind] = .mixed
+    @inline(__always)
+    func requireTypeInfo(userTypeID: UInt32) throws -> TypeInfo {
+        guard let typeInfo = byUserTypeID.value(for: UInt64(userTypeID)) else {
+            throw ForyError.typeNotRegistered("user_type_id=\(userTypeID)")
         }
+        return typeInfo
     }
 
-    private func dynamicRegistrationMode(for kind: TypeId) throws -> DynamicRegistrationMode {
-        guard let mode = registrationModeByKind[kind] else {
-            throw ForyError.typeNotRegistered("no dynamic registration mode for kind \(kind)")
+    @inline(__always)
+    func requireTypeInfo(namespace: String, typeName: String) throws -> TypeInfo {
+        guard let typeInfo = byTypeName[TypeNameKey(namespace: namespace, typeName: typeName)] else {
+            throw ForyError.typeNotRegistered("namespace=\(namespace), type=\(typeName)")
         }
-        return mode
+        return typeInfo
     }
 
     private func validateIDRegistration<T: Serializer>(
@@ -456,13 +553,14 @@ public final class TypeResolver {
         type: T.Type,
         id: UInt32
     ) throws {
-        if let existing = bySwiftType[key] {
+        let swiftKey = UInt64(UInt(bitPattern: key))
+        if let existing = bySwiftType.value(for: swiftKey) {
             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 {
+            if existing.typeID != 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)"
@@ -470,7 +568,7 @@ public final class TypeResolver {
             }
         }
 
-        if let existing = byUserTypeID[id], existing.swiftType != key {
+        if let existing = byUserTypeID.value(for: UInt64(id)), existing.swiftTypeID != key {
             throw ForyError.invalidData("user type id \(id) is already registered by another type")
         }
     }
@@ -481,18 +579,18 @@ public final class TypeResolver {
         namespace: String,
         typeName: String
     ) throws {
-        if let existing = bySwiftType[key] {
+        if let existing = bySwiftType.value(for: UInt64(UInt(bitPattern: 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 ||
+            if existing.typeID != T.staticTypeId ||
+                existing.namespace.value != namespace ||
                 existing.typeName.value != typeName {
                 throw ForyError.invalidData(
                     """
-                    \(type) registration conflict: existing name=\(existing.namespace?.value ?? "")::\(existing.typeName.value), \
+                    \(type) registration conflict: existing name=\(existing.namespace.value)::\(existing.typeName.value), \
                     new name=\(namespace)::\(typeName)
                     """
                 )
@@ -500,27 +598,28 @@ public final class TypeResolver {
         }
 
         let nameKey = TypeNameKey(namespace: namespace, typeName: typeName)
-        if let existing = byTypeName[nameKey], existing.swiftType != key {
+        if let existing = byTypeName[nameKey], existing.swiftTypeID != key {
             throw ForyError.invalidData("type name \(namespace)::\(typeName) is already registered by another type")
         }
     }
 
-    private static func readMetaString(
-        buffer: ByteBuffer,
-        decoder: MetaStringDecoder,
-        encodings: [MetaStringEncoding]
-    ) throws -> MetaString {
-        let header = try buffer.readUInt8()
-        let encodingIndex = Int(header & 0b11)
-        guard encodingIndex < encodings.count else {
-            throw ForyError.invalidData("invalid meta string encoding index")
+    @inline(__always)
+    private func requireTypeInfo(for typeMeta: TypeMeta) throws -> TypeInfo {
+        if typeMeta.registerByName {
+            guard let typeInfo = byTypeName[TypeNameKey(namespace: typeMeta.namespace.value, typeName: typeMeta.typeName.value)] else {
+                throw ForyError.typeNotRegistered(
+                    "namespace=\(typeMeta.namespace.value), type=\(typeMeta.typeName.value)"
+                )
+            }
+            return typeInfo
         }
-
-        var length = Int(header >> 2)
-        if length >= 0b11_1111 {
-            length = 0b11_1111 + Int(try buffer.readVarUInt32())
+        if let userTypeID = typeMeta.userTypeID {
+            guard let typeInfo = byUserTypeID.value(for: UInt64(userTypeID)) else {
+                throw ForyError.typeNotRegistered("user_type_id=\(userTypeID)")
+            }
+            return typeInfo
         }
-        let bytes = try buffer.readBytes(count: length)
-        return try decoder.decode(bytes: bytes, encoding: encodings[encodingIndex])
+        throw ForyError.invalidData("missing user type id in compatible dynamic type meta")
     }
+
 }
diff --git a/swift/Sources/Fory/UnsafeUtil.swift b/swift/Sources/Fory/UnsafeUtil.swift
new file mode 100644
index 000000000..ce5d15054
--- /dev/null
+++ b/swift/Sources/Fory/UnsafeUtil.swift
@@ -0,0 +1,1383 @@
+// 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.
+
+import Foundation
+
+// swiftlint:disable type_body_length
+public enum UnsafeUtil {
+    @inlinable
+    @inline(__always)
+    public static func writeBool(
+        _ value: Bool,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        base[index] = value ? 1 : 0
+        return index + 1
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeInt8(
+        _ value: Int8,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        base[index] = UInt8(bitPattern: value)
+        return index + 1
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeUInt8(
+        _ value: UInt8,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        base[index] = value
+        return index + 1
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeInt16(
+        _ value: Int16,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        writeUInt16(UInt16(bitPattern: value), to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeUInt16(
+        _ value: UInt16,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        let little = value.littleEndian
+        base[index] = UInt8(truncatingIfNeeded: little)
+        base[index + 1] = UInt8(truncatingIfNeeded: little >> 8)
+        return index + 2
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeInt32(
+        _ value: Int32,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        let zigzag = UInt32(bitPattern: (value << 1) ^ (value >> 31))
+        return writeVarUInt32(zigzag, to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeInt64(
+        _ value: Int64,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        let zigzag = UInt64(bitPattern: (value << 1) ^ (value >> 63))
+        return writeVarUInt64(zigzag, to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeInt(
+        _ value: Int,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        writeInt64(Int64(value), to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeUInt32(
+        _ value: UInt32,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        writeVarUInt32(value, to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeUInt64(
+        _ value: UInt64,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        writeVarUInt64(value, to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeUInt(
+        _ value: UInt,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        writeVarUInt64(UInt64(value), to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeFloat32(
+        _ value: Float,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        writeFixedUInt32(value.bitPattern, to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeFloat64(
+        _ value: Double,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        writeFixedUInt64(value.bitPattern, to: base, index: index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func varUInt32Size(_ value: UInt32) -> Int {
+        if value < 0x80 {
+            return 1
+        }
+        if value < 0x4000 {
+            return 2
+        }
+        if value < 0x20_0000 {
+            return 3
+        }
+        if value < 0x1000_0000 {
+            return 4
+        }
+        return 5
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func varInt32Size(_ value: Int32) -> Int {
+        let zigzag = UInt32(bitPattern: (value << 1) ^ (value >> 31))
+        return varUInt32Size(zigzag)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func varUInt64Size(_ value: UInt64) -> Int {
+        if value < 0x80 {
+            return 1
+        }
+        if value < 0x4000 {
+            return 2
+        }
+        if value < 0x20_0000 {
+            return 3
+        }
+        if value < 0x1000_0000 {
+            return 4
+        }
+        if value < 0x8_0000_0000 {
+            return 5
+        }
+        if value < 0x400_0000_0000 {
+            return 6
+        }
+        if value < 0x2_0000_0000_0000 {
+            return 7
+        }
+        if value < 0x100_0000_0000_0000 {
+            return 8
+        }
+        return 9
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func varInt64Size(_ value: Int64) -> Int {
+        let zigzag = UInt64(bitPattern: (value << 1) ^ (value >> 63))
+        return varUInt64Size(zigzag)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func varIntSize(_ value: Int) -> Int {
+        varInt64Size(Int64(value))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func varUIntSize(_ value: UInt) -> Int {
+        varUInt64Size(UInt64(value))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeVarUInt32(
+        _ value: UInt32,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        if value < 0x80 {
+            base[index] = UInt8(value)
+            return index + 1
+        }
+        if value < 0x4000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = UInt8(truncatingIfNeeded: value >> 7)
+            return index + 2
+        }
+        if value < 0x20_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = UInt8(truncatingIfNeeded: value >> 14)
+            return index + 3
+        }
+        if value < 0x1000_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+            base[index + 3] = UInt8(truncatingIfNeeded: value >> 21)
+            return index + 4
+        }
+        base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+        base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+        base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+        base[index + 3] = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
+        base[index + 4] = UInt8(truncatingIfNeeded: value >> 28)
+        return index + 5
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeVarUInt64(
+        _ value: UInt64,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        if value < 0x80 {
+            base[index] = UInt8(value)
+            return index + 1
+        }
+        if value < 0x4000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = UInt8(truncatingIfNeeded: value >> 7)
+            return index + 2
+        }
+        if value < 0x20_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = UInt8(truncatingIfNeeded: value >> 14)
+            return index + 3
+        }
+        if value < 0x1000_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+            base[index + 3] = UInt8(truncatingIfNeeded: value >> 21)
+            return index + 4
+        }
+        if value < 0x8_0000_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+            base[index + 3] = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
+            base[index + 4] = UInt8(truncatingIfNeeded: value >> 28)
+            return index + 5
+        }
+        if value < 0x400_0000_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+            base[index + 3] = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
+            base[index + 4] = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
+            base[index + 5] = UInt8(truncatingIfNeeded: value >> 35)
+            return index + 6
+        }
+        if value < 0x2_0000_0000_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+            base[index + 3] = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
+            base[index + 4] = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
+            base[index + 5] = (UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80
+            base[index + 6] = UInt8(truncatingIfNeeded: value >> 42)
+            return index + 7
+        }
+        if value < 0x100_0000_0000_0000 {
+            base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+            base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+            base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+            base[index + 3] = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
+            base[index + 4] = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
+            base[index + 5] = (UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80
+            base[index + 6] = (UInt8(truncatingIfNeeded: value >> 42) & 0x7F) | 0x80
+            base[index + 7] = UInt8(truncatingIfNeeded: value >> 49)
+            return index + 8
+        }
+        base[index] = (UInt8(truncatingIfNeeded: value) & 0x7F) | 0x80
+        base[index + 1] = (UInt8(truncatingIfNeeded: value >> 7) & 0x7F) | 0x80
+        base[index + 2] = (UInt8(truncatingIfNeeded: value >> 14) & 0x7F) | 0x80
+        base[index + 3] = (UInt8(truncatingIfNeeded: value >> 21) & 0x7F) | 0x80
+        base[index + 4] = (UInt8(truncatingIfNeeded: value >> 28) & 0x7F) | 0x80
+        base[index + 5] = (UInt8(truncatingIfNeeded: value >> 35) & 0x7F) | 0x80
+        base[index + 6] = (UInt8(truncatingIfNeeded: value >> 42) & 0x7F) | 0x80
+        base[index + 7] = (UInt8(truncatingIfNeeded: value >> 49) & 0x7F) | 0x80
+        base[index + 8] = UInt8(truncatingIfNeeded: value >> 56)
+        return index + 9
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readBoolUnchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> Bool {
+        base[index] != 0
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt8Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> Int8 {
+        Int8(bitPattern: base[index])
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt8Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> UInt8 {
+        base[index]
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt16Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> Int16 {
+        Int16(bitPattern: readUInt16Unchecked(from: base, index: index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt16Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> UInt16 {
+        let b0 = UInt16(base[index])
+        let b1 = UInt16(base[index + 1]) << 8
+        return b0 | b1
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readFloat32Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> Float {
+        Float(bitPattern: readFixedUInt32Unchecked(from: base, index: index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readFloat64Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> Double {
+        Double(bitPattern: readFixedUInt64Unchecked(from: base, index: index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readBool(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Bool {
+        try readUInt8(from: bytes, index: &index) != 0
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt8(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Int8 {
+        Int8(bitPattern: try readUInt8(from: bytes, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt8(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt8 {
+        try checkReadable(bytes, index: index, need: 1)
+        guard let base = bytes.baseAddress else {
+            throw ForyError.outOfBounds(cursor: index, need: 1, length: bytes.count)
+        }
+        let value = base[index]
+        index += 1
+        return value
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt16(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Int16 {
+        Int16(bitPattern: try readUInt16(from: bytes, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt16(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt16 {
+        try checkReadable(bytes, index: index, need: 2)
+        guard let base = bytes.baseAddress else {
+            throw ForyError.outOfBounds(cursor: index, need: 2, length: bytes.count)
+        }
+        let value = readUInt16Unchecked(from: UnsafePointer(base), index: index)
+        index += 2
+        return value
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt32(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Int32 {
+        try readVarInt32(from: bytes, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt32(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt32 {
+        try readVarUInt32(from: bytes, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt64(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Int64 {
+        try readVarInt64(from: bytes, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt64(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt64 {
+        try readVarUInt64(from: bytes, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Int {
+        Int(try readVarInt64(from: bytes, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt {
+        UInt(try readVarUInt64(from: bytes, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readFloat32(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Float {
+        Float(bitPattern: try readFixedUInt32(from: bytes, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readFloat64(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Double {
+        Double(bitPattern: try readFixedUInt64(from: bytes, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarInt32(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Int32 {
+        let encoded = try readVarUInt32(from: bytes, index: &index)
+        return Int32(bitPattern: (encoded >> 1) ^ (~(encoded & 1) &+ 1))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarInt64(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> Int64 {
+        let encoded = try readVarUInt64(from: bytes, index: &index)
+        return Int64(bitPattern: (encoded >> 1) ^ (~(encoded & 1) &+ 1))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt32(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> Int32 {
+        try readVarInt32(from: base, length: length, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt32(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> UInt32 {
+        try readVarUInt32(from: base, length: length, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt64(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> Int64 {
+        try readVarInt64(from: base, length: length, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt64(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> UInt64 {
+        try readVarUInt64(from: base, length: length, index: &index)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readInt(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> Int {
+        Int(try readVarInt64(from: base, length: length, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readUInt(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> UInt {
+        UInt(try readVarUInt64(from: base, length: length, index: &index))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarUInt32(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt32 {
+        guard let base = bytes.baseAddress else {
+            throw ForyError.outOfBounds(cursor: index, need: 1, length: bytes.count)
+        }
+        let available = bytes.count - index
+        guard available > 0 else {
+            throw ForyError.outOfBounds(cursor: index, need: 1, length: bytes.count)
+        }
+
+        let b0 = base[index]
+        if b0 < 0x80 {
+            index += 1
+            return UInt32(b0)
+        }
+        guard available >= 2 else {
+            throw ForyError.outOfBounds(cursor: index, need: 2, length: bytes.count)
+        }
+        let b1 = base[index + 1]
+        if b1 < 0x80 {
+            index += 2
+            return UInt32(b0 & 0x7F) | (UInt32(b1) << 7)
+        }
+        guard available >= 3 else {
+            throw ForyError.outOfBounds(cursor: index, need: 3, length: bytes.count)
+        }
+        let b2 = base[index + 2]
+        if b2 < 0x80 {
+            index += 3
+            return UInt32(b0 & 0x7F) | (UInt32(b1 & 0x7F) << 7) | (UInt32(b2) << 14)
+        }
+        guard available >= 4 else {
+            throw ForyError.outOfBounds(cursor: index, need: 4, length: bytes.count)
+        }
+        let b3 = base[index + 3]
+        if b3 < 0x80 {
+            index += 4
+            return UInt32(b0 & 0x7F) |
+                (UInt32(b1 & 0x7F) << 7) |
+                (UInt32(b2 & 0x7F) << 14) |
+                (UInt32(b3) << 21)
+        }
+        guard available >= 5 else {
+            throw ForyError.outOfBounds(cursor: index, need: 5, length: bytes.count)
+        }
+        let b4 = base[index + 4]
+        if b4 >= 0x80 {
+            throw ForyError.encodingError("varuint32 overflow")
+        }
+        index += 5
+        return UInt32(b0 & 0x7F) |
+            (UInt32(b1 & 0x7F) << 7) |
+            (UInt32(b2 & 0x7F) << 14) |
+            (UInt32(b3 & 0x7F) << 21) |
+            (UInt32(b4) << 28)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarUInt64(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt64 {
+        let available = bytes.count - index
+        guard let base = bytes.baseAddress else {
+            throw ForyError.outOfBounds(cursor: index, need: 1, length: bytes.count)
+        }
+        if available >= 9 {
+            let offset = index
+            let b0 = base[offset]
+            if b0 < 0x80 {
+                index = offset + 1
+                return UInt64(b0)
+            }
+
+            let b1 = base[offset + 1]
+            if b1 < 0x80 {
+                index = offset + 2
+                return UInt64(b0 & 0x7F) | (UInt64(b1) << 7)
+            }
+
+            let b2 = base[offset + 2]
+            if b2 < 0x80 {
+                index = offset + 3
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2) << 14)
+            }
+
+            let b3 = base[offset + 3]
+            if b3 < 0x80 {
+                index = offset + 4
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3) << 21)
+            }
+
+            let b4 = base[offset + 4]
+            if b4 < 0x80 {
+                index = offset + 5
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4) << 28)
+            }
+
+            let b5 = base[offset + 5]
+            if b5 < 0x80 {
+                index = offset + 6
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4 & 0x7F) << 28) |
+                    (UInt64(b5) << 35)
+            }
+
+            let b6 = base[offset + 6]
+            if b6 < 0x80 {
+                index = offset + 7
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4 & 0x7F) << 28) |
+                    (UInt64(b5 & 0x7F) << 35) |
+                    (UInt64(b6) << 42)
+            }
+
+            let b7 = base[offset + 7]
+            if b7 < 0x80 {
+                index = offset + 8
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4 & 0x7F) << 28) |
+                    (UInt64(b5 & 0x7F) << 35) |
+                    (UInt64(b6 & 0x7F) << 42) |
+                    (UInt64(b7) << 49)
+            }
+
+            let b8 = base[offset + 8]
+            index = offset + 9
+            let low = UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21)
+            let high = (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5 & 0x7F) << 35) |
+                (UInt64(b6 & 0x7F) << 42) |
+                (UInt64(b7 & 0x7F) << 49) |
+                (UInt64(b8) << 56)
+            return low | high
+        }
+
+        try checkReadable(bytes, index: index, need: 1)
+        let b0 = base[index]
+        if b0 < 0x80 {
+            index += 1
+            return UInt64(b0)
+        }
+
+        try checkReadable(bytes, index: index, need: 2)
+        let b1 = base[index + 1]
+        if b1 < 0x80 {
+            index += 2
+            return UInt64(b0 & 0x7F) | (UInt64(b1) << 7)
+        }
+
+        try checkReadable(bytes, index: index, need: 3)
+        let b2 = base[index + 2]
+        if b2 < 0x80 {
+            index += 3
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2) << 14)
+        }
+
+        try checkReadable(bytes, index: index, need: 4)
+        let b3 = base[index + 3]
+        if b3 < 0x80 {
+            index += 4
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3) << 21)
+        }
+
+        try checkReadable(bytes, index: index, need: 5)
+        let b4 = base[index + 4]
+        if b4 < 0x80 {
+            index += 5
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4) << 28)
+        }
+
+        try checkReadable(bytes, index: index, need: 6)
+        let b5 = base[index + 5]
+        if b5 < 0x80 {
+            index += 6
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5) << 35)
+        }
+
+        try checkReadable(bytes, index: index, need: 7)
+        let b6 = base[index + 6]
+        if b6 < 0x80 {
+            index += 7
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5 & 0x7F) << 35) |
+                (UInt64(b6) << 42)
+        }
+
+        try checkReadable(bytes, index: index, need: 8)
+        let b7 = base[index + 7]
+        if b7 < 0x80 {
+            index += 8
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5 & 0x7F) << 35) |
+                (UInt64(b6 & 0x7F) << 42) |
+                (UInt64(b7) << 49)
+        }
+
+        try checkReadable(bytes, index: index, need: 9)
+        let b8 = base[index + 8]
+        index += 9
+        let low = UInt64(b0 & 0x7F) |
+            (UInt64(b1 & 0x7F) << 7) |
+            (UInt64(b2 & 0x7F) << 14) |
+            (UInt64(b3 & 0x7F) << 21)
+        let high = (UInt64(b4 & 0x7F) << 28) |
+            (UInt64(b5 & 0x7F) << 35) |
+            (UInt64(b6 & 0x7F) << 42) |
+            (UInt64(b7 & 0x7F) << 49) |
+            (UInt64(b8) << 56)
+        return low | high
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarInt32(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> Int32 {
+        let encoded = try readVarUInt32(from: base, length: length, index: &index)
+        return Int32(bitPattern: (encoded >> 1) ^ (~(encoded & 1) &+ 1))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarInt64(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> Int64 {
+        let encoded = try readVarUInt64(from: base, length: length, index: &index)
+        return Int64(bitPattern: (encoded >> 1) ^ (~(encoded & 1) &+ 1))
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarUInt32(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> UInt32 {
+        let available = length - index
+        guard available > 0 else {
+            throw ForyError.outOfBounds(cursor: index, need: 1, length: length)
+        }
+
+        let b0 = base[index]
+        if b0 < 0x80 {
+            index += 1
+            return UInt32(b0)
+        }
+        guard available >= 2 else {
+            throw ForyError.outOfBounds(cursor: index, need: 2, length: length)
+        }
+        let b1 = base[index + 1]
+        if b1 < 0x80 {
+            index += 2
+            return UInt32(b0 & 0x7F) | (UInt32(b1) << 7)
+        }
+        guard available >= 3 else {
+            throw ForyError.outOfBounds(cursor: index, need: 3, length: length)
+        }
+        let b2 = base[index + 2]
+        if b2 < 0x80 {
+            index += 3
+            return UInt32(b0 & 0x7F) | (UInt32(b1 & 0x7F) << 7) | (UInt32(b2) << 14)
+        }
+        guard available >= 4 else {
+            throw ForyError.outOfBounds(cursor: index, need: 4, length: length)
+        }
+        let b3 = base[index + 3]
+        if b3 < 0x80 {
+            index += 4
+            return UInt32(b0 & 0x7F) |
+                (UInt32(b1 & 0x7F) << 7) |
+                (UInt32(b2 & 0x7F) << 14) |
+                (UInt32(b3) << 21)
+        }
+        guard available >= 5 else {
+            throw ForyError.outOfBounds(cursor: index, need: 5, length: length)
+        }
+        let b4 = base[index + 4]
+        if b4 >= 0x80 {
+            throw ForyError.encodingError("varuint32 overflow")
+        }
+        index += 5
+        return UInt32(b0 & 0x7F) |
+            (UInt32(b1 & 0x7F) << 7) |
+            (UInt32(b2 & 0x7F) << 14) |
+            (UInt32(b3 & 0x7F) << 21) |
+            (UInt32(b4) << 28)
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readVarUInt64(
+        from base: UnsafePointer<UInt8>,
+        length: Int,
+        index: inout Int
+    ) throws -> UInt64 {
+        let available = length - index
+        if available >= 9 {
+            let offset = index
+            let b0 = base[offset]
+            if b0 < 0x80 {
+                index = offset + 1
+                return UInt64(b0)
+            }
+
+            let b1 = base[offset + 1]
+            if b1 < 0x80 {
+                index = offset + 2
+                return UInt64(b0 & 0x7F) | (UInt64(b1) << 7)
+            }
+
+            let b2 = base[offset + 2]
+            if b2 < 0x80 {
+                index = offset + 3
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2) << 14)
+            }
+
+            let b3 = base[offset + 3]
+            if b3 < 0x80 {
+                index = offset + 4
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3) << 21)
+            }
+
+            let b4 = base[offset + 4]
+            if b4 < 0x80 {
+                index = offset + 5
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4) << 28)
+            }
+
+            let b5 = base[offset + 5]
+            if b5 < 0x80 {
+                index = offset + 6
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4 & 0x7F) << 28) |
+                    (UInt64(b5) << 35)
+            }
+
+            let b6 = base[offset + 6]
+            if b6 < 0x80 {
+                index = offset + 7
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4 & 0x7F) << 28) |
+                    (UInt64(b5 & 0x7F) << 35) |
+                    (UInt64(b6) << 42)
+            }
+
+            let b7 = base[offset + 7]
+            if b7 < 0x80 {
+                index = offset + 8
+                return UInt64(b0 & 0x7F) |
+                    (UInt64(b1 & 0x7F) << 7) |
+                    (UInt64(b2 & 0x7F) << 14) |
+                    (UInt64(b3 & 0x7F) << 21) |
+                    (UInt64(b4 & 0x7F) << 28) |
+                    (UInt64(b5 & 0x7F) << 35) |
+                    (UInt64(b6 & 0x7F) << 42) |
+                    (UInt64(b7) << 49)
+            }
+
+            let b8 = base[offset + 8]
+            index = offset + 9
+            let low = UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21)
+            let high = (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5 & 0x7F) << 35) |
+                (UInt64(b6 & 0x7F) << 42) |
+                (UInt64(b7 & 0x7F) << 49) |
+                (UInt64(b8) << 56)
+            return low | high
+        }
+
+        try checkReadable(length: length, index: index, need: 1)
+        let b0 = base[index]
+        if b0 < 0x80 {
+            index += 1
+            return UInt64(b0)
+        }
+
+        try checkReadable(length: length, index: index, need: 2)
+        let b1 = base[index + 1]
+        if b1 < 0x80 {
+            index += 2
+            return UInt64(b0 & 0x7F) | (UInt64(b1) << 7)
+        }
+
+        try checkReadable(length: length, index: index, need: 3)
+        let b2 = base[index + 2]
+        if b2 < 0x80 {
+            index += 3
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2) << 14)
+        }
+
+        try checkReadable(length: length, index: index, need: 4)
+        let b3 = base[index + 3]
+        if b3 < 0x80 {
+            index += 4
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3) << 21)
+        }
+
+        try checkReadable(length: length, index: index, need: 5)
+        let b4 = base[index + 4]
+        if b4 < 0x80 {
+            index += 5
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4) << 28)
+        }
+
+        try checkReadable(length: length, index: index, need: 6)
+        let b5 = base[index + 5]
+        if b5 < 0x80 {
+            index += 6
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5) << 35)
+        }
+
+        try checkReadable(length: length, index: index, need: 7)
+        let b6 = base[index + 6]
+        if b6 < 0x80 {
+            index += 7
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5 & 0x7F) << 35) |
+                (UInt64(b6) << 42)
+        }
+
+        try checkReadable(length: length, index: index, need: 8)
+        let b7 = base[index + 7]
+        if b7 < 0x80 {
+            index += 8
+            return UInt64(b0 & 0x7F) |
+                (UInt64(b1 & 0x7F) << 7) |
+                (UInt64(b2 & 0x7F) << 14) |
+                (UInt64(b3 & 0x7F) << 21) |
+                (UInt64(b4 & 0x7F) << 28) |
+                (UInt64(b5 & 0x7F) << 35) |
+                (UInt64(b6 & 0x7F) << 42) |
+                (UInt64(b7) << 49)
+        }
+
+        try checkReadable(length: length, index: index, need: 9)
+        let b8 = base[index + 8]
+        index += 9
+        let low = UInt64(b0 & 0x7F) |
+            (UInt64(b1 & 0x7F) << 7) |
+            (UInt64(b2 & 0x7F) << 14) |
+            (UInt64(b3 & 0x7F) << 21)
+        let high = (UInt64(b4 & 0x7F) << 28) |
+            (UInt64(b5 & 0x7F) << 35) |
+            (UInt64(b6 & 0x7F) << 42) |
+            (UInt64(b7 & 0x7F) << 49) |
+            (UInt64(b8) << 56)
+        return low | high
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readFixedUInt32(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt32 {
+        try checkReadable(bytes, index: index, need: 4)
+        guard let base = bytes.baseAddress else {
+            throw ForyError.outOfBounds(cursor: index, need: 4, length: bytes.count)
+        }
+        let value = readFixedUInt32Unchecked(from: UnsafePointer(base), index: index)
+        index += 4
+        return value
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readFixedUInt64(
+        from bytes: UnsafeBufferPointer<UInt8>,
+        index: inout Int
+    ) throws -> UInt64 {
+        try checkReadable(bytes, index: index, need: 8)
+        guard let base = bytes.baseAddress else {
+            throw ForyError.outOfBounds(cursor: index, need: 8, length: bytes.count)
+        }
+        let value = readFixedUInt64Unchecked(from: UnsafePointer(base), index: index)
+        index += 8
+        return value
+    }
+
+    @inlinable
+    @inline(__always)
+    static func writeFixedUInt32(
+        _ value: UInt32,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        let little = value.littleEndian
+        base[index] = UInt8(truncatingIfNeeded: little)
+        base[index + 1] = UInt8(truncatingIfNeeded: little >> 8)
+        base[index + 2] = UInt8(truncatingIfNeeded: little >> 16)
+        base[index + 3] = UInt8(truncatingIfNeeded: little >> 24)
+        return index + 4
+    }
+
+    @inlinable
+    @inline(__always)
+    static func writeFixedUInt64(
+        _ value: UInt64,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        let little = value.littleEndian
+        base[index] = UInt8(truncatingIfNeeded: little)
+        base[index + 1] = UInt8(truncatingIfNeeded: little >> 8)
+        base[index + 2] = UInt8(truncatingIfNeeded: little >> 16)
+        base[index + 3] = UInt8(truncatingIfNeeded: little >> 24)
+        base[index + 4] = UInt8(truncatingIfNeeded: little >> 32)
+        base[index + 5] = UInt8(truncatingIfNeeded: little >> 40)
+        base[index + 6] = UInt8(truncatingIfNeeded: little >> 48)
+        base[index + 7] = UInt8(truncatingIfNeeded: little >> 56)
+        return index + 8
+    }
+
+    @inlinable
+    @inline(__always)
+    static func readFixedUInt32Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> UInt32 {
+        let b0 = UInt32(base[index])
+        let b1 = UInt32(base[index + 1]) << 8
+        let b2 = UInt32(base[index + 2]) << 16
+        let b3 = UInt32(base[index + 3]) << 24
+        return b0 | b1 | b2 | b3
+    }
+
+    @inlinable
+    @inline(__always)
+    static func readFixedUInt64Unchecked(
+        from base: UnsafePointer<UInt8>,
+        index: Int
+    ) -> UInt64 {
+        let b0 = UInt64(base[index])
+        let b1 = UInt64(base[index + 1]) << 8
+        let b2 = UInt64(base[index + 2]) << 16
+        let b3 = UInt64(base[index + 3]) << 24
+        let b4 = UInt64(base[index + 4]) << 32
+        let b5 = UInt64(base[index + 5]) << 40
+        let b6 = UInt64(base[index + 6]) << 48
+        let b7 = UInt64(base[index + 7]) << 56
+        return b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func checkReadable(
+        _ bytes: UnsafeBufferPointer<UInt8>,
+        index: Int,
+        need: Int
+    ) throws {
+        if index < 0 || need < 0 || index + need > bytes.count {
+            throw ForyError.outOfBounds(cursor: index, need: need, length: bytes.count)
+        }
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func checkReadable(
+        length: Int,
+        index: Int,
+        need: Int
+    ) throws {
+        if index < 0 || need < 0 || index + need > length {
+            throw ForyError.outOfBounds(cursor: index, need: need, length: length)
+        }
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeRegion(
+        buffer: ByteBuffer,
+        exactCount: Int,
+        _ body: (UnsafeMutablePointer<UInt8>) -> Void
+    ) {
+        guard exactCount > 0 else {
+            return
+        }
+        let start = buffer.storage.count
+        buffer.storage.append(contentsOf: repeatElement(0, count: exactCount))
+        buffer.storage.withUnsafeMutableBufferPointer { bytes in
+            body(bytes.baseAddress!.advanced(by: start))
+        }
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func writeRegion(
+        buffer: ByteBuffer,
+        maxCount: Int,
+        _ body: (UnsafeMutablePointer<UInt8>) -> Int
+    ) {
+        // Keep the closure non-throwing for the hot path; callers return the
+        // actual byte count and we trim the unused suffix afterward.
+        guard maxCount > 0 else {
+            return
+        }
+        let start = buffer.storage.count
+        buffer.storage.append(contentsOf: repeatElement(0, count: maxCount))
+        let written = buffer.storage.withUnsafeMutableBufferPointer { bytes in
+            body(bytes.baseAddress!.advanced(by: start))
+        }
+        precondition(
+            written >= 0 && written <= maxCount,
+            "writeRegion wrote \(written) bytes into a maxCount \(maxCount) region"
+        )
+        if written < maxCount {
+            buffer.storage.removeLast(maxCount - written)
+        }
+    }
+
+    @inlinable
+    @inline(__always)
+    public static func readRegion(
+        buffer: ByteBuffer,
+        _ body: (UnsafeBufferPointer<UInt8>) throws -> Int
+    ) throws {
+        let startIndex = buffer.cursor
+        let readableCount = buffer.count
+        if _slowPath(startIndex < 0 || startIndex > readableCount) {
+            throw ForyError.outOfBounds(
+                cursor: startIndex,
+                need: 0,
+                length: readableCount
+            )
+        }
+        let available = readableCount - startIndex
+        let consumed = try buffer.storage.withUnsafeBufferPointer { bytes -> Int in
+            let start = bytes.baseAddress.map { $0.advanced(by: startIndex) }
+            let region = UnsafeBufferPointer(start: start, count: available)
+            return try body(region)
+        }
+        if consumed < 0 || consumed > available {
+            throw ForyError.outOfBounds(cursor: startIndex, need: consumed, length: readableCount)
+        }
+        buffer.cursor = startIndex + consumed
+    }
+
+    @inline(__always)
+    static func copyBytes(
+        _ bytes: [UInt8],
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        guard !bytes.isEmpty else {
+            return index
+        }
+        bytes.withUnsafeBufferPointer { source in
+            guard let sourceBase = source.baseAddress else {
+                return
+            }
+            UnsafeMutableRawPointer(base.advanced(by: index))
+                .copyMemory(from: UnsafeRawPointer(sourceBase), byteCount: source.count)
+        }
+        return index + bytes.count
+    }
+
+    @inline(__always)
+    static func copyBytes(
+        _ bytes: UnsafeBufferPointer<UInt8>,
+        to base: UnsafeMutablePointer<UInt8>,
+        index: Int
+    ) -> Int {
+        guard let sourceBase = bytes.baseAddress, bytes.count > 0 else {
+            return index
+        }
+        UnsafeMutableRawPointer(base.advanced(by: index))
+            .copyMemory(from: UnsafeRawPointer(sourceBase), byteCount: bytes.count)
+        return index + bytes.count
+    }
+}
+// swiftlint:enable type_body_length
diff --git a/swift/Sources/Fory/WriteContext.swift b/swift/Sources/Fory/WriteContext.swift
new file mode 100644
index 000000000..9d10aa10e
--- /dev/null
+++ b/swift/Sources/Fory/WriteContext.swift
@@ -0,0 +1,288 @@
+// 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.
+
+import Foundation
+
+private struct MetaStringCacheKey: Hashable {
+    let encoding: MetaStringEncoding
+    let bytes: [UInt8]
+}
+
+final class MetaStringWriteState {
+    private var stringIndexByKey: [MetaStringCacheKey: UInt32] = [:]
+    private var nextIndex: UInt32 = 0
+
+    init() {}
+
+    func index(for value: MetaString) -> UInt32? {
+        stringIndexByKey[MetaStringCacheKey(encoding: value.encoding, bytes: value.bytes)]
+    }
+
+    func assignIndexIfAbsent(for value: MetaString) -> (index: UInt32, isNew: Bool) {
+        let key = MetaStringCacheKey(encoding: value.encoding, bytes: value.bytes)
+        if let existing = stringIndexByKey[key] {
+            return (existing, false)
+        }
+        let index = nextIndex
+        nextIndex &+= 1
+        stringIndexByKey[key] = index
+        return (index, true)
+    }
+
+    func reset() {
+        if !stringIndexByKey.isEmpty {
+            stringIndexByKey.removeAll(keepingCapacity: true)
+        }
+        if nextIndex != 0 {
+            nextIndex = 0
+        }
+    }
+}
+
+public final class WriteContext {
+    public let buffer: ByteBuffer
+    let typeResolver: TypeResolver
+    public let trackRef: Bool
+    public let compatible: Bool
+    public let checkClassVersion: Bool
+    public let maxDepth: Int
+    public let refWriter: RefWriter
+    let metaStringWriteState: MetaStringWriteState
+    private let typeIndexBySwiftType = UInt64Map<UInt32>(initialCapacity: 8)
+    private var typeDefStateUsed = false
+    private var metaStringWriteStateUsed = false
+    private var dynamicAnyDepth = 0
+    private var lastTypeInfo = TypeInfo.uncached
+
+    convenience init(
+        buffer: ByteBuffer,
+        typeResolver: TypeResolver,
+        trackRef: Bool,
+        compatible: Bool = false,
+        checkClassVersion: Bool = true,
+        maxDepth: Int = 5
+    ) {
+        self.init(
+            buffer: buffer,
+            typeResolver: typeResolver,
+            trackRef: trackRef,
+            compatible: compatible,
+            checkClassVersion: checkClassVersion,
+            maxDepth: maxDepth,
+            metaStringWriteState: MetaStringWriteState()
+        )
+    }
+
+    init(
+        buffer: ByteBuffer,
+        typeResolver: TypeResolver,
+        trackRef: Bool,
+        compatible: Bool,
+        checkClassVersion: Bool,
+        maxDepth: Int,
+        metaStringWriteState: MetaStringWriteState
+    ) {
+        self.buffer = buffer
+        self.typeResolver = typeResolver
+        self.trackRef = trackRef
+        self.compatible = compatible
+        self.checkClassVersion = checkClassVersion
+        self.maxDepth = maxDepth
+        self.refWriter = RefWriter()
+        self.metaStringWriteState = metaStringWriteState
+    }
+
+    @inline(__always)
+    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)
+    func typeInfo<T: Serializer>(for type: T.Type) throws -> TypeInfo {
+        let typeID = ObjectIdentifier(type)
+        if lastTypeInfo.swiftTypeID == typeID {
+            return lastTypeInfo
+        }
+        let info = try typeResolver.requireTypeInfo(for: type)
+        lastTypeInfo = info
+        return info
+    }
+
+    @inline(__always)
+    func writeStaticTypeInfo(_ typeID: TypeId) {
+        buffer.writeUInt8(UInt8(truncatingIfNeeded: typeID.rawValue))
+    }
+
+    @inline(__always)
+    func leaveDynamicAnyDepth() {
+        if dynamicAnyDepth > 0 {
+            dynamicAnyDepth -= 1
+        }
+    }
+
+    func writeTypeMeta(_ typeInfo: TypeInfo) {
+        if !typeDefStateUsed {
+            typeDefStateUsed = true
+        }
+
+        let typeIndexBySwiftType = self.typeIndexBySwiftType
+        let typeKey = UInt64(UInt(bitPattern: typeInfo.swiftTypeID))
+        let assignment = typeIndexBySwiftType.putIfAbsent(
+            UInt32(typeIndexBySwiftType.count),
+            for: typeKey
+        )
+        let buffer = self.buffer
+        if assignment.inserted {
+            if assignment.value == 0, let firstTypeDefBytes = typeInfo.firstTypeDefBytes {
+                buffer.writeBytes(firstTypeDefBytes)
+                return
+            }
+
+            let marker = assignment.value << 1
+            if marker < 0x80 {
+                buffer.writeUInt8(UInt8(truncatingIfNeeded: marker))
+            } else {
+                buffer.writeVarUInt32(marker)
+            }
+            if let typeDefBytes = typeInfo.typeDefBytes {
+                buffer.writeBytes(typeDefBytes)
+            }
+        } else {
+            let marker = (assignment.value << 1) | 1
+            if marker < 0x80 {
+                buffer.writeUInt8(UInt8(truncatingIfNeeded: marker))
+            } else {
+                buffer.writeVarUInt32(marker)
+            }
+        }
+    }
+
+    @inline(__always)
+    func markMetaStringWriteStateUsed() {
+        metaStringWriteStateUsed = true
+    }
+
+    func reset() {
+        if dynamicAnyDepth != 0 {
+            dynamicAnyDepth = 0
+        }
+        if trackRef {
+            refWriter.reset()
+        }
+        if typeDefStateUsed {
+            if !typeIndexBySwiftType.isEmpty {
+                typeIndexBySwiftType.clear()
+            }
+            typeDefStateUsed = false
+        }
+        if metaStringWriteStateUsed {
+            metaStringWriteState.reset()
+            metaStringWriteStateUsed = false
+        }
+    }
+}
+
+public extension WriteContext {
+    func writeAny(
+        _ value: Any?,
+        refMode: RefMode,
+        writeTypeInfo: Bool = true,
+        hasGenerics: Bool = false
+    ) throws {
+        try DynamicAnyValue.wrapped(value).foryWrite(
+            self,
+            refMode: refMode,
+            writeTypeInfo: writeTypeInfo,
+            hasGenerics: hasGenerics
+        )
+    }
+
+    func writeAnyList(
+        _ value: [Any]?,
+        refMode: RefMode,
+        writeTypeInfo: Bool = false,
+        hasGenerics: Bool = true
+    ) throws {
+        let wrapped = value?.map { DynamicAnyValue.wrapped($0) }
+        try wrapped.foryWrite(
+            self,
+            refMode: refMode,
+            writeTypeInfo: writeTypeInfo,
+            hasGenerics: hasGenerics
+        )
+    }
+
+    func writeStringAnyMap(
+        _ value: [String: Any]?,
+        refMode: RefMode,
+        writeTypeInfo: Bool = false,
+        hasGenerics: Bool = true
+    ) throws {
+        let wrapped = value?.reduce(into: [String: DynamicAnyValue]()) { result, pair in
+            result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+        }
+        try wrapped.foryWrite(
+            self,
+            refMode: refMode,
+            writeTypeInfo: writeTypeInfo,
+            hasGenerics: hasGenerics
+        )
+    }
+
+    func writeInt32AnyMap(
+        _ value: [Int32: Any]?,
+        refMode: RefMode,
+        writeTypeInfo: Bool = false,
+        hasGenerics: Bool = true
+    ) throws {
+        let wrapped = value?.reduce(into: [Int32: DynamicAnyValue]()) { result, pair in
+            result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+        }
+        try wrapped.foryWrite(
+            self,
+            refMode: refMode,
+            writeTypeInfo: writeTypeInfo,
+            hasGenerics: hasGenerics
+        )
+    }
+
+    func writeAnyHashableAnyMap(
+        _ value: [AnyHashable: Any]?,
+        refMode: RefMode,
+        writeTypeInfo: Bool = false,
+        hasGenerics: Bool = true
+    ) throws {
+        let wrapped = value?.reduce(into: [AnyHashable: DynamicAnyValue]()) { result, pair in
+            result[pair.key] = DynamicAnyValue.wrapped(pair.value)
+        }
+        try wrapped.foryWrite(
+            self,
+            refMode: refMode,
+            writeTypeInfo: writeTypeInfo,
+            hasGenerics: hasGenerics
+        )
+    }
+}
diff --git a/swift/Sources/ForyMacro/ForyObjectMacro.swift b/swift/Sources/ForyMacro/ForyObjectMacro.swift
index 35774b2b3..8a26ad6d0 100644
--- a/swift/Sources/ForyMacro/ForyObjectMacro.swift
+++ b/swift/Sources/ForyMacro/ForyObjectMacro.swift
@@ -48,7 +48,7 @@ public struct ForyObjectMacro: MemberMacro, ExtensionMacro {
         """
 
         let referenceTrackDecl: DeclSyntax? = parsed.isClass ? """
-        \(raw: accessPrefix)static var isReferenceTrackableType: Bool { true }
+        \(raw: accessPrefix)static var isRefType: Bool { true }
         """ : nil
 
         let schemaHashDecl: DeclSyntax = DeclSyntax(stringLiteral: buildSchemaHashDecl(fields: parsed.fields))
@@ -59,7 +59,9 @@ public struct ForyObjectMacro: MemberMacro, ExtensionMacro {
             stringLiteral: buildDefaultDecl(isClass: parsed.isClass, fields: parsed.fields, accessPrefix: accessPrefix)
         )
         let writeWrapperDecl: DeclSyntax = DeclSyntax(stringLiteral: buildWriteWrapperDecl(accessPrefix: accessPrefix))
-        let readWrapperDecl: DeclSyntax = DeclSyntax(stringLiteral: buildReadWrapperDecl(accessPrefix: accessPrefix))
+        let readWrapperDecl: DeclSyntax? = parsed.isClass
+            ? DeclSyntax(stringLiteral: buildClassReadWrapperDecl(accessPrefix: accessPrefix))
+            : nil
         let writeDecl: DeclSyntax = DeclSyntax(
             stringLiteral: buildWriteDataDecl(sortedFields: sortedFields, accessPrefix: accessPrefix)
         )
@@ -71,7 +73,14 @@ public struct ForyObjectMacro: MemberMacro, ExtensionMacro {
                 accessPrefix: accessPrefix
             )
         )
-
+        let readCompatibleDecl: DeclSyntax = DeclSyntax(
+            stringLiteral: buildReadCompatibleDataDecl(
+                isClass: parsed.isClass,
+                fields: parsed.fields,
+                sortedFields: sortedFields,
+                accessPrefix: accessPrefix
+            )
+        )
         return [
             staticTypeIDDecl,
             referenceTrackDecl,
@@ -81,7 +90,8 @@ public struct ForyObjectMacro: MemberMacro, ExtensionMacro {
             writeWrapperDecl,
             readWrapperDecl,
             writeDecl,
-            readDecl
+            readDecl,
+            readCompatibleDecl
         ].compactMap { $0 }
     }
 
@@ -131,7 +141,7 @@ private enum FieldEncoding: String {
     case tagged
 }
 
-private enum DynamicAnyCodecKind {
+enum DynamicAnyCodecKind {
     case anyValue
     case anyHashableValue
     case anyList
@@ -140,7 +150,7 @@ private enum DynamicAnyCodecKind {
     case anyHashableAnyMap
 }
 
-private struct ParsedField {
+struct ParsedField {
     let name: String
     let typeText: String
     let originalIndex: Int
@@ -318,7 +328,6 @@ private func buildOrdinalEnumDecls(_ cases: [ParsedEnumCase], accessPrefix: Stri
     \(raw: accessPrefix)static var staticTypeId: TypeId { .enumType }
     """
     let writeWrapperDecl: DeclSyntax = DeclSyntax(stringLiteral: buildWriteWrapperDecl(accessPrefix: accessPrefix))
-    let readWrapperDecl: DeclSyntax = DeclSyntax(stringLiteral: buildReadWrapperDecl(accessPrefix: accessPrefix))
 
     let writeDecl: DeclSyntax = DeclSyntax(
         stringLiteral: """
@@ -346,7 +355,7 @@ private func buildOrdinalEnumDecls(_ cases: [ParsedEnumCase], accessPrefix: Stri
         """
     )
 
-    return [defaultDecl, staticTypeIDDecl, writeWrapperDecl, readWrapperDecl, writeDecl, readDecl]
+    return [defaultDecl, staticTypeIDDecl, writeWrapperDecl, writeDecl, readDecl]
 }
 
 private func buildTaggedUnionEnumDecls(_ cases: [ParsedEnumCase], accessPrefix: String) -> [DeclSyntax] {
@@ -403,7 +412,6 @@ private func buildTaggedUnionEnumDecls(_ cases: [ParsedEnumCase], accessPrefix:
     \(raw: accessPrefix)static var staticTypeId: TypeId { .typedUnion }
     """
     let writeWrapperDecl: DeclSyntax = DeclSyntax(stringLiteral: buildWriteWrapperDecl(accessPrefix: accessPrefix))
-    let readWrapperDecl: DeclSyntax = DeclSyntax(stringLiteral: buildReadWrapperDecl(accessPrefix: accessPrefix))
 
     let writeDecl: DeclSyntax = DeclSyntax(
         stringLiteral: """
@@ -431,7 +439,7 @@ private func buildTaggedUnionEnumDecls(_ cases: [ParsedEnumCase], accessPrefix:
         """
     )
 
-    return [defaultDecl, staticTypeIDDecl, writeWrapperDecl, readWrapperDecl, writeDecl, readDecl]
+    return [defaultDecl, staticTypeIDDecl, writeWrapperDecl, writeDecl, readDecl]
 }
 
 private func enumCasePattern(_ enumCase: ParsedEnumCase) -> String {
@@ -904,33 +912,37 @@ private func buildSchemaHashDecl(fields: [ParsedField]) -> String {
 }
 
 private func buildCompatibleTypeMetaFieldsDecl(sortedFields: [ParsedField], accessPrefix: String) -> String {
-    func fieldIDExpression(_ field: ParsedField) -> String {
-        if let fieldID = field.fieldID {
-            return "\(fieldID)"
-        }
-        return "nil"
+    let disabledExpr = compatibleTypeMetaFieldsExpr(sortedFields: sortedFields, trackRefExpression: "false")
+    let enabledExpr = compatibleTypeMetaFieldsExpr(sortedFields: sortedFields, trackRefExpression: "true")
+    return """
+    private static let __foryFieldsInfoTrackRefDisabled: [TypeMeta.FieldInfo] = \(disabledExpr)
+    private static let __foryFieldsInfoTrackRefEnabled: [TypeMeta.FieldInfo] = \(enabledExpr)
+
+    \(accessPrefix)static func foryFieldsInfo(trackRef: Bool) -> [TypeMeta.FieldInfo] {
+        trackRef ? Self.__foryFieldsInfoTrackRefEnabled : Self.__foryFieldsInfoTrackRefDisabled
     }
+    """
+}
 
-    let fieldInfosTrackRefDisabled = sortedFields.map { field in
-        "TypeMetaFieldInfo(fieldID: \(fieldIDExpression(field)), fieldName: \"\(field.name)\", fieldType: \(compatibleTypeMetaFieldExpression(field, trackRefExpression: "false")))"
+private func compatibleTypeMetaFieldsExpr(
+    sortedFields: [ParsedField],
+    trackRefExpression: String
+) -> String {
+    let fieldInfos = sortedFields.map { field in
+        let fieldTypeExpr = compatibleTypeMetaFieldExpression(field, trackRefExpression: trackRefExpression)
+        return "TypeMeta.FieldInfo(fieldID: \(compatibleFieldIDExpr(field)), fieldName: \"\(field.name)\", fieldType: \(fieldTypeExpr))"
     }
-    let fieldInfosTrackRefEnabled = sortedFields.map { field in
-        "TypeMetaFieldInfo(fieldID: \(fieldIDExpression(field)), fieldName: \"\(field.name)\", fieldType: \(compatibleTypeMetaFieldExpression(field, trackRefExpression: "true")))"
+    guard !fieldInfos.isEmpty else {
+        return "[]"
     }
-    let disabledExpr = fieldInfosTrackRefDisabled.isEmpty
-        ? "[]"
-        : "[\n            \(fieldInfosTrackRefDisabled.joined(separator: ",\n            "))\n        ]"
-    let enabledExpr = fieldInfosTrackRefEnabled.isEmpty
-        ? "[]"
-        : "[\n            \(fieldInfosTrackRefEnabled.joined(separator: ",\n            "))\n        ]"
-    return """
-    private static let __foryCompatibleTypeMetaFieldsTrackRefDisabled: [TypeMetaFieldInfo] = \(disabledExpr)
-    private static let __foryCompatibleTypeMetaFieldsTrackRefEnabled: [TypeMetaFieldInfo] = \(enabledExpr)
+    return "[\n            \(fieldInfos.joined(separator: ",\n            "))\n        ]"
+}
 
-    \(accessPrefix)static func foryCompatibleTypeMetaFields(trackRef: Bool) -> [TypeMetaFieldInfo] {
-        trackRef ? Self.__foryCompatibleTypeMetaFieldsTrackRefEnabled : Self.__foryCompatibleTypeMetaFieldsTrackRefDisabled
+private func compatibleFieldIDExpr(_ field: ParsedField) -> String {
+    if let fieldID = field.fieldID {
+        return "\(fieldID)"
     }
-    """
+    return "nil"
 }
 
 private func buildSchemaFingerprint(fields: [ParsedField], trackRefExpression: String) -> String {
@@ -953,7 +965,7 @@ private func buildSchemaFingerprint(fields: [ParsedField], trackRefExpression: S
                     trackRefExpr = "0"
                 }
             } else {
-                trackRefExpr = "((\(trackRefExpression)) && \(field.typeText).isReferenceTrackableType) ? 1 : 0"
+                trackRefExpr = "((\(trackRefExpression)) && \(field.typeText).isRefType) ? 1 : 0"
             }
             return "\"\(field.schemaIdentifier),\(typeID),\\(\(trackRefExpr)),\(nullable);\""
         }
@@ -992,10 +1004,7 @@ private func buildDefaultDecl(isClass: Bool, fields: [ParsedField], accessPrefix
     let args = fields
         .sorted(by: { $0.originalIndex < $1.originalIndex })
         .map { field in
-            if field.dynamicAnyCodec != nil {
-                return "\(field.name): \(dynamicAnyDefaultExpr(typeText: field.typeText))"
-            }
-            return "\(field.name): \(field.typeText).foryDefault()"
+            "\(field.name): \(fieldDefaultExpr(field))"
         }
         .joined(separator: ",\n            ")
 
@@ -1016,18 +1025,19 @@ private func buildWriteWrapperDecl(accessPrefix: String) -> String {
         writeTypeInfo: Bool,
         hasGenerics: Bool
     ) throws {
+        let __buffer = context.buffer
         if refMode != .none {
-            if refMode == .tracking, Self.isReferenceTrackableType, let object = self as AnyObject? {
-                if context.refWriter.tryWriteReference(buffer: context.buffer, object: object) {
+            if refMode == .tracking, Self.isRefType, let object = self as AnyObject? {
+                if context.refWriter.tryWriteRef(buffer: __buffer, object: object) {
                     return
                 }
             } else {
-                context.buffer.writeInt8(RefFlag.notNullValue.rawValue)
+                __buffer.writeInt8(RefFlag.notNullValue.rawValue)
             }
         }
 
         if writeTypeInfo {
-            try Self.foryWriteTypeInfo(context)
+            try Self.foryWriteStaticTypeInfo(context)
         }
 
         try foryWriteData(context, hasGenerics: hasGenerics)
@@ -1035,90 +1045,49 @@ private func buildWriteWrapperDecl(accessPrefix: String) -> String {
     """
 }
 
-private func buildReadWrapperDecl(accessPrefix: String) -> String {
-    """
-    \(accessPrefix)static func foryRead(
-        _ context: ReadContext,
-        refMode: RefMode,
-        readTypeInfo: Bool
-    ) throws -> Self {
-        if refMode != .none {
-            let rawFlag = try context.buffer.readInt8()
-            guard let flag = RefFlag(rawValue: rawFlag) else {
-                throw ForyError.refError("invalid ref flag \\(rawFlag)")
-            }
-
-            switch flag {
-            case .null:
-                return Self.foryDefault()
-            case .ref:
-                let refID = try context.buffer.readVarUInt32()
-                return try context.refReader.readRef(refID, as: Self.self)
-            case .refValue:
-                let reservedRefID = context.refReader.reserveRefID()
-                context.pushPendingReference(reservedRefID)
-                if readTypeInfo {
-                    try Self.foryReadTypeInfo(context)
-                }
-                let value = try Self.foryReadData(context)
-                context.finishPendingReferenceIfNeeded(value)
-                context.popPendingReference()
-                return value
-            case .notNullValue:
-                break
-            }
-        }
-
-        if readTypeInfo {
-            try Self.foryReadTypeInfo(context)
-        }
-        return try Self.foryReadData(context)
-    }
-    """
-}
-
 private func buildWriteDataDecl(sortedFields: [ParsedField], accessPrefix: String) -> String {
-    let schemaFieldLines = sortedFields.map { field in
-        schemaWriteLine(for: field)
+    let allFieldLines = sortedFields.map { field in
+        writeLine(for: field)
     }
-    let compatibleLines = sortedFields.map { field in
-        compatibleWriteLine(for: field)
+    let leadingPrimitiveFields = leadingPrimitiveFastPathFields(sortedFields)
+    let remainingFieldLines = sortedFields.dropFirst(leadingPrimitiveFields.count).map { field in
+        writeLine(for: field)
     }
-    var schemaBodyLines = [
+    var schemaHeaderLines = [
         "if context.checkClassVersion {",
-        "    context.buffer.writeInt32(Int32(bitPattern: Self.__forySchemaHash(context.trackRef)))",
+        "    __buffer.writeInt32(Int32(bitPattern: Self.__forySchemaHash(context.trackRef)))",
         "}"
     ]
     let primitiveReserveBytes = schemaPrimitiveReserveBytes(sortedFields)
     if primitiveReserveBytes > 0 {
-        schemaBodyLines.insert(
-            "context.buffer.reserve(\(primitiveReserveBytes) + (context.checkClassVersion ? 4 : 0))",
+        schemaHeaderLines.insert(
+            "__buffer.reserve(\(primitiveReserveBytes) + (context.checkClassVersion ? 4 : 0))",
             at: 0
         )
     }
-    if schemaFieldLines.isEmpty {
-        schemaBodyLines.append("_ = hasGenerics")
-    } else {
-        schemaBodyLines.append(contentsOf: schemaFieldLines)
+    let schemaHeader = schemaHeaderLines.joined(separator: "\n            ")
+    let primitiveFastWriteBlock = buildPrimitiveFastWriteBlock(leadingPrimitiveFields)
+    var fastFieldLines: [String] = []
+    if let primitiveFastWriteBlock {
+        fastFieldLines.append(primitiveFastWriteBlock)
     }
-    let schemaBody = schemaBodyLines.joined(separator: "\n        ")
+    fastFieldLines.append(contentsOf: remainingFieldLines)
 
-    let compatibleWriteLines: String
-    if compatibleLines.isEmpty {
-        compatibleWriteLines = "\n            _ = hasGenerics"
+    let fieldBody: String
+    if allFieldLines.isEmpty {
+        fieldBody = "_ = hasGenerics"
     } else {
-        let joinedCompatibleLines = compatibleLines.joined(separator: "\n            ")
-        compatibleWriteLines = "\n            \(joinedCompatibleLines)"
+        fieldBody = fastFieldLines.joined(separator: "\n        ")
     }
 
     return """
     @inline(__always)
     \(accessPrefix)func foryWriteData(_ context: WriteContext, hasGenerics: Bool) throws {
-        if context.compatible {
-            \(compatibleWriteLines)
-            return
+        let __buffer = context.buffer
+        if !context.compatible {
+            \(schemaHeader)
         }
-        \(schemaBody)
+        \(fieldBody)
     }
     """
 }
@@ -1168,7 +1137,7 @@ private func schemaPrimitiveReserveBytes(for field: ParsedField) -> Int {
     }
 }
 
-private func schemaWriteLine(for field: ParsedField) -> String {
+private func writeLine(for field: ParsedField) -> String {
     if let dynamicAnyCodec = field.dynamicAnyCodec {
         let refMode = fieldRefModeExpression(field)
         return dynamicAnyWriteLine(
@@ -1199,291 +1168,78 @@ private func schemaWriteLine(for field: ParsedField) -> String {
         )
         """
     }
-    if !field.isOptional, field.typeID != 27 {
+    if !field.isOptional, !compatibleFieldNeedsTypeInfo(field) {
         if let primitiveLine = primitiveSchemaWriteLine(field) {
             return primitiveLine
         }
         return "try self.\(field.name).foryWriteData(context, hasGenerics: \(hasGenerics))"
     }
     let refMode = fieldRefModeExpression(field)
-    return "try self.\(field.name).foryWrite(context, refMode: \(refMode), writeTypeInfo: false, hasGenerics: \(hasGenerics))"
-}
-
-private func compatibleWriteLine(for field: ParsedField) -> String {
-    let refMode = fieldRefModeExpression(field)
-    if let dynamicAnyCodec = field.dynamicAnyCodec {
-        return dynamicAnyWriteLine(
-            field: field,
-            dynamicAnyCodec: dynamicAnyCodec,
-            refModeExpr: refMode
-        )
-    }
-    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 \(codecType)(rawValue: self.\(field.name)).foryWrite(
-            context,
-            refMode: \(refMode),
-            writeTypeInfo: false,
-            hasGenerics: false
-        )
-        """
-    }
+    let writeTypeInfoExpr = "context.compatible ? TypeId.needsTypeInfoForField(\(field.typeText).staticTypeId) : false"
     return """
     try self.\(field.name).foryWrite(
         context,
         refMode: \(refMode),
-        writeTypeInfo: TypeId.needsTypeInfoForField(\(field.typeText).staticTypeId),
+        writeTypeInfo: \(writeTypeInfoExpr),
         hasGenerics: \(hasGenerics)
     )
     """
 }
 
-private func buildReadDataDecl(
-    isClass: Bool,
-    fields: [ParsedField],
-    sortedFields: [ParsedField],
-    accessPrefix: String
-) -> String {
-    if isClass {
-        let assignLines = sortedFields.map { field -> String in
-            let refMode = fieldRefModeExpression(field)
-            let valueExpr = readFieldExpr(
-                field,
-                refModeExpr: refMode,
-                readTypeInfoExpr: "false"
-            )
-            return "value.\(field.name) = \(valueExpr)"
-        }.joined(separator: "\n        ")
-        let compatibleCases = sortedFields.map { field -> String in
-            let valueExpr = readFieldExpr(
-                field,
-                refModeExpr: "RefMode.from(nullable: remoteField.fieldType.nullable, trackRef: remoteField.fieldType.trackRef)",
-                readTypeInfoExpr: "TypeId.needsTypeInfoForField(TypeId(rawValue: remoteField.fieldType.typeID) ?? .unknown)"
-            )
-            return "case \"\(field.fieldIdentifier)\": value.\(field.name) = \(valueExpr)"
-        }.joined(separator: "\n                ")
-
-        return """
-        @inline(__always)
-        \(accessPrefix)static func foryReadData(_ context: ReadContext) throws -> Self {
-            if context.compatible, let typeMeta = context.consumeCompatibleTypeMetaIfPresent(for: Self.self) {
-                let value = Self.init()
-                context.bindPendingReference(value)
-                for remoteField in typeMeta.fields {
-                    switch remoteField.fieldName {
-                \(compatibleCases)
-                    default:
-                        try FieldSkipper.skipFieldValue(context: context, fieldType: remoteField.fieldType)
-                    }
-                }
-                return value
-            }
-            if context.checkClassVersion {
-                let __schemaHash = UInt32(bitPattern: try context.buffer.readInt32())
-                let __expectedHash = Self.__forySchemaHash(context.trackRef)
-                if __schemaHash != __expectedHash {
-                    throw ForyError.invalidData("class version hash mismatch: expected \\(__expectedHash), got \\(__schemaHash)")
-                }
-            }
-            let value = Self.init()
-            context.bindPendingReference(value)
-            \(assignLines)
-            return value
-        }
-        """
-    }
-
-    if fields.isEmpty {
-        return """
-        @inline(__always)
-        \(accessPrefix)static func foryReadData(_ context: ReadContext) throws -> Self {
-            if context.compatible, let typeMeta = context.consumeCompatibleTypeMetaIfPresent(for: Self.self) {
-                for remoteField in typeMeta.fields {
-                    try FieldSkipper.skipFieldValue(context: context, fieldType: remoteField.fieldType)
-                }
-                return Self()
-            }
-            if context.checkClassVersion {
-                let __schemaHash = UInt32(bitPattern: try context.buffer.readInt32())
-                let __expectedHash = Self.__forySchemaHash(context.trackRef)
-                if __schemaHash != __expectedHash {
-                    throw ForyError.invalidData("class version hash mismatch: expected \\(__expectedHash), got \\(__schemaHash)")
-                }
-            }
-            return Self()
-        }
-        """
-    }
-
-    let readLines = sortedFields.map { field -> String in
-        let valueExpr = schemaReadFieldExpr(field)
-        return "let __\(field.name) = \(valueExpr)"
-    }.joined(separator: "\n        ")
-
-    let ctorArgs = fields
-        .sorted(by: { $0.originalIndex < $1.originalIndex })
-        .map { "\($0.name): __\($0.name)" }
-        .joined(separator: ",\n            ")
-    let compatibleDefaults = fields
-        .sorted(by: { $0.originalIndex < $1.originalIndex })
-        .map { field in
-            if field.dynamicAnyCodec != nil {
-                return "var __\(field.name): \(field.typeText) = \(dynamicAnyDefaultExpr(typeText: field.typeText))"
-            }
-            return "var __\(field.name) = \(field.typeText).foryDefault()"
-        }
-        .joined(separator: "\n                ")
-    let compatibleCases = sortedFields.map { field -> String in
-        let valueExpr = readFieldExpr(
-            field,
-            refModeExpr: "RefMode.from(nullable: remoteField.fieldType.nullable, trackRef: remoteField.fieldType.trackRef)",
-            readTypeInfoExpr: "TypeId.needsTypeInfoForField(TypeId(rawValue: remoteField.fieldType.typeID) ?? .unknown)"
-        )
-        return "case \"\(field.fieldIdentifier)\": __\(field.name) = \(valueExpr)"
-    }.joined(separator: "\n                    ")
-
-    return """
-    @inline(__always)
-    \(accessPrefix)static func foryReadData(_ context: ReadContext) throws -> Self {
-        if context.compatible, let typeMeta = context.consumeCompatibleTypeMetaIfPresent(for: Self.self) {
-                \(compatibleDefaults)
-                for remoteField in typeMeta.fields {
-                    switch remoteField.fieldName {
-                    \(compatibleCases)
-                    default:
-                        try FieldSkipper.skipFieldValue(context: context, fieldType: remoteField.fieldType)
-                    }
-                }
-                return Self(
-                    \(ctorArgs)
-                )
-            }
-        if context.checkClassVersion {
-            let __schemaHash = UInt32(bitPattern: try context.buffer.readInt32())
-            let __expectedHash = Self.__forySchemaHash(context.trackRef)
-            if __schemaHash != __expectedHash {
-                throw ForyError.invalidData("class version hash mismatch: expected \\(__expectedHash), got \\(__schemaHash)")
-            }
-        }
-        \(readLines)
-        return Self(
-            \(ctorArgs)
-        )
-    }
-    """
-}
-
-private func readFieldExpr(
-    _ field: ParsedField,
-    refModeExpr: String,
-    readTypeInfoExpr: String
-) -> String {
-    if let dynamicAnyCodec = field.dynamicAnyCodec {
-        return dynamicAnyReadExpr(
-            field: field,
-            dynamicAnyCodec: dynamicAnyCodec,
-            refModeExpr: refModeExpr,
-            readTypeInfoExpr: readTypeInfoExpr
-        )
-    }
-    if let codecType = field.customCodecType {
-        if field.isOptional {
-            return "try \(codecType)?.foryRead(context, refMode: \(refModeExpr), readTypeInfo: false)?.rawValue"
-        }
-        return "try \(codecType).foryRead(context, refMode: \(refModeExpr), readTypeInfo: false).rawValue"
-    }
-    return "try \(field.typeText).foryRead(context, refMode: \(refModeExpr), readTypeInfo: \(readTypeInfoExpr))"
-}
-
-private func schemaReadFieldExpr(_ field: ParsedField) -> String {
-    if field.dynamicAnyCodec != nil || field.customCodecType != nil || field.isOptional || field.typeID == 27 {
-        let refMode = fieldRefModeExpression(field)
-        return readFieldExpr(
-            field,
-            refModeExpr: refMode,
-            readTypeInfoExpr: "false"
-        )
-    }
-    if let primitiveExpr = primitiveSchemaReadExpr(field) {
-        return primitiveExpr
-    }
-    return "try \(field.typeText).foryReadData(context)"
-}
-
-private func primitiveSchemaWriteLine(_ field: ParsedField) -> String? {
-    let type = trimType(field.typeText)
-    switch type {
-    case "Bool":
-        return "context.buffer.writeUInt8(self.\(field.name) ? 1 : 0)"
-    case "Int8":
-        return "context.buffer.writeInt8(self.\(field.name))"
-    case "Int16":
-        return "context.buffer.writeInt16(self.\(field.name))"
-    case "Int32":
-        return "context.buffer.writeVarInt32(self.\(field.name))"
-    case "Int64":
-        return "context.buffer.writeVarInt64(self.\(field.name))"
-    case "Int":
-        return "context.buffer.writeVarInt64(Int64(self.\(field.name)))"
-    case "UInt8":
-        return "context.buffer.writeUInt8(self.\(field.name))"
-    case "UInt16":
-        return "context.buffer.writeUInt16(self.\(field.name))"
-    case "UInt32":
-        return "context.buffer.writeVarUInt32(self.\(field.name))"
-    case "UInt64":
-        return "context.buffer.writeVarUInt64(self.\(field.name))"
-    case "UInt":
-        return "context.buffer.writeVarUInt64(UInt64(self.\(field.name)))"
-    case "Float":
-        return "context.buffer.writeFloat32(self.\(field.name))"
-    case "Double":
-        return "context.buffer.writeFloat64(self.\(field.name))"
+private enum MacroTypeId {
+    static let unknown: UInt32 = 0
+    static let compatibleStruct: UInt32 = 27
+    static let namedStruct: UInt32 = 28
+    static let namedCompatibleStruct: UInt32 = 29
+    static let enumType: UInt32 = 30
+    static let namedEnum: UInt32 = 31
+    static let ext: UInt32 = 32
+}
+
+func compatibleFieldNeedsTypeInfo(_ field: ParsedField) -> Bool {
+    switch field.typeID {
+    case MacroTypeId.unknown,
+         MacroTypeId.compatibleStruct,
... 1497 lines suppressed ...


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org