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 bf6ebf9c7 feat(rust): fast fory_read_compatible macro to use match by 
assigned field id (#2758)
bf6ebf9c7 is described below

commit bf6ebf9c703fe3b4db7b42e5994322aa016526be
Author: Shawn Yang <[email protected]>
AuthorDate: Mon Oct 13 17:55:07 2025 +0530

    feat(rust): fast fory_read_compatible macro to use match by assigned field 
id (#2758)
    
    ## Why?
    
    <!-- Describe the purpose of this PR. -->
    
    ## What does this PR do?
    
    This pr implemented a new fory_read_compatible macro function to use
    match by assigned field id for better performance.
    - When read type meta, assign field id based on local field type info.
    If type info are consistent(excluding nullability), then assign remote
    field to local field. Otherwise, skip this remote field value when
    deserializing, use default value instead.
    - When generating fory_read_compatible code, use match by field id arm,
    which will compiled to switch. This is much more efficient compared to
    previous compare field by string
    - Skip using Option is local field is primitive and not Option.
    
    Now the macro generate much more efficient and compact code:
    ```rust
    fn fory_read_compatible(
    fory: &fory_core::fory::Fory,
    context: &mut fory_core::resolver::context::ReadContext,
    ) -> Result<Self, fory_core::error::Error> {
    let remote_type_id = context.reader.read_varuint32();
    let meta_index = context.reader.read_varuint32();
    let meta = context.get_meta(meta_index as usize);
    let fields = {
        let meta = context.get_meta(meta_index as usize);
        meta.get_field_infos().clone()
    };
    let mut _f7: i16 = 0 as i16;
    let mut _f5: i8 = 0 as i8;
    let mut _last: i8 = 0 as i8;
    let mut _f4: Option<String> = None;
    let mut _f3: Option<Vec<i8>> = None;
    let mut _f6: Option<Vec<i16>> = None;
    let mut _f1: Option<HashMap<i8, Vec<i8>>> = None;
    let local_type_def = fory
        .get_type_resolver()
        .get_type_info(std::any::TypeId::of::<Self>())
        .get_type_def();
    let high_bytes = &local_type_def[..8];
    let local_type_hash = i64::from_le_bytes(high_bytes.try_into().unwrap());
    if meta.get_hash() == local_type_hash {
        <Self as fory_core::serializer::Serializer>::fory_read_data(
            fory,
            context,
            false,
        )
    } else {
        for _field in fields.iter() {
            match _field.field_id {
                0i16 => {
                    if !&_field.field_type.nullable {
                        _f7 = fory_core::serializer::read_ref_info_data::<
                            i16,
                        >(fory, context, true, true, false)?;
                    } else {
                        if (context.reader.read_bool()) {
                            _f7 = <i16 as 
fory_core::serializer::ForyDefault>::fory_default();
                        } else {
                            _f7 = fory_core::serializer::read_ref_info_data::<
                                i16,
                            >(fory, context, true, true, false)?;
                        }
                    }
                }
                1i16 => {
                    if !&_field.field_type.nullable {
                        _f5 = fory_core::serializer::read_ref_info_data::<
                            i8,
                        >(fory, context, true, true, false)?;
                    } else {
                        if (context.reader.read_bool()) {
                            _f5 = <i8 as 
fory_core::serializer::ForyDefault>::fory_default();
                        } else {
                            _f5 = fory_core::serializer::read_ref_info_data::<
                                i8,
                            >(fory, context, true, true, false)?;
                        }
                    }
                }
                2i16 => {
                    if !&_field.field_type.nullable {
                        _last = fory_core::serializer::read_ref_info_data::<
                            i8,
                        >(fory, context, true, true, false)?;
                    } else {
                        if (context.reader.read_bool()) {
                            _last = <i8 as 
fory_core::serializer::ForyDefault>::fory_default();
                        } else {
                            _last = fory_core::serializer::read_ref_info_data::<
                                i8,
                            >(fory, context, true, true, false)?;
                        }
                    }
                }
                3i16 => {
                    if !&_field.field_type.nullable {
                        _f4 = Some(
                            fory_core::serializer::read_ref_info_data::<
                                String,
                            >(fory, context, true, false, false)?,
                        );
                    } else {
                        if (context.reader.read_bool()) {
                            _f4 = Some(
                                <String as 
fory_core::serializer::ForyDefault>::fory_default(),
                            );
                        } else {
                            _f4 = Some(
                                fory_core::serializer::read_ref_info_data::<
                                    String,
                                >(fory, context, true, false, false)?,
                            );
                        }
                    }
                }
                4i16 => {
                    if !&_field.field_type.nullable {
                        _f3 = Some(
                            fory_core::serializer::read_ref_info_data::<
                                Vec<i8>,
                            >(fory, context, true, false, false)?,
                        );
                    } else {
                        if (context.reader.read_bool()) {
                            _f3 = Some(
                                <Vec<
                                    i8,
                                > as 
fory_core::serializer::ForyDefault>::fory_default(),
                            );
                        } else {
                            _f3 = Some(
                                fory_core::serializer::read_ref_info_data::<
                                    Vec<i8>,
                                >(fory, context, true, false, false)?,
                            );
                        }
                    }
                }
                5i16 => {
                    if !&_field.field_type.nullable {
                        _f6 = Some(
                            fory_core::serializer::read_ref_info_data::<
                                Vec<i16>,
                            >(fory, context, true, false, false)?,
                        );
                    } else {
                        if (context.reader.read_bool()) {
                            _f6 = Some(
                                <Vec<
                                    i16,
                                > as 
fory_core::serializer::ForyDefault>::fory_default(),
                            );
                        } else {
                            _f6 = Some(
                                fory_core::serializer::read_ref_info_data::<
                                    Vec<i16>,
                                >(fory, context, true, false, false)?,
                            );
                        }
                    }
                }
                6i16 => {
                    if !&_field.field_type.nullable {
                        _f1 = Some(
                            fory_core::serializer::read_ref_info_data::<
                                HashMap<i8, Vec<i8>>,
                            >(fory, context, true, false, false)?,
                        );
                    } else {
                        if (context.reader.read_bool()) {
                            _f1 = Some(
                                <HashMap<
                                    i8,
                                    Vec<i8>,
                                > as 
fory_core::serializer::ForyDefault>::fory_default(),
                            );
                        } else {
                            _f1 = Some(
                                fory_core::serializer::read_ref_info_data::<
                                    HashMap<i8, Vec<i8>>,
                                >(fory, context, true, false, false)?,
                            );
                        }
                    }
                }
                _ => {
                    let field_type = &_field.field_type;
                    let read_ref_flag = 
fory_core::serializer::skip::get_read_ref_flag(
                        &field_type,
                    );
                    fory_core::serializer::skip::skip_field_value(
                            fory,
                            context,
                            &field_type,
                            read_ref_flag,
                        )
                        .unwrap();
                }
            }
        }
        Ok(Self {
            f7: _f7,
            f5: _f5,
            last: _last,
            f4: _f4.unwrap_or_default(),
            f3: _f3.unwrap_or_default(),
            f6: _f6.unwrap_or_default(),
            f1: _f1.unwrap_or_default(),
        })
    }
    ```
    
    ## Related issues
    
    #2492 #2545
    
    Closes #2761
    
    ## Does this PR introduce any user-facing change?
    
    <!--
    If any user-facing interface changes, please [open an
    issue](https://github.com/apache/fory/issues/new/choose) describing the
    need to do so and update the document if necessary.
    
    Delete section if not applicable.
    -->
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
    
    <!--
    When the PR has an impact on performance (if you don't know whether the
    PR will have an impact on performance, you can submit the PR first, and
    if it will have impact on performance, the code reviewer will explain
    it), be sure to attach a benchmark data here.
    
    Delete section if not applicable.
    -->
---
 AGENTS.md                                    |   6 +
 CONTRIBUTING.md                              |   2 +
 docs/guide/DEVELOPMENT.md                    |   6 +-
 rust/fory-core/src/buffer.rs                 |   7 +
 rust/fory-core/src/fory.rs                   |   2 +-
 rust/fory-core/src/meta/mod.rs               |   3 +-
 rust/fory-core/src/meta/type_meta.rs         | 169 +++++-----
 rust/fory-core/src/resolver/context.rs       |  11 +-
 rust/fory-core/src/resolver/meta_resolver.rs |  89 ++---
 rust/fory-core/src/resolver/type_resolver.rs |  46 ++-
 rust/fory-core/src/serializer/enum_.rs       |   5 +-
 rust/fory-core/src/serializer/mod.rs         |   6 +-
 rust/fory-core/src/serializer/skip.rs        |  16 +-
 rust/fory-core/src/serializer/struct_.rs     |   9 +-
 rust/fory-derive/src/object/misc.rs          |   5 +
 rust/fory-derive/src/object/read.rs          | 243 ++++++-------
 rust/fory-derive/src/object/serializer.rs    |  16 +-
 rust/fory-derive/src/object/util.rs          | 488 +++------------------------
 rust/tests/tests/compatible/test_struct.rs   |   1 +
 rust/tests/tests/test_simple_struct.rs       |   2 +-
 20 files changed, 377 insertions(+), 755 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 882f20c92..7e2cd126e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -140,6 +140,12 @@ cargo test --features tests
 # run specific test
 cargo test -p fory-tests  --test $test_file $test_method
 
+# run specific test under subdirectory
+cargo test --test mod $dir$::$test_file::$test_method
+
+# inspect generated code by fory derive macro
+cargo expand --test mod $mod$::$file$ > expanded.rs
+
 # Format code
 cargo fmt
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6e8461076..180cd2646 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -64,6 +64,8 @@ cd rust
 cargo test
 # run test with specific test file and method
 cargo test -p fory-tests  --test $test_file $test_method
+# run specific test under subdirectory
+ cargo test --test mod $dir$::$test_file::$test_method
 ```
 
 ### JavaScript
diff --git a/docs/guide/DEVELOPMENT.md b/docs/guide/DEVELOPMENT.md
index 3b7105c85..dc08f8a00 100644
--- a/docs/guide/DEVELOPMENT.md
+++ b/docs/guide/DEVELOPMENT.md
@@ -97,7 +97,11 @@ cargo build
 # run test
 cargo test
 # run specific test
-cargo test -p fory-tests --test $test_file $test_method
+cargo test -p fory-tests  --test $test_file $test_method
+# run specific test under subdirectory
+cargo test --test mod $dir$::$test_file::$test_method
+# inspect generated code by fory derive macro
+cargo expand --test mod $mod$::$file$ > expanded.rs
 ```
 
 #### Environment Requirements
diff --git a/rust/fory-core/src/buffer.rs b/rust/fory-core/src/buffer.rs
index 9baf94c65..a51f6bdc2 100644
--- a/rust/fory-core/src/buffer.rs
+++ b/rust/fory-core/src/buffer.rs
@@ -393,6 +393,13 @@ impl Reader {
         self.cursor
     }
 
+    #[inline(always)]
+    pub fn read_bool(&mut self) -> bool {
+        let result = unsafe { *self.ptr_at(self.cursor) };
+        self.move_next(1);
+        result != 0
+    }
+
     #[inline(always)]
     pub fn read_u8(&mut self) -> u8 {
         let result = unsafe { *self.ptr_at(self.cursor) };
diff --git a/rust/fory-core/src/fory.rs b/rust/fory-core/src/fory.rs
index a4c2b940b..91f4f3474 100644
--- a/rust/fory-core/src/fory.rs
+++ b/rust/fory-core/src/fory.rs
@@ -404,7 +404,7 @@ impl Fory {
         if self.mode == Mode::Compatible {
             let meta_offset = context.reader.read_i32();
             if meta_offset != -1 {
-                bytes_to_skip = context.load_meta(meta_offset as usize);
+                bytes_to_skip = context.load_meta(self.get_type_resolver(), 
meta_offset as usize);
             }
         }
         let result = <T as Serializer>::fory_read(self, context, false);
diff --git a/rust/fory-core/src/meta/mod.rs b/rust/fory-core/src/meta/mod.rs
index d80a13eb8..ce7bd276a 100644
--- a/rust/fory-core/src/meta/mod.rs
+++ b/rust/fory-core/src/meta/mod.rs
@@ -25,6 +25,5 @@ pub use meta_string::{
 };
 pub use string_util::{buffer_rw_string, get_latin1_length, is_latin, 
murmurhash3_x64_128};
 pub use type_meta::{
-    FieldInfo, FieldType, NullableFieldType, TypeMeta, TypeMetaLayer, 
NAMESPACE_ENCODINGS,
-    TYPE_NAME_ENCODINGS,
+    FieldInfo, FieldType, TypeMeta, TypeMetaLayer, NAMESPACE_ENCODINGS, 
TYPE_NAME_ENCODINGS,
 };
diff --git a/rust/fory-core/src/meta/type_meta.rs 
b/rust/fory-core/src/meta/type_meta.rs
index 0ae8e6c5a..2dbbe06a9 100644
--- a/rust/fory-core/src/meta/type_meta.rs
+++ b/rust/fory-core/src/meta/type_meta.rs
@@ -21,10 +21,12 @@ use crate::meta::{
     murmurhash3_x64_128, Encoding, MetaString, MetaStringDecoder, 
FIELD_NAME_DECODER,
     FIELD_NAME_ENCODER, NAMESPACE_DECODER, TYPE_NAME_DECODER,
 };
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 use crate::types::{TypeId, PRIMITIVE_TYPES};
 use anyhow::anyhow;
 use std::clone::Clone;
 use std::cmp::min;
+use std::collections::HashMap;
 
 const SMALL_NUM_FIELDS_THRESHOLD: usize = 0b11111;
 const REGISTER_BY_NAME_FLAG: u8 = 0b100000;
@@ -59,57 +61,20 @@ static FIELD_NAME_ENCODINGS: &[Encoding] = &[
 #[derive(Debug, Eq, Clone)]
 pub struct FieldType {
     pub type_id: u32,
-    pub generics: Vec<FieldType>,
-}
-
-#[derive(Debug, Clone)]
-pub struct NullableFieldType {
-    pub type_id: u32,
-    pub generics: Vec<NullableFieldType>,
     pub nullable: bool,
+    pub generics: Vec<FieldType>,
 }
 
-impl NullableFieldType {
-    pub fn from(node: &FieldType) -> Self {
-        if node.type_id == TypeId::ForyNullable as u32 {
-            let inner = NullableFieldType::from(&node.generics[0]);
-            NullableFieldType {
-                type_id: inner.type_id,
-                generics: inner.generics,
-                nullable: true,
-            }
-        } else {
-            let generics = 
node.generics.iter().map(NullableFieldType::from).collect();
-            NullableFieldType {
-                type_id: node.type_id,
-                generics,
-                nullable: false,
-            }
-        }
-    }
-}
-
-impl PartialEq for NullableFieldType {
-    fn eq(&self, other: &Self) -> bool {
-        self.type_id == other.type_id && self.generics == other.generics
-    }
-}
-
-impl Eq for NullableFieldType {}
-
 impl FieldType {
-    pub fn new(type_id: u32, generics: Vec<FieldType>) -> Self {
-        FieldType { type_id, generics }
+    pub fn new(type_id: u32, nullable: bool, generics: Vec<FieldType>) -> Self 
{
+        FieldType {
+            type_id,
+            nullable,
+            generics,
+        }
     }
 
     fn to_bytes(&self, writer: &mut Writer, write_flag: bool, nullable: bool) 
-> Result<(), Error> {
-        if self.type_id == TypeId::ForyNullable as u32 {
-            self.generics
-                .first()
-                .unwrap()
-                .to_bytes(writer, write_flag, true)?;
-            return Ok(());
-        }
         let mut header = self.type_id;
         if write_flag {
             header <<= 2;
@@ -147,11 +112,12 @@ impl FieldType {
             type_id = header;
             _nullable = nullable.unwrap();
         }
-        let field_type = match type_id {
+        match type_id {
             x if x == TypeId::LIST as u32 || x == TypeId::SET as u32 => {
                 let generic = Self::from_bytes(reader, true, None);
                 Self {
                     type_id,
+                    nullable: _nullable,
                     generics: vec![generic],
                 }
             }
@@ -160,21 +126,15 @@ impl FieldType {
                 let val_generic = Self::from_bytes(reader, true, None);
                 Self {
                     type_id,
+                    nullable: _nullable,
                     generics: vec![key_generic, val_generic],
                 }
             }
             _ => Self {
                 type_id,
+                nullable: _nullable,
                 generics: vec![],
             },
-        };
-        if _nullable {
-            Self {
-                type_id: TypeId::ForyNullable as u32,
-                generics: vec![field_type],
-            }
-        } else {
-            field_type
         }
     }
 }
@@ -241,7 +201,7 @@ impl FieldInfo {
         let name_size = name_encoded.len() - 1;
         let mut header: u8 = (min(FIELD_NAME_SIZE_THRESHOLD, name_size) as u8) 
<< 2;
         // let ref_tracking = false;
-        let nullable = self.field_type.type_id == TypeId::ForyNullable as u32;
+        let nullable = self.field_type.nullable;
         // if ref_tracking {
         //     header |= 1;
         // }
@@ -296,6 +256,16 @@ impl TypeMetaLayer {
         }
     }
 
+    pub fn empty() -> TypeMetaLayer {
+        TypeMetaLayer {
+            type_id: 0,
+            namespace: MetaString::default(),
+            type_name: MetaString::default(),
+            register_by_name: false,
+            field_infos: vec![],
+        }
+    }
+
     pub fn get_type_id(&self) -> u32 {
         self.type_id
     }
@@ -396,14 +366,11 @@ impl TypeMetaLayer {
         let mut other_fields = Vec::new();
 
         for field_info in field_infos.into_iter() {
-            let mut type_id = field_info.field_type.type_id;
-            let is_nullable = type_id == TypeId::ForyNullable as u32;
-            if is_nullable {
-                type_id = 
field_info.field_type.generics.first().unwrap().type_id;
-                if PRIMITIVE_TYPES.contains(&type_id) {
-                    nullable_primitive_fields.push(field_info);
-                    continue;
-                }
+            let type_id = field_info.field_type.type_id;
+            let is_nullable = field_info.field_type.nullable;
+            if is_nullable && PRIMITIVE_TYPES.contains(&type_id) {
+                nullable_primitive_fields.push(field_info);
+                continue;
             }
 
             if PRIMITIVE_TYPES.contains(&type_id) {
@@ -447,28 +414,21 @@ impl TypeMetaLayer {
             .contains(&type_id)
         }
         fn numeric_sorter(a: &FieldInfo, b: &FieldInfo) -> std::cmp::Ordering {
-            let (a_id, b_id) = {
-                // for nullable_primitive
-                if a.field_type.type_id == TypeId::ForyNullable as u32 {
-                    (
-                        a.field_type.generics.first().unwrap().type_id,
-                        b.field_type.generics.first().unwrap().type_id,
-                    )
-                } else {
-                    (a.field_type.type_id, b.field_type.type_id)
-                }
-            };
+            let (a_id, b_id) = (a.field_type.type_id, b.field_type.type_id);
             let a_field_name = &a.field_name;
             let b_field_name = &b.field_name;
             let compress_a = is_compress(a_id);
             let compress_b = is_compress(b_id);
             let size_a = get_primitive_type_size(a_id);
             let size_b = get_primitive_type_size(b_id);
-            compress_a
-                .cmp(&compress_b)
-                .then_with(|| size_b.cmp(&size_a))
-                .then_with(|| a_id.cmp(&b_id))
-                .then_with(|| a_field_name.cmp(b_field_name))
+            let a_nullable = a.field_type.nullable;
+            let b_nullable = b.field_type.nullable;
+            a_nullable
+                .cmp(&b_nullable) // non-nullable first
+                .then_with(|| compress_a.cmp(&compress_b)) // fixed-size 
(false) first, then variable-size (true) last
+                .then_with(|| size_b.cmp(&size_a)) // when same compress 
status: larger size first
+                .then_with(|| a_id.cmp(&b_id)) // when same size: smaller type 
id first
+                .then_with(|| a_field_name.cmp(b_field_name)) // when same id: 
lexicographic name
         }
         fn type_then_name_sorter(a: &FieldInfo, b: &FieldInfo) -> 
std::cmp::Ordering {
             a.field_type
@@ -497,7 +457,7 @@ impl TypeMetaLayer {
         sorted_field_infos
     }
 
-    fn from_bytes(reader: &mut Reader) -> TypeMetaLayer {
+    fn from_bytes(reader: &mut Reader, type_resolver: &TypeResolver) -> 
TypeMetaLayer {
         let meta_header = reader.read_u8();
         let register_by_name = (meta_header & REGISTER_BY_NAME_FLAG) != 0;
         let mut num_fields = meta_header as usize & SMALL_NUM_FIELDS_THRESHOLD;
@@ -517,11 +477,23 @@ impl TypeMetaLayer {
             namespace = empty_name.clone();
             type_name = empty_name;
         }
+
         let mut field_infos = Vec::with_capacity(num_fields);
         for _ in 0..num_fields {
             field_infos.push(FieldInfo::from_bytes(reader));
         }
-        let sorted_field_infos = Self::sort_field_infos(field_infos);
+        let mut sorted_field_infos = Self::sort_field_infos(field_infos);
+
+        if register_by_name {
+            if let Some(type_info_current) =
+                type_resolver.get_type_info_by_name(&namespace.original, 
&type_name.original)
+            {
+                Self::assign_field_ids(type_info_current, &mut 
sorted_field_infos);
+            }
+        } else if let Some(type_info_current) = 
type_resolver.get_type_info_by_id(type_id) {
+            Self::assign_field_ids(type_info_current, &mut sorted_field_infos);
+        }
+        // if no type found, keep all fields id as -1 to be skipped.
         TypeMetaLayer::new(
             type_id,
             namespace,
@@ -530,6 +502,32 @@ impl TypeMetaLayer {
             sorted_field_infos,
         )
     }
+
+    fn assign_field_ids(type_info_current: &TypeInfo, field_infos: &mut 
[FieldInfo]) {
+        // convert to map: fiend_name -> field_info
+        let field_info_map = type_info_current
+            .get_type_meta()
+            .get_field_infos()
+            .iter()
+            .map(|field_info| (field_info.field_name.clone(), 
field_info.clone()))
+            .collect::<HashMap<String, FieldInfo>>();
+        for field in field_infos.iter_mut() {
+            match field_info_map.get(&field.field_name.clone()) {
+                Some(local_field_info) => {
+                    if field.field_type.type_id != 
local_field_info.field_type.type_id
+                        || field.field_type.generics != 
local_field_info.field_type.generics
+                    {
+                        field.field_id = -1;
+                    } else {
+                        field.field_id = local_field_info.field_id;
+                    }
+                }
+                None => {
+                    field.field_id = -1;
+                }
+            }
+        }
+    }
 }
 
 #[derive(Debug)]
@@ -560,6 +558,13 @@ impl TypeMeta {
         self.layer.get_namespace().clone()
     }
 
+    pub fn empty() -> TypeMeta {
+        TypeMeta {
+            hash: 0,
+            layer: TypeMetaLayer::empty(),
+        }
+    }
+
     pub fn from_fields(
         type_id: u32,
         namespace: MetaString,
@@ -573,7 +578,7 @@ impl TypeMeta {
         }
     }
     #[allow(unused_assignments)]
-    pub fn from_bytes(reader: &mut Reader) -> TypeMeta {
+    pub fn from_bytes(reader: &mut Reader, type_resolver: &TypeResolver) -> 
TypeMeta {
         let header = reader.read_i64();
         let mut meta_size = header & META_SIZE_MASK;
         if meta_size == META_SIZE_MASK {
@@ -586,7 +591,7 @@ impl TypeMeta {
 
         // let current_meta_size = 0;
         // while current_meta_size < meta_size {}
-        let layer = TypeMetaLayer::from_bytes(reader);
+        let layer = TypeMetaLayer::from_bytes(reader, type_resolver);
         TypeMeta {
             layer,
             hash: header,
diff --git a/rust/fory-core/src/resolver/context.rs 
b/rust/fory-core/src/resolver/context.rs
index 4b3f81cc9..f06738341 100644
--- a/rust/fory-core/src/resolver/context.rs
+++ b/rust/fory-core/src/resolver/context.rs
@@ -24,7 +24,7 @@ use crate::resolver::metastring_resolver::{
     MetaStringBytes, MetaStringReaderResolver, MetaStringWriterResolver,
 };
 use crate::resolver::ref_resolver::{RefReader, RefWriter};
-use crate::resolver::type_resolver::Harness;
+use crate::resolver::type_resolver::{Harness, TypeResolver};
 use std::sync::{Arc, Mutex};
 
 pub struct WriteContext {
@@ -158,10 +158,11 @@ impl ReadContext {
     }
 
     #[inline(always)]
-    pub fn load_meta(&mut self, offset: usize) -> usize {
-        self.meta_resolver.load(&mut Reader::new(
-            &self.reader.slice_after_cursor()[offset..],
-        ))
+    pub fn load_meta(&mut self, type_resolver: &TypeResolver, offset: usize) 
-> usize {
+        self.meta_resolver.load(
+            type_resolver,
+            &mut Reader::new(&self.reader.slice_after_cursor()[offset..]),
+        )
     }
 
     pub fn read_any_typeinfo(&mut self, fory: &Fory) -> Arc<Harness> {
diff --git a/rust/fory-core/src/resolver/meta_resolver.rs 
b/rust/fory-core/src/resolver/meta_resolver.rs
index 6d12d744d..0e15f653f 100644
--- a/rust/fory-core/src/resolver/meta_resolver.rs
+++ b/rust/fory-core/src/resolver/meta_resolver.rs
@@ -19,9 +19,52 @@ use crate::buffer::{Reader, Writer};
 use crate::error::Error;
 use crate::fory::Fory;
 use crate::meta::{Encoding, MetaString, TypeMeta, NAMESPACE_DECODER};
+use crate::TypeResolver;
 use std::collections::HashMap;
 use std::sync::Arc;
 
+#[derive(Default)]
+pub struct MetaWriterResolver {
+    type_defs: Vec<Arc<Vec<u8>>>,
+    type_id_index_map: HashMap<std::any::TypeId, usize>,
+}
+
+#[allow(dead_code)]
+impl MetaWriterResolver {
+    pub fn push(&mut self, type_id: std::any::TypeId, fory: &Fory) -> usize {
+        match self.type_id_index_map.get(&type_id) {
+            None => {
+                let index = self.type_defs.len();
+                self.type_defs.push(
+                    fory.get_type_resolver()
+                        .get_type_info(type_id)
+                        .get_type_def(),
+                );
+                self.type_id_index_map.insert(type_id, index);
+                index
+            }
+            Some(index) => *index,
+        }
+    }
+
+    pub fn to_bytes(&self, writer: &mut Writer) -> Result<(), Error> {
+        writer.write_varuint32(self.type_defs.len() as u32);
+        for item in &self.type_defs {
+            writer.write_bytes(item);
+        }
+        Ok(())
+    }
+
+    pub fn empty(&mut self) -> bool {
+        self.type_defs.is_empty()
+    }
+
+    pub fn reset(&mut self) {
+        self.type_defs.clear();
+        self.type_id_index_map.clear();
+    }
+}
+
 #[derive(Default)]
 pub struct MetaReaderResolver {
     pub reading_type_defs: Vec<Arc<TypeMeta>>,
@@ -32,11 +75,11 @@ impl MetaReaderResolver {
         unsafe { self.reading_type_defs.get_unchecked(index) }
     }
 
-    pub fn load(&mut self, reader: &mut Reader) -> usize {
+    pub fn load(&mut self, type_resolver: &TypeResolver, reader: &mut Reader) 
-> usize {
         let meta_size = reader.read_varuint32();
         // self.reading_type_defs.reserve(meta_size as usize);
         for _ in 0..meta_size {
-            let type_meta = TypeMeta::from_bytes(reader);
+            let type_meta = TypeMeta::from_bytes(reader, type_resolver);
             self.reading_type_defs.push(Arc::new(type_meta));
         }
         reader.get_cursor()
@@ -71,45 +114,3 @@ impl MetaReaderResolver {
         self.reading_type_defs.clear();
     }
 }
-
-#[derive(Default)]
-pub struct MetaWriterResolver {
-    type_defs: Vec<Arc<Vec<u8>>>,
-    type_id_index_map: HashMap<std::any::TypeId, usize>,
-}
-
-#[allow(dead_code)]
-impl MetaWriterResolver {
-    pub fn push(&mut self, type_id: std::any::TypeId, fory: &Fory) -> usize {
-        match self.type_id_index_map.get(&type_id) {
-            None => {
-                let index = self.type_defs.len();
-                self.type_defs.push(
-                    fory.get_type_resolver()
-                        .get_type_info(type_id)
-                        .get_type_def(),
-                );
-                self.type_id_index_map.insert(type_id, index);
-                index
-            }
-            Some(index) => *index,
-        }
-    }
-
-    pub fn to_bytes(&self, writer: &mut Writer) -> Result<(), Error> {
-        writer.write_varuint32(self.type_defs.len() as u32);
-        for item in &self.type_defs {
-            writer.write_bytes(item);
-        }
-        Ok(())
-    }
-
-    pub fn empty(&mut self) -> bool {
-        self.type_defs.is_empty()
-    }
-
-    pub fn reset(&mut self) {
-        self.type_defs.clear();
-        self.type_id_index_map.clear();
-    }
-}
diff --git a/rust/fory-core/src/resolver/type_resolver.rs 
b/rust/fory-core/src/resolver/type_resolver.rs
index b0f9a5c9d..e9b64f345 100644
--- a/rust/fory-core/src/resolver/type_resolver.rs
+++ b/rust/fory-core/src/resolver/type_resolver.rs
@@ -23,6 +23,7 @@ use crate::meta::{
     TYPE_NAME_ENCODINGS,
 };
 use crate::serializer::{ForyDefault, Serializer, StructSerializer};
+use crate::Reader;
 use std::sync::Arc;
 use std::{any::Any, collections::HashMap};
 
@@ -88,6 +89,7 @@ impl Harness {
 #[derive(Clone, Debug)]
 pub struct TypeInfo {
     type_def: Arc<Vec<u8>>,
+    type_meta: Arc<TypeMeta>,
     type_id: u32,
     namespace: MetaString,
     type_name: MetaString,
@@ -108,14 +110,16 @@ impl TypeInfo {
         let type_name_metastring = TYPE_NAME_ENCODER
             .encode_with_encodings(type_name, TYPE_NAME_ENCODINGS)
             .unwrap();
+        let (type_def_bytes, type_meta) = T::fory_type_def(
+            fory,
+            type_id,
+            namespace_metastring.clone(),
+            type_name_metastring.clone(),
+            register_by_name,
+        );
         TypeInfo {
-            type_def: Arc::from(T::fory_type_def(
-                fory,
-                type_id,
-                namespace_metastring.clone(),
-                type_name_metastring.clone(),
-                register_by_name,
-            )),
+            type_def: Arc::from(type_def_bytes),
+            type_meta: Arc::new(type_meta),
             type_id,
             namespace: namespace_metastring,
             type_name: type_name_metastring,
@@ -144,8 +148,11 @@ impl TypeInfo {
             vec![],
         );
         let type_def = meta.to_bytes().unwrap();
+        let type_resolver = _fory.get_type_resolver();
+        let meta = TypeMeta::from_bytes(&mut Reader::new(&type_def), 
type_resolver);
         TypeInfo {
             type_def: Arc::from(type_def),
+            type_meta: Arc::new(meta),
             type_id,
             namespace: namespace_metastring,
             type_name: type_name_metastring,
@@ -169,6 +176,10 @@ impl TypeInfo {
         self.type_def.clone()
     }
 
+    pub fn get_type_meta(&self) -> Arc<TypeMeta> {
+        self.type_meta.clone()
+    }
+
     pub fn is_registered_by_name(&self) -> bool {
         self.register_by_name
     }
@@ -180,6 +191,8 @@ pub struct TypeResolver {
     type_id_map: HashMap<std::any::TypeId, u32>,
     type_name_map: HashMap<std::any::TypeId, (MetaString, MetaString)>,
     type_info_cache: HashMap<std::any::TypeId, TypeInfo>,
+    type_info_map_by_id: HashMap<u32, TypeInfo>,
+    type_info_map_by_name: HashMap<(String, String), TypeInfo>,
     // Fast lookup by numeric ID for common types
     type_id_index: Vec<u32>,
 }
@@ -194,6 +207,8 @@ impl Default for TypeResolver {
             type_id_map: HashMap::new(),
             type_name_map: HashMap::new(),
             type_info_cache: HashMap::new(),
+            type_info_map_by_id: HashMap::new(),
+            type_info_map_by_name: HashMap::new(),
             type_id_index: Vec::new(),
         };
         resolver.register_builtin_types();
@@ -209,6 +224,7 @@ impl TypeResolver {
             ($ty:ty, $type_id:expr) => {{
                 let type_info = TypeInfo {
                     type_def: Arc::from(vec![]),
+                    type_meta: Arc::new(TypeMeta::empty()),
                     type_id: $type_id as u32,
                     namespace: NAMESPACE_ENCODER
                         .encode_with_encodings("", NAMESPACE_ENCODINGS)
@@ -243,12 +259,21 @@ impl TypeResolver {
     pub fn get_type_info(&self, type_id: std::any::TypeId) -> &TypeInfo {
         self.type_info_cache.get(&type_id).unwrap_or_else(|| {
             panic!(
-                "TypeId {:?} not found in type_info_map, maybe you forgot to 
register some types",
+                "TypeId {:?} not found in type_info registry, maybe you forgot 
to register some types",
                 type_id
             )
         })
     }
 
+    pub fn get_type_info_by_id(&self, id: u32) -> Option<&TypeInfo> {
+        self.type_info_map_by_id.get(&id)
+    }
+
+    pub fn get_type_info_by_name(&self, namespace: &str, type_name: &str) -> 
Option<&TypeInfo> {
+        self.type_info_map_by_name
+            .get(&(namespace.to_owned(), type_name.to_owned()))
+    }
+
     /// Fast path for getting type info by numeric ID (avoids HashMap lookup 
by TypeId)
     pub fn get_type_id(&self, type_id: &std::any::TypeId, id: u32) -> u32 {
         let id_usize = id as usize;
@@ -351,6 +376,8 @@ impl TypeResolver {
             panic!("rs_struct:{:?} already registered", rs_type_id);
         }
         self.type_info_cache.insert(rs_type_id, type_info.clone());
+        self.type_info_map_by_id
+            .insert(type_info.type_id, type_info.clone());
         let index = T::fory_type_index() as usize;
         if index >= self.type_id_index.len() {
             self.type_id_index.resize(index + 1, NO_TYPE_ID);
@@ -380,6 +407,9 @@ impl TypeResolver {
                     to_serializer::<T>,
                 )),
             );
+            let string_key = (namespace.original.clone(), 
type_name.original.clone());
+            self.type_info_map_by_name
+                .insert(string_key, type_info.clone());
         } else {
             let type_id = type_info.type_id;
             if self.serializer_map.contains_key(&type_id) {
diff --git a/rust/fory-core/src/serializer/enum_.rs 
b/rust/fory-core/src/serializer/enum_.rs
index fa3c4c245..da4688955 100644
--- a/rust/fory-core/src/serializer/enum_.rs
+++ b/rust/fory-core/src/serializer/enum_.rs
@@ -38,9 +38,10 @@ pub fn type_def(
     namespace: MetaString,
     type_name: MetaString,
     register_by_name: bool,
-) -> Vec<u8> {
+) -> (Vec<u8>, TypeMeta) {
     let meta = TypeMeta::from_fields(type_id, namespace, type_name, 
register_by_name, vec![]);
-    meta.to_bytes().unwrap()
+    let bytes = meta.to_bytes().unwrap();
+    (bytes, meta)
 }
 
 #[inline(always)]
diff --git a/rust/fory-core/src/serializer/mod.rs 
b/rust/fory-core/src/serializer/mod.rs
index c91eb09ab..5ce462d5f 100644
--- a/rust/fory-core/src/serializer/mod.rs
+++ b/rust/fory-core/src/serializer/mod.rs
@@ -17,7 +17,7 @@
 
 use crate::error::Error;
 use crate::fory::Fory;
-use crate::meta::{MetaString, NAMESPACE_DECODER, TYPE_NAME_DECODER};
+use crate::meta::{MetaString, TypeMeta, NAMESPACE_DECODER, TYPE_NAME_DECODER};
 use crate::resolver::context::{ReadContext, WriteContext};
 use crate::types::{Mode, RefFlag, TypeId, PRIMITIVE_TYPES};
 use anyhow::anyhow;
@@ -318,8 +318,8 @@ pub trait StructSerializer: Serializer + 'static {
         _namespace: MetaString,
         _type_name: MetaString,
         _register_by_name: bool,
-    ) -> Vec<u8> {
-        Vec::default()
+    ) -> (Vec<u8>, TypeMeta) {
+        (Vec::default(), TypeMeta::empty())
     }
 
     fn fory_type_index() -> u32 {
diff --git a/rust/fory-core/src/serializer/skip.rs 
b/rust/fory-core/src/serializer/skip.rs
index dda7ff175..1dd658a68 100644
--- a/rust/fory-core/src/serializer/skip.rs
+++ b/rust/fory-core/src/serializer/skip.rs
@@ -16,7 +16,7 @@
 // under the License.
 
 use crate::error::Error;
-use crate::meta::NullableFieldType;
+use crate::meta::FieldType;
 use crate::resolver::context::ReadContext;
 use crate::serializer::collection::{HAS_NULL, IS_SAME_TYPE};
 use crate::serializer::Serializer;
@@ -24,7 +24,7 @@ use crate::types::{RefFlag, TypeId, BASIC_TYPES, 
CONTAINER_TYPES, PRIMITIVE_TYPE
 use crate::Fory;
 use chrono::{NaiveDate, NaiveDateTime};
 
-pub fn get_read_ref_flag(field_type: &NullableFieldType) -> bool {
+pub fn get_read_ref_flag(field_type: &FieldType) -> bool {
     let nullable = field_type.nullable;
     nullable || !PRIMITIVE_TYPES.contains(&field_type.type_id)
 }
@@ -48,7 +48,7 @@ macro_rules! basic_type_deserialize {
 pub fn skip_field_value(
     fory: &Fory,
     context: &mut ReadContext,
-    field_type: &NullableFieldType,
+    field_type: &FieldType,
     read_ref_flag: bool,
 ) -> Result<(), Error> {
     if read_ref_flag {
@@ -155,9 +155,8 @@ pub fn skip_field_value(
                 let field_infos = type_meta.get_field_infos().to_vec();
                 context.inc_depth()?;
                 for field_info in field_infos.iter() {
-                    let nullable_field_type = 
NullableFieldType::from(&field_info.field_type);
-                    let read_ref_flag = 
get_read_ref_flag(&nullable_field_type);
-                    skip_field_value(fory, context, &nullable_field_type, 
read_ref_flag)?;
+                    let read_ref_flag = 
get_read_ref_flag(&field_info.field_type);
+                    skip_field_value(fory, context, &field_info.field_type, 
read_ref_flag)?;
                 }
                 context.dec_depth();
                 Ok(())
@@ -188,9 +187,8 @@ pub fn skip_field_value(
                 let field_infos = type_meta.get_field_infos().to_vec();
                 context.inc_depth()?;
                 for field_info in field_infos.iter() {
-                    let nullable_field_type = 
NullableFieldType::from(&field_info.field_type);
-                    let read_ref_flag = 
get_read_ref_flag(&nullable_field_type);
-                    skip_field_value(fory, context, &nullable_field_type, 
read_ref_flag)?;
+                    let read_ref_flag = 
get_read_ref_flag(&field_info.field_type);
+                    skip_field_value(fory, context, &field_info.field_type, 
read_ref_flag)?;
                 }
                 context.dec_depth();
             } else if internal_id == ENUM_ID {
diff --git a/rust/fory-core/src/serializer/struct_.rs 
b/rust/fory-core/src/serializer/struct_.rs
index a171d1859..815bf9884 100644
--- a/rust/fory-core/src/serializer/struct_.rs
+++ b/rust/fory-core/src/serializer/struct_.rs
@@ -44,7 +44,7 @@ pub fn type_def<T: Serializer + StructSerializer>(
     type_name: MetaString,
     register_by_name: bool,
     mut field_infos: Vec<FieldInfo>,
-) -> Vec<u8> {
+) -> (Vec<u8>, TypeMeta) {
     let sorted_field_names = T::fory_get_sorted_field_names(fory);
     let mut sorted_field_infos: Vec<FieldInfo> = 
Vec::with_capacity(field_infos.len());
     for name in sorted_field_names.iter() {
@@ -61,6 +61,10 @@ pub fn type_def<T: Serializer + StructSerializer>(
             panic!("Field {} not found in field_infos", name);
         }
     }
+    // assign field id in ascending order
+    for (i, field_info) in sorted_field_infos.iter_mut().enumerate() {
+        field_info.field_id = i as i16;
+    }
     let meta = TypeMeta::from_fields(
         type_id,
         namespace,
@@ -68,7 +72,8 @@ pub fn type_def<T: Serializer + StructSerializer>(
         register_by_name,
         sorted_field_infos,
     );
-    meta.to_bytes().unwrap()
+    let bytes = meta.to_bytes().unwrap();
+    (bytes, meta)
 }
 
 #[inline(always)]
diff --git a/rust/fory-derive/src/object/misc.rs 
b/rust/fory-derive/src/object/misc.rs
index 4a2d1374a..e15750544 100644
--- a/rust/fory-derive/src/object/misc.rs
+++ b/rust/fory-derive/src/object/misc.rs
@@ -87,8 +87,10 @@ pub fn gen_type_def(fields: &[&Field]) -> TokenStream {
                 quote! {
                     fory_core::meta::FieldInfo::new(#name, 
fory_core::meta::FieldType {
                         type_id: fory_core::types::TypeId::LIST as u32,
+                        nullable: false,
                         generics: vec![fory_core::meta::FieldType {
                             type_id: fory_core::types::TypeId::UNKNOWN as u32,
+                            nullable: false,
                             generics: Vec::new()
                         }]
                     })
@@ -100,10 +102,12 @@ pub fn gen_type_def(fields: &[&Field]) -> TokenStream {
                 quote! {
                     fory_core::meta::FieldInfo::new(#name, 
fory_core::meta::FieldType {
                         type_id: fory_core::types::TypeId::MAP as u32,
+                        nullable: false,
                         generics: vec![
                             #key_generic_token,
                             fory_core::meta::FieldType {
                                 type_id: fory_core::types::TypeId::UNKNOWN as 
u32,
+                                nullable: false,
                                 generics: Vec::new()
                             }
                         ]
@@ -114,6 +118,7 @@ pub fn gen_type_def(fields: &[&Field]) -> TokenStream {
                 quote! {
                     fory_core::meta::FieldInfo::new(#name, 
fory_core::meta::FieldType {
                         type_id: fory_core::types::TypeId::UNKNOWN as u32,
+                        nullable: false,
                         generics: Vec::new()
                     })
                 }
diff --git a/rust/fory-derive/src/object/read.rs 
b/rust/fory-derive/src/object/read.rs
index c3ca1c5d7..fc9124638 100644
--- a/rust/fory-derive/src/object/read.rs
+++ b/rust/fory-derive/src/object/read.rs
@@ -15,21 +15,23 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use fory_core::types::RefFlag;
 use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote};
 use syn::{Field, Type};
 
 use super::util::{
     classify_trait_object_field, create_wrapper_types_arc, 
create_wrapper_types_rc,
-    generic_tree_to_tokens, parse_generic_tree, skip_ref_flag, 
NullableTypeNode, StructField,
+    extract_type_name, is_primitive_type, parse_generic_tree, skip_ref_flag, 
StructField,
 };
 
 fn create_private_field_name(field: &Field) -> Ident {
     format_ident!("_{}", field.ident.as_ref().expect(""))
 }
 
-fn create_read_nullable_fn_name(field: &Field) -> Ident {
-    format_ident!("fory_read_nullable_{}", field.ident.as_ref().expect(""))
+fn need_declared_by_option(field: &Field) -> bool {
+    let type_name = extract_type_name(&field.ty);
+    type_name == "Option" || !is_primitive_type(type_name.as_str())
 }
 
 fn declare_var(fields: &[&Field]) -> Vec<TokenStream> {
@@ -47,8 +49,18 @@ fn declare_var(fields: &[&Field]) -> Vec<TokenStream> {
                     }
                 }
                 _ => {
-                    quote! {
-                        let mut #var_name: Option<#ty> = None;
+                    if need_declared_by_option(field) {
+                        quote! {
+                            let mut #var_name: Option<#ty> = None;
+                        }
+                    } else if extract_type_name(&field.ty) == "bool" {
+                        quote! {
+                            let mut #var_name: bool = false;
+                        }
+                    } else {
+                        quote! {
+                            let mut #var_name: #ty = 0 as #ty;
+                        }
                     }
                 }
             }
@@ -74,8 +86,14 @@ fn assign_value(fields: &[&Field]) -> Vec<TokenStream> {
                     }
                 }
                 _ => {
-                    quote! {
-                        #name: #var_name.unwrap_or_default()
+                    if need_declared_by_option(field) {
+                        quote! {
+                            #name: #var_name.unwrap_or_default()
+                        }
+                    } else {
+                        quote! {
+                            #name: #var_name
+                        }
                     }
                 }
             }
@@ -228,29 +246,26 @@ pub fn gen_read_data(fields: &[&Field]) -> TokenStream {
     }
 }
 
-fn gen_read_compatible_match_arm(field: &Field, var_name: &Ident) -> 
TokenStream {
+fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> 
TokenStream {
     let ty = &field.ty;
-    let field_name_str = field.ident.as_ref().unwrap().to_string();
 
     match classify_trait_object_field(ty) {
         StructField::BoxDyn(trait_name) => {
             let from_any_fn = format_ident!("from_any_internal_{}", 
trait_name);
             let helper_mod = format_ident!("__fory_trait_helpers_{}", 
trait_name);
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let ref_flag = context.reader.read_i8();
-                    if ref_flag != fory_core::types::RefFlag::NotNullValue as 
i8 {
-                        panic!("Expected NotNullValue for trait object field");
-                    }
-                    let fory_type_id = context.reader.read_varuint32();
-                    let harness = fory.get_type_resolver()
-                        .get_harness(fory_type_id)
-                        .expect("Type not registered for trait object field");
-                    let deserializer_fn = harness.get_read_fn();
-                    let any_box = deserializer_fn(fory, context, true, 
false).unwrap();
-                    let base_type_id = fory_type_id >> 8;
-                    #var_name = #helper_mod::#from_any_fn(any_box, 
base_type_id).unwrap();
+                let ref_flag = context.reader.read_i8();
+                if ref_flag != fory_core::types::RefFlag::NotNullValue as i8 {
+                    panic!("Expected NotNullValue for trait object field");
                 }
+                let fory_type_id = context.reader.read_varuint32();
+                let harness = fory.get_type_resolver()
+                    .get_harness(fory_type_id)
+                    .expect("Type not registered for trait object field");
+                let deserializer_fn = harness.get_read_fn();
+                let any_box = deserializer_fn(fory, context, true, false)?;
+                let base_type_id = fory_type_id >> 8;
+                #var_name = #helper_mod::#from_any_fn(any_box, base_type_id)?;
             }
         }
         StructField::RcDyn(trait_name) => {
@@ -258,10 +273,8 @@ fn gen_read_compatible_match_arm(field: &Field, var_name: 
&Ident) -> TokenStream
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let wrapper = <#wrapper_ty as 
fory_core::serializer::Serializer>::fory_read(fory, context, true).unwrap();
-                    #var_name = Some(std::rc::Rc::<dyn 
#trait_ident>::from(wrapper));
-                }
+                let wrapper = <#wrapper_ty as 
fory_core::serializer::Serializer>::fory_read(fory, context, true)?;
+                #var_name = Some(std::rc::Rc::<dyn 
#trait_ident>::from(wrapper));
             }
         }
         StructField::ArcDyn(trait_name) => {
@@ -269,10 +282,8 @@ fn gen_read_compatible_match_arm(field: &Field, var_name: 
&Ident) -> TokenStream
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let wrapper = <#wrapper_ty as 
fory_core::serializer::Serializer>::fory_read(fory, context, true).unwrap();
-                    #var_name = Some(std::sync::Arc::<dyn 
#trait_ident>::from(wrapper));
-                }
+                let wrapper = <#wrapper_ty as 
fory_core::serializer::Serializer>::fory_read(fory, context, true)?;
+                #var_name = Some(std::sync::Arc::<dyn 
#trait_ident>::from(wrapper));
             }
         }
         StructField::VecRc(trait_name) => {
@@ -280,12 +291,10 @@ fn gen_read_compatible_match_arm(field: &Field, var_name: 
&Ident) -> TokenStream
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let wrapper_vec = <Vec<#wrapper_ty> as 
fory_core::serializer::Serializer>::fory_read(fory, context, true).unwrap();
-                    #var_name = Some(wrapper_vec.into_iter()
-                        .map(|w| std::rc::Rc::<dyn #trait_ident>::from(w))
-                        .collect());
-                }
+                let wrapper_vec = <Vec<#wrapper_ty> as 
fory_core::serializer::Serializer>::fory_read(fory, context, true)?;
+                #var_name = Some(wrapper_vec.into_iter()
+                    .map(|w| std::rc::Rc::<dyn #trait_ident>::from(w))
+                    .collect());
             }
         }
         StructField::VecArc(trait_name) => {
@@ -293,12 +302,10 @@ fn gen_read_compatible_match_arm(field: &Field, var_name: 
&Ident) -> TokenStream
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let wrapper_vec = <Vec<#wrapper_ty> as 
fory_core::serializer::Serializer>::fory_read(fory, context, true).unwrap();
-                    #var_name = Some(wrapper_vec.into_iter()
-                        .map(|w| std::sync::Arc::<dyn #trait_ident>::from(w))
-                        .collect());
-                }
+                let wrapper_vec = <Vec<#wrapper_ty> as 
fory_core::serializer::Serializer>::fory_read(fory, context, true)?;
+                #var_name = Some(wrapper_vec.into_iter()
+                    .map(|w| std::sync::Arc::<dyn #trait_ident>::from(w))
+                    .collect());
             }
         }
         StructField::HashMapRc(key_ty, trait_name) => {
@@ -306,12 +313,10 @@ fn gen_read_compatible_match_arm(field: &Field, var_name: 
&Ident) -> TokenStream
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let wrapper_map = <std::collections::HashMap<#key_ty, 
#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(fory, context, 
true).unwrap();
-                    #var_name = Some(wrapper_map.into_iter()
-                        .map(|(k, v)| (k, std::rc::Rc::<dyn 
#trait_ident>::from(v)))
-                        .collect());
-                }
+                let wrapper_map = <std::collections::HashMap<#key_ty, 
#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(fory, context, 
true)?;
+                #var_name = Some(wrapper_map.into_iter()
+                    .map(|(k, v)| (k, std::rc::Rc::<dyn 
#trait_ident>::from(v)))
+                    .collect());
             }
         }
         StructField::HashMapArc(key_ty, trait_name) => {
@@ -319,66 +324,61 @@ fn gen_read_compatible_match_arm(field: &Field, var_name: 
&Ident) -> TokenStream
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let wrapper_map = <std::collections::HashMap<#key_ty, 
#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(fory, context, 
true).unwrap();
-                    #var_name = Some(wrapper_map.into_iter()
-                        .map(|(k, v)| (k, std::sync::Arc::<dyn 
#trait_ident>::from(v)))
-                        .collect());
-                }
+                let wrapper_map = <std::collections::HashMap<#key_ty, 
#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(fory, context, 
true)?;
+                #var_name = Some(wrapper_map.into_iter()
+                    .map(|(k, v)| (k, std::sync::Arc::<dyn 
#trait_ident>::from(v)))
+                    .collect());
             }
         }
         StructField::ContainsTraitObject => {
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let skip_ref_flag = 
fory_core::serializer::get_skip_ref_flag::<#ty>(fory);
-                    #var_name = 
Some(fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, 
skip_ref_flag, false)?);
-                }
+                let skip_ref_flag = 
fory_core::serializer::get_skip_ref_flag::<#ty>(fory);
+                #var_name = 
Some(fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, 
skip_ref_flag, false)?);
             }
         }
         StructField::Forward => {
             quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    #var_name = 
Some(fory_core::serializer::Serializer::fory_read(fory, context, 
true).unwrap());
-                }
+                #var_name = 
Some(fory_core::serializer::Serializer::fory_read(fory, context, true)?);
             }
         }
         StructField::None => {
             let generic_tree = parse_generic_tree(ty);
-            let generic_token = generic_tree_to_tokens(&generic_tree);
-            let read_nullable_fn_name = create_read_nullable_fn_name(field);
-
+            let local_nullable = generic_tree.name == "Option";
             let _base_ty = match &ty {
                 Type::Path(type_path) => 
&type_path.path.segments.first().unwrap().ident,
                 _ => panic!("Unsupported type"),
             };
-            quote! {
-                if _field.field_name.as_str() == #field_name_str {
-                    let local_field_type = #generic_token;
-                    if &_field.field_type == &local_field_type {
-                        let skip_ref_flag = 
fory_core::serializer::get_skip_ref_flag::<#ty>(fory);
-                        #var_name = 
Some(fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, 
skip_ref_flag, false).unwrap_or_else(|_err| {
-                            panic!("Err at deserializing {:?}: {:?}", 
#field_name_str, _err);
-                        }));
+            if local_nullable {
+                quote! {
+                    if _field.field_type.nullable {
+                        #var_name = 
Some(fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, 
false, false)?);
                     } else {
-                        let local_nullable_type = 
fory_core::meta::NullableFieldType::from(&local_field_type);
-                        let remote_nullable_type = 
fory_core::meta::NullableFieldType::from(&_field.field_type);
-                        if local_nullable_type != remote_nullable_type {
-                            println!("Type not match, just skip: {}", 
#field_name_str);
-                            let read_ref_flag = 
fory_core::serializer::skip::get_read_ref_flag(&remote_nullable_type);
-                            
fory_core::serializer::skip::skip_field_value(fory, context, 
&remote_nullable_type, read_ref_flag).unwrap();
-                            #var_name = Some(<#ty as 
fory_core::serializer::ForyDefault>::fory_default());
+                        #var_name = Some(
+                            
fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, true, 
false)?
+                        );
+                    }
+                }
+            } else {
+                let dec_by_option = need_declared_by_option(field);
+                if dec_by_option {
+                    quote! {
+                        if !_field.field_type.nullable {
+                            #var_name = 
Some(fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, 
true, false)?);
                         } else {
-                            println!("Try to deserialize_compatible: {}", 
#field_name_str);
-                            #var_name = Some(
-                                Self::#read_nullable_fn_name(
-                                    fory,
-                                    context,
-                                    &local_nullable_type,
-                                    &remote_nullable_type
-                                ).unwrap_or_else(|_err| {
-                                    panic!("Err at deserializing {:?}: {:?}", 
#field_name_str, _err);
-                                })
-                            );
+                            #var_name = 
fory_core::serializer::read_ref_info_data::<Option<#ty>>(fory, context, true, 
false, false)?
+                        }
+                    }
+                } else {
+                    let null_flag = RefFlag::Null as i8;
+                    quote! {
+                        if !_field.field_type.nullable {
+                            #var_name = 
fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, true, 
false)?;
+                        } else {
+                            if context.reader.read_i8() == #null_flag {
+                                #var_name = <#ty as 
fory_core::serializer::ForyDefault>::fory_default();
+                            } else {
+                                #var_name = 
fory_core::serializer::read_ref_info_data::<#ty>(fory, context, true, true, 
false)?;
+                            }
                         }
                     }
                 }
@@ -413,13 +413,24 @@ pub fn gen_read(struct_ident: &Ident) -> TokenStream {
 }
 
 pub fn gen_read_compatible(fields: &[&Field]) -> TokenStream {
-    let pattern_items = fields.iter().map(|field| {
-        let var_name = create_private_field_name(field);
-        gen_read_compatible_match_arm(field, &var_name)
-    });
     let declare_ts: Vec<TokenStream> = declare_var(fields);
     let assign_ts: Vec<TokenStream> = assign_value(fields);
 
+    let match_arms: Vec<TokenStream> = fields
+        .iter()
+        .enumerate()
+        .map(|(i, field)| {
+            let var_name = create_private_field_name(field);
+            let field_id = i as i16;
+            let body = gen_read_compatible_match_arm_body(field, &var_name);
+            quote! {
+                #field_id => {
+                    #body
+                }
+            }
+        })
+        .collect();
+
     quote! {
         let remote_type_id = context.reader.read_varuint32();
         let meta_index = context.reader.read_varuint32();
@@ -434,15 +445,16 @@ pub fn gen_read_compatible(fields: &[&Field]) -> 
TokenStream {
         let high_bytes = &local_type_def[..8];
         let local_type_hash = 
i64::from_le_bytes(high_bytes.try_into().unwrap());
         if meta.get_hash() == local_type_hash {
-            // fast path
             <Self as fory_core::serializer::Serializer>::fory_read_data(fory, 
context, false)
         } else {
             for _field in fields.iter() {
-                #(#pattern_items else)* {
-                    println!("skip {:?}:{:?}", _field.field_name.as_str(), 
_field.field_type);
-                    let nullable_field_type = 
fory_core::meta::NullableFieldType::from(&_field.field_type);
-                    let read_ref_flag = 
fory_core::serializer::skip::get_read_ref_flag(&nullable_field_type);
-                    fory_core::serializer::skip::skip_field_value(fory, 
context, &nullable_field_type, read_ref_flag).unwrap();
+                match _field.field_id {
+                    #(#match_arms)*
+                    _ => {
+                        let field_type = &_field.field_type;
+                        let read_ref_flag = 
fory_core::serializer::skip::get_read_ref_flag(&field_type);
+                        fory_core::serializer::skip::skip_field_value(fory, 
context, &field_type, read_ref_flag).unwrap();
+                    }
                 }
             }
             Ok(Self {
@@ -451,34 +463,3 @@ pub fn gen_read_compatible(fields: &[&Field]) -> 
TokenStream {
         }
     }
 }
-
-pub fn gen_read_nullable(fields: &[&Field]) -> TokenStream {
-    let func_tokens: Vec<TokenStream> = fields
-        .iter()
-        .filter_map(|field| {
-            let ty = &field.ty;
-            match classify_trait_object_field(ty) {
-                StructField::None => {
-                    let fn_name = create_read_nullable_fn_name(field);
-                    let generic_tree = parse_generic_tree(ty);
-                    let nullable_generic_tree = 
NullableTypeNode::from(generic_tree);
-                    let read_tokens = 
nullable_generic_tree.to_read_tokens(&vec![], true);
-                    Some(quote! {
-                        fn #fn_name(
-                            fory: &fory_core::fory::Fory,
-                            context: &mut 
fory_core::resolver::context::ReadContext,
-                            local_nullable_type: 
&fory_core::meta::NullableFieldType,
-                            remote_nullable_type: 
&fory_core::meta::NullableFieldType
-                        ) -> Result<#ty, fory_core::error::Error> {
-                            #read_tokens
-                        }
-                    })
-                }
-                _ => None,
-            }
-        })
-        .collect::<Vec<_>>();
-    quote! {
-        #(#func_tokens)*
-    }
-}
diff --git a/rust/fory-derive/src/object/serializer.rs 
b/rust/fory-derive/src/object/serializer.rs
index 53b07f20d..480784667 100644
--- a/rust/fory-derive/src/object/serializer.rs
+++ b/rust/fory-derive/src/object/serializer.rs
@@ -106,17 +106,6 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> 
TokenStream {
             panic!("Union is not supported")
         }
     };
-    // extra
-    let (deserialize_nullable_ts,) = match &ast.data {
-        syn::Data::Struct(s) => {
-            let fields = sorted_fields(&s.fields);
-            (read::gen_read_nullable(&fields),)
-        }
-        syn::Data::Enum(_s) => (quote! {},),
-        syn::Data::Union(_) => {
-            panic!("Union is not supported")
-        }
-    };
 
     // Allocate a unique type ID once and share it between both functions
     let type_idx = misc::allocate_type_id();
@@ -139,7 +128,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> 
TokenStream {
                 #get_sorted_field_names_ts
             }
 
-            fn fory_type_def(fory: &fory_core::fory::Fory, type_id: u32, 
namespace: fory_core::meta::MetaString, type_name: fory_core::meta::MetaString, 
register_by_name: bool) -> Vec<u8> {
+            fn fory_type_def(fory: &fory_core::fory::Fory, type_id: u32, 
namespace: fory_core::meta::MetaString, type_name: fory_core::meta::MetaString, 
register_by_name: bool) -> (Vec<u8>, fory_core::meta::TypeMeta) {
                 #type_def_ts
             }
         }
@@ -188,9 +177,6 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> 
TokenStream {
                 #read_compatible_ts
             }
         }
-        impl #name {
-            #deserialize_nullable_ts
-        }
     };
     let code = gen.into();
     clear_struct_context();
diff --git a/rust/fory-derive/src/object/util.rs 
b/rust/fory-derive/src/object/util.rs
index 6841dfa14..c0698bf1a 100644
--- a/rust/fory-derive/src/object/util.rs
+++ b/rust/fory-derive/src/object/util.rs
@@ -19,12 +19,12 @@ use crate::util::{
     detect_collection_with_trait_object, is_arc_dyn_trait, is_box_dyn_trait, 
is_rc_dyn_trait,
     CollectionTraitInfo,
 };
-use fory_core::types::{TypeId, BASIC_TYPE_NAMES, CONTAINER_TYPE_NAMES, 
PRIMITIVE_ARRAY_TYPE_MAP};
+use fory_core::types::{TypeId, PRIMITIVE_ARRAY_TYPE_MAP};
 use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote, ToTokens};
 use std::cell::RefCell;
 use std::fmt;
-use syn::{parse_str, Field, GenericArgument, PathArguments, Type};
+use syn::{Field, GenericArgument, PathArguments, Type};
 
 thread_local! {
     static MACRO_CONTEXT: RefCell<Option<MacroContext>> = const 
{RefCell::new(None)};
@@ -212,42 +212,8 @@ pub(super) fn classify_trait_object_field(ty: &Type) -> 
StructField {
 
 #[derive(Debug)]
 pub(super) struct TypeNode {
-    name: String,
-    generics: Vec<TypeNode>,
-}
-
-#[derive(Debug)]
-pub(super) struct NullableTypeNode {
-    name: String,
-    generics: Vec<NullableTypeNode>,
-    nullable: bool,
-}
-
-macro_rules! basic_type_deserialize {
-    ($name:expr, $nullable:expr; $( ($ty_str:expr, $ty:ty) ),* $(,)?) => {
-        match $name {
-            $(
-                $ty_str => {
-                    if $nullable {
-                        quote! {
-                            <$ty as 
fory_core::serializer::Serializer>::fory_read_type_info(fory, context, true);
-                            let res1 = Some(<$ty as 
fory_core::serializer::Serializer>::fory_read_data(fory, context, true)
-                                .map_err(fory_core::error::Error::from)?);
-                            Ok::<Option<$ty>, fory_core::error::Error>(res1)
-                        }
-                    } else {
-                        quote! {
-                            <$ty as 
fory_core::serializer::Serializer>::fory_read_type_info(fory, context, true);
-                            let res2 = <$ty as 
fory_core::serializer::Serializer>::fory_read_data(fory, context, true)
-                                .map_err(fory_core::error::Error::from)?;
-                            Ok::<$ty, fory_core::error::Error>(res2)
-                        }
-                    }
-                }
-            )*
-            _ => unreachable!(),
-        }
-    };
+    pub name: String,
+    pub generics: Vec<TypeNode>,
 }
 
 pub(super) fn try_primitive_vec_type(node: &TypeNode) -> Option<TokenStream> {
@@ -283,377 +249,6 @@ pub(super) fn try_vec_of_option_primitive(node: 
&TypeNode) -> Option<TokenStream
     None
 }
 
-pub(super) fn try_primitive_vec_type_name(node: &NullableTypeNode) -> 
Option<String> {
-    if node.name != "Vec" {
-        return None;
-    }
-    let child = node.generics.first()?;
-    for (generic_name, _, ty_name) in PRIMITIVE_ARRAY_TYPE_MAP {
-        if child.name == *generic_name {
-            return Some(ty_name.to_string());
-        }
-    }
-    None
-}
-
-impl NullableTypeNode {
-    pub(super) fn to_read_tokens(
-        &self,
-        generic_path: &Vec<i8>,
-        read_ref_flag: bool,
-    ) -> TokenStream {
-        let tokens = if let Some(primitive_ty_name) = 
try_primitive_vec_type_name(self) {
-            let ty_type: Type = parse_str(&primitive_ty_name).expect("Invalid 
primitive type name");
-            let nullable = self.nullable;
-            if nullable {
-                quote! {
-                    let res1 = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                        None
-                    } else {
-                        <#ty_type as 
fory_core::serializer::Serializer>::fory_read_type_info(fory, context, true);
-                        Some(<#ty_type as 
fory_core::serializer::Serializer>::fory_read_data(fory, context, true)
-                            .map_err(fory_core::error::Error::from)?)
-                    };
-                    Ok::<Option<#ty_type>, fory_core::error::Error>(res1)
-                }
-            } else {
-                quote! {
-                    let res2 = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                        Vec::default()
-                    } else {
-                        <#ty_type as 
fory_core::serializer::Serializer>::fory_read_type_info(fory, context, true);
-                        <#ty_type as 
fory_core::serializer::Serializer>::fory_read_data(fory, context, true)
-                            .map_err(fory_core::error::Error::from)?
-                    };
-                    Ok::<#ty_type, fory_core::error::Error>(res2)
-                }
-            }
-        } else if BASIC_TYPE_NAMES.contains(&self.name.as_str()) {
-            basic_type_deserialize!(self.name.as_str(), self.nullable;
-                ("bool", bool),
-                ("i8", i8),
-                ("i16", i16),
-                ("i32", i32),
-                ("i64", i64),
-                ("f32", f32),
-                ("f64", f64),
-                ("String", String),
-                ("NaiveDate", chrono::NaiveDate),
-                ("NaiveDateTime", chrono::NaiveDateTime),
-            )
-        } else if CONTAINER_TYPE_NAMES.contains(&self.name.as_str()) {
-            let ty = parse_str::<Type>(&self.to_string()).unwrap();
-            let mut new_path = generic_path.clone();
-            match self.name.as_str() {
-                "Vec" => {
-                    new_path.push(0);
-                    let generic_node = self.generics.first().unwrap();
-                    let element_tokens = 
generic_node.to_read_tokens(&new_path, false);
-                    let element_ty: Type = 
parse_str(&generic_node.to_string()).unwrap();
-                    let vec_ts = quote! {
-                        let length = context.reader.read_varuint32() as usize;
-                        if length == 0 {
-                            Vec::default()
-                        } else {
-                            let mut v = Vec::with_capacity(length);
-                            let header = context.reader.read_u8();
-                            let has_null = (header & 
fory_core::serializer::collection::HAS_NULL) != 0;
-                            let is_same_type = (header & 
fory_core::serializer::collection::IS_SAME_TYPE) != 0;
-                            let read_ref_flag = !(is_same_type && !has_null);
-                            for _ in 0..length {
-                                let ref_flag = if read_ref_flag {
-                                    context.reader.read_i8()
-                                } else {
-                                    fory_core::types::RefFlag::NotNullValue as 
i8
-                                };
-                                let element = if ref_flag == 
fory_core::types::RefFlag::Null as i8 {
-                                    <#element_ty as 
fory_core::serializer::ForyDefault>::fory_default()
-                                } else {
-                                    #element_tokens?
-                                };
-                                v.push(element);
-                            }
-                            v
-                        }
-                    };
-                    if self.nullable {
-                        quote! {
-                            let v = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                                None
-                            } else {
-                                Some({#vec_ts})
-                            };
-                            Ok::<#ty, fory_core::error::Error>(v)
-                        }
-                    } else {
-                        quote! {
-                            let v = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                                Vec::default()
-                            } else {
-                                #vec_ts
-                            };
-                            Ok::<#ty, fory_core::error::Error>(v)
-                        }
-                    }
-                }
-                "HashSet" => {
-                    new_path.push(0);
-                    let generic_node = self.generics.first().unwrap();
-                    let element_tokens = 
generic_node.to_read_tokens(&new_path, false);
-                    let element_ty: Type = 
parse_str(&generic_node.to_string()).unwrap();
-                    let set_ts = quote! {
-                        let length = context.reader.read_varuint32() as usize;
-                        if length == 0 {
-                            HashSet::default()
-                        } else {
-                            let mut s = HashSet::with_capacity(length);
-                            let header = context.reader.read_u8();
-                            let has_null = (header & 
fory_core::serializer::collection::HAS_NULL) != 0;
-                            let is_same_type = (header & 
fory_core::serializer::collection::IS_SAME_TYPE) != 0;
-                            let read_ref_flag = !(is_same_type && !has_null);
-                            for _ in 0..length {
-                                let ref_flag = if read_ref_flag {
-                                    context.reader.read_i8()
-                                } else {
-                                    fory_core::types::RefFlag::NotNullValue as 
i8
-                                };
-                                let element = if ref_flag == 
fory_core::types::RefFlag::Null as i8 {
-                                    <#element_ty as 
fory_core::serializer::ForyDefault>::fory_default()
-                                } else {
-                                    #element_tokens?
-                                };
-                                s.insert(element);
-                            }
-                            s
-                        }
-                    };
-                    if self.nullable {
-                        quote! {
-                            let s = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                                None
-                            } else {
-                                Some({#set_ts})
-                            };
-                            Ok::<#ty, fory_core::error::Error>(s)
-                        }
-                    } else {
-                        quote! {
-                            let s = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                                HashSet::default()
-                            } else {
-                                #set_ts
-                            };
-                            Ok::<#ty, fory_core::error::Error>(s)
-                        }
-                    }
-                }
-                "HashMap" => {
-                    let key_generic_node = self.generics.first().unwrap();
-                    let val_generic_node = self.generics.get(1).unwrap();
-
-                    new_path.push(0);
-                    let key_tokens = 
key_generic_node.to_read_tokens(&new_path, false);
-                    new_path.pop();
-                    new_path.push(1);
-                    let val_tokens = 
val_generic_node.to_read_tokens(&new_path, false);
-
-                    let key_ty: Type = 
parse_str(&key_generic_node.to_string()).unwrap();
-                    let val_ty: Type = 
parse_str(&val_generic_node.to_string()).unwrap();
-
-                    let map_ts = quote! {
-                        let length = context.reader.read_varuint32();
-                        let mut map = HashMap::with_capacity(length as usize);
-                        if length == 0 {
-                            map
-                        } else {
-                            let mut len_counter = 0;
-                            loop {
-                                if len_counter == length {
-                                    break;
-                                }
-                                let header = context.reader.read_u8();
-                                if header & 
fory_core::serializer::map::KEY_NULL != 0 && header & 
fory_core::serializer::map::VALUE_NULL != 0 {
-                                    map.insert(<#key_ty as 
fory_core::serializer::ForyDefault>::fory_default(), <#val_ty as 
fory_core::serializer::ForyDefault>::fory_default());
-                                    len_counter += 1;
-                                    continue;
-                                }
-                                if header & 
fory_core::serializer::map::KEY_NULL != 0 {
-                                    let value: #val_ty = {#val_tokens}?;
-                                    map.insert(<#key_ty as 
fory_core::serializer::ForyDefault>::fory_default(), value);
-                                    len_counter += 1;
-                                    continue;
-                                }
-                                if header & 
fory_core::serializer::map::VALUE_NULL != 0 {
-                                    let key: #key_ty = {#key_tokens}?;
-                                    map.insert(key, <#val_ty as 
fory_core::serializer::ForyDefault>::fory_default());
-                                    len_counter += 1;
-                                    continue;
-                                }
-                                let chunk_size = context.reader.read_u8();
-                                <#key_ty as 
fory_core::serializer::Serializer>::fory_read_type_info(fory, context, true);
-                                <#val_ty as 
fory_core::serializer::Serializer>::fory_read_type_info(fory, context, true);
-                                for _ in (0..chunk_size).enumerate() {
-                                    let key: #key_ty = {#key_tokens}?;
-                                    let value: #val_ty = {#val_tokens}?;
-                                    map.insert(key, value);
-                                }
-                                len_counter += chunk_size as u32;
-                            }
-                            map
-                        }
-                    };
-                    if self.nullable {
-                        quote! {
-                            let m = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                                None
-                            } else {
-                                Some({#map_ts})
-                            };
-                            Ok::<#ty, fory_core::error::Error>(m)
-                        }
-                    } else {
-                        quote! {
-                            let m = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                                HashMap::default()
-                            } else {
-                                #map_ts
-                            };
-                            Ok::<#ty, fory_core::error::Error>(m)
-                        }
-                    }
-                }
-                _ => quote! { compile_error!("Unsupported type for 
container"); },
-            }
-        } else {
-            // struct or enum
-            let nullable_ty = 
parse_str::<Type>(&self.nullable_ty_string()).unwrap();
-            let ty = parse_str::<Type>(&self.to_string()).unwrap();
-            let ts = if self.nullable {
-                quote! {
-                    let res1 = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                        None
-                    } else {
-                        let type_id = cur_remote_nullable_type.type_id;
-                        let internal_id = type_id & 0xff;
-                        Some(
-                            if internal_id == COMPATIBLE_STRUCT_ID
-                                || internal_id == NAMED_COMPATIBLE_STRUCT_ID
-                                || internal_id == ENUM_ID
-                                || internal_id == NAMED_ENUM_ID
-                                || internal_id == EXT_ID
-                                || internal_id == NAMED_EXT_ID
-                            {
-                                <#nullable_ty as 
fory_core::serializer::Serializer>::fory_read_compatible(fory, context)
-                                    .map_err(fory_core::error::Error::from)?
-                            } else {
-                                unimplemented!()
-                            }
-                        )
-                    };
-                    Ok::<#ty, fory_core::error::Error>(res1)
-                }
-            } else {
-                quote! {
-                    let res2 = if cur_remote_nullable_type.nullable && 
ref_flag == (fory_core::types::RefFlag::Null as i8) {
-                        <#ty as 
fory_core::serializer::ForyDefault>::fory_default()
-                    } else {
-                        let type_id = cur_remote_nullable_type.type_id;
-                        let internal_id = type_id & 0xff;
-                        if internal_id == COMPATIBLE_STRUCT_ID
-                            || internal_id == NAMED_COMPATIBLE_STRUCT_ID
-                            || internal_id == ENUM_ID
-                            || internal_id == NAMED_ENUM_ID
-                            || internal_id == EXT_ID
-                            || internal_id == NAMED_EXT_ID
-                        {
-                            <#nullable_ty as 
fory_core::serializer::Serializer>::fory_read_compatible(fory, context)
-                                .map_err(fory_core::error::Error::from)?
-                        } else {
-                            unimplemented!()
-                        }
-                    };
-                    Ok::<#ty, fory_core::error::Error>(res2)
-                }
-            };
-            quote! {
-                const COMPATIBLE_STRUCT_ID: u32 = 
fory_core::types::TypeId::COMPATIBLE_STRUCT as u32;
-                const ENUM_ID: u32 = fory_core::types::TypeId::ENUM as u32;
-                const NAMED_COMPATIBLE_STRUCT_ID: u32 = 
fory_core::types::TypeId::NAMED_COMPATIBLE_STRUCT as u32;
-                const NAMED_ENUM_ID: u32 = 
fory_core::types::TypeId::NAMED_ENUM as u32;
-                const EXT_ID: u32 = fory_core::types::TypeId::EXT as u32;
-                const NAMED_EXT_ID: u32 = fory_core::types::TypeId::NAMED_EXT 
as u32;
-                #ts
-            }
-        };
-        let mut cur_remote_nullable_type = quote! { remote_nullable_type };
-        for idx in generic_path {
-            cur_remote_nullable_type = quote! {
-                #cur_remote_nullable_type.generics.get(#idx as usize).unwrap()
-            };
-        }
-        let read_ref_flag_ts = if read_ref_flag {
-            quote! {
-                let read_ref_flag = 
fory_core::serializer::skip::get_read_ref_flag(cur_remote_nullable_type);
-                let ref_flag = if read_ref_flag {
-                    context.reader.read_i8()
-                } else {
-                    fory_core::types::RefFlag::NotNullValue as i8
-                };
-                if ref_flag == fory_core::types::RefFlag::Null as i8 {
-                    Ok(Default::default())
-                } else {
-                    #tokens
-                }
-            }
-        } else {
-            quote! { #tokens }
-        };
-        quote! {
-            let cur_remote_nullable_type = &#cur_remote_nullable_type;
-            #read_ref_flag_ts
-        }
-    }
-
-    pub(super) fn from(node: TypeNode) -> Self {
-        if node.name == "Option" {
-            let inner = 
NullableTypeNode::from(node.generics.into_iter().next().unwrap());
-            NullableTypeNode {
-                name: inner.name,
-                generics: inner.generics,
-                nullable: true,
-            }
-        } else {
-            let generics = node
-                .generics
-                .into_iter()
-                .map(NullableTypeNode::from)
-                .collect();
-
-            NullableTypeNode {
-                name: node.name,
-                generics,
-                nullable: false,
-            }
-        }
-    }
-
-    pub(super) fn nullable_ty_string(&self) -> String {
-        if self.generics.is_empty() {
-            self.name.clone()
-        } else {
-            format!(
-                "{}<{}>",
-                self.name,
-                self.generics
-                    .iter()
-                    .map(|g| g.to_string())
-                    .collect::<Vec<_>>()
-                    .join(",")
-            )
-        }
-    }
-}
-
 impl fmt::Display for TypeNode {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if self.generics.is_empty() {
@@ -673,31 +268,7 @@ impl fmt::Display for TypeNode {
     }
 }
 
-impl fmt::Display for NullableTypeNode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let inner_type = if self.generics.is_empty() {
-            self.name.clone()
-        } else {
-            format!(
-                "{}<{}>",
-                self.name,
-                self.generics
-                    .iter()
-                    .map(|g| g.to_string())
-                    .collect::<Vec<_>>()
-                    .join(",")
-            )
-        };
-
-        if self.nullable {
-            write!(f, "Option<{}>", inner_type)
-        } else {
-            write!(f, "{}", inner_type)
-        }
-    }
-}
-
-fn extract_type_name(ty: &Type) -> String {
+pub(super) fn extract_type_name(ty: &Type) -> String {
     if let Type::Path(type_path) = ty {
         type_path.path.segments.last().unwrap().ident.to_string()
     } else if matches!(ty, Type::TraitObject(_)) {
@@ -742,40 +313,55 @@ pub(super) fn parse_generic_tree(ty: &Type) -> TypeNode {
 }
 
 pub(super) fn generic_tree_to_tokens(node: &TypeNode) -> TokenStream {
-    if node.name == "Option" {
-        if let Some(first_generic) = node.generics.first() {
-            if first_generic.name == "Option" {
-                return quote! {
-                    compile_error!("adjacent Options are not supported");
-                };
+    // If Option, unwrap it before generating children
+    let (nullable, base_node) = if node.name == "Option" {
+        if let Some(inner) = node.generics.first() {
+            if inner.name == "Option" {
+                return quote! { compile_error!("Nested adjacent Option is not 
allowed!"); };
             }
+            // Unwrap Option and propagate parsing
+            (true, inner)
+        } else {
+            return quote! { compile_error!("Missing Option inner type"); };
         }
-    }
+    } else {
+        (!PRIMITIVE_TYPE_NAMES.contains(&node.name.as_str()), node)
+    };
 
-    if let Some(ts) = try_vec_of_option_primitive(node) {
+    // Vec<Option<primitive>> rule stays as is
+    if let Some(ts) = try_vec_of_option_primitive(base_node) {
         return ts;
     }
-    let primitive_vec = try_primitive_vec_type(node);
 
+    // Try primitive Vec type
+    let primitive_vec = try_primitive_vec_type(base_node);
+
+    // Recursively generate children token streams
     let children_tokens: Vec<TokenStream> = if primitive_vec.is_none() {
-        node.generics.iter().map(generic_tree_to_tokens).collect()
+        base_node
+            .generics
+            .iter()
+            .map(generic_tree_to_tokens)
+            .collect()
     } else {
         vec![]
     };
-    let ty: syn::Type = syn::parse_str(&node.to_string()).unwrap();
-    let get_type_id = if node.name == "Option" {
-        let option_type_id = TypeId::ForyNullable as u32;
-        quote! { #option_type_id }
-    } else if let Some(ts) = primitive_vec {
+
+    // Build the syn::Type from the DISPLAY of base_node, not the original 
node if Option
+    let ty: syn::Type = syn::parse_str(&base_node.to_string()).unwrap();
+
+    let get_type_id = if let Some(ts) = primitive_vec {
         ts
     } else {
         quote! {
             <#ty as fory_core::serializer::Serializer>::fory_get_type_id(fory)
         }
     };
+
     quote! {
         fory_core::meta::FieldType::new(
             #get_type_id,
+            #nullable,
             vec![#(#children_tokens),*] as Vec<fory_core::meta::FieldType>
         )
     }
@@ -807,6 +393,10 @@ fn get_primitive_type_id(ty: &str) -> u32 {
     }
 }
 
+pub(super) fn is_primitive_type(ty: &str) -> bool {
+    PRIMITIVE_TYPE_NAMES.contains(&ty)
+}
+
 fn group_fields_by_type(fields: &[&Field]) -> FieldGroups {
     fn extract_option_inner(s: &str) -> Option<&str> {
         s.strip_prefix("Option<")?.strip_suffix(">")
diff --git a/rust/tests/tests/compatible/test_struct.rs 
b/rust/tests/tests/compatible/test_struct.rs
index 23fd99f2b..b103aa071 100644
--- a/rust/tests/tests/compatible/test_struct.rs
+++ b/rust/tests/tests/compatible/test_struct.rs
@@ -517,6 +517,7 @@ fn named_enum() {
 #[test]
 #[allow(clippy::unnecessary_literal_unwrap)]
 fn boxed() {
+    // cargo expand --test mod compatible::test_struct > e1.rs
     #[derive(ForyObject, Debug, PartialEq)]
     struct Item1 {
         f1: i32,
diff --git a/rust/tests/tests/test_simple_struct.rs 
b/rust/tests/tests/test_simple_struct.rs
index 438554a1e..cf65d437e 100644
--- a/rust/tests/tests/test_simple_struct.rs
+++ b/rust/tests/tests/test_simple_struct.rs
@@ -22,7 +22,7 @@ use std::collections::HashMap;
 
 #[test]
 fn test_simple() {
-    // a single test for cargo expand and analysis
+    // a single test for cargo expand and analysis: `cargo expand --test 
test_simple_struct 2>&1 > expanded.rs`
     // &["f7", "last", "f2", "f5", "f3", "f6", "f1"]
     #[derive(ForyObject, Debug)]
     struct Animal1 {


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


Reply via email to