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 be26deba9 fix(Rust): Move the calculating of TypeMeta::bytes and 
TypeMeta::hash ahead of serialization (#3060)
be26deba9 is described below

commit be26deba903c4689a0d8055d8ad3604e00fa6fb9
Author: urlyy <[email protected]>
AuthorDate: Thu Dec 18 12:36:25 2025 +0800

    fix(Rust): Move the calculating of TypeMeta::bytes and TypeMeta::hash ahead 
of serialization (#3060)
    
    ## What does this PR do?
    Move the calculating of TypeMeta::bytes and TypeMeta::hash ahead of
    serialization.
    The TypeMeta object will save and hold its own bytes and hash when it is
    created.
    
    ## Related issues
    Fixes #3058
    
    ## Does this PR introduce any user-facing change?
    No
---
 rust/fory-core/src/meta/type_meta.rs         | 45 ++++++++++++++++++++--------
 rust/fory-core/src/resolver/type_resolver.rs | 18 +++++------
 rust/tests/tests/test_meta.rs                | 39 ++++++++++++++++++++++++
 3 files changed, 80 insertions(+), 22 deletions(-)

diff --git a/rust/fory-core/src/meta/type_meta.rs 
b/rust/fory-core/src/meta/type_meta.rs
index e21d64651..a4fe08086 100644
--- a/rust/fory-core/src/meta/type_meta.rs
+++ b/rust/fory-core/src/meta/type_meta.rs
@@ -326,6 +326,7 @@ pub struct TypeMeta {
     type_name: Rc<MetaString>,
     register_by_name: bool,
     field_infos: Vec<FieldInfo>,
+    bytes: Vec<u8>,
 }
 
 impl TypeMeta {
@@ -335,15 +336,20 @@ impl TypeMeta {
         type_name: MetaString,
         register_by_name: bool,
         field_infos: Vec<FieldInfo>,
-    ) -> TypeMeta {
-        TypeMeta {
+    ) -> Result<TypeMeta, Error> {
+        let mut meta = TypeMeta {
             hash: 0,
             type_id,
             namespace: Rc::from(namespace),
             type_name: Rc::from(type_name),
             register_by_name,
             field_infos,
-        }
+            bytes: vec![],
+        };
+        let (bytes, meta_hash) = meta.to_bytes()?;
+        meta.bytes = bytes;
+        meta.hash = meta_hash;
+        Ok(meta)
     }
 
     #[inline(always)]
@@ -372,15 +378,25 @@ impl TypeMeta {
     }
 
     #[inline(always)]
-    pub fn empty() -> TypeMeta {
-        TypeMeta {
+    pub fn get_bytes(&self) -> &[u8] {
+        &self.bytes
+    }
+
+    #[inline(always)]
+    pub fn empty() -> Result<TypeMeta, Error> {
+        let mut meta = TypeMeta {
             hash: 0,
             type_id: 0,
             namespace: Rc::from(MetaString::get_empty().clone()),
             type_name: Rc::from(MetaString::get_empty().clone()),
             register_by_name: false,
             field_infos: vec![],
-        }
+            bytes: vec![],
+        };
+        let (bytes, meta_hash) = meta.to_bytes()?;
+        meta.bytes = bytes;
+        meta.hash = meta_hash;
+        Ok(meta)
     }
 
     /// Creates a deep clone with new Rc instances.
@@ -393,6 +409,7 @@ impl TypeMeta {
             type_name: Rc::new((*self.type_name).clone()),
             register_by_name: self.register_by_name,
             field_infos: self.field_infos.clone(),
+            bytes: self.bytes.clone(),
         }
     }
 
@@ -402,7 +419,7 @@ impl TypeMeta {
         type_name: MetaString,
         register_by_name: bool,
         field_infos: Vec<FieldInfo>,
-    ) -> TypeMeta {
+    ) -> Result<TypeMeta, Error> {
         TypeMeta::new(type_id, namespace, type_name, register_by_name, 
field_infos)
     }
 
@@ -628,13 +645,13 @@ impl TypeMeta {
             Self::assign_field_ids(&type_info_current, &mut 
sorted_field_infos);
         }
         // if no type found, keep all fields id as -1 to be skipped.
-        Ok(TypeMeta::new(
+        TypeMeta::new(
             type_id,
             namespace,
             type_name,
             register_by_name,
             sorted_field_infos,
-        ))
+        )
     }
 
     fn assign_field_ids(type_info_current: &TypeInfo, field_infos: &mut 
[FieldInfo]) {
@@ -734,7 +751,7 @@ impl TypeMeta {
         Ok(())
     }
 
-    pub(crate) fn to_bytes(&self) -> Result<Vec<u8>, Error> {
+    fn to_bytes(&self) -> Result<(Vec<u8>, i64), Error> {
         // | global_binary_header | meta_bytes |
         let mut buffer = vec![];
         let mut result = Writer::from_buffer(&mut buffer);
@@ -752,13 +769,15 @@ impl TypeMeta {
         if is_compressed {
             header |= COMPRESS_META_FLAG;
         }
-        let meta_hash = murmurhash3_x64_128(meta_writer.dump().as_slice(), 
47).0 as i64;
-        header |= (meta_hash << (64 - NUM_HASH_BITS)).abs();
+        let hash_value = murmurhash3_x64_128(meta_writer.dump().as_slice(), 
47).0 as i64;
+        let meta_hash_shifted = (hash_value << (64 - NUM_HASH_BITS)).abs();
+        let meta_hash = meta_hash_shifted >> (64 - NUM_HASH_BITS);
+        header |= meta_hash_shifted;
         result.write_i64(header);
         if meta_size >= META_SIZE_MASK {
             result.write_varuint32((meta_size - META_SIZE_MASK) as u32);
         }
         result.write_bytes(meta_buffer.as_slice());
-        Ok(buffer)
+        Ok((buffer, meta_hash))
     }
 }
diff --git a/rust/fory-core/src/resolver/type_resolver.rs 
b/rust/fory-core/src/resolver/type_resolver.rs
index 4a88f8d2c..5f6e67fda 100644
--- a/rust/fory-core/src/resolver/type_resolver.rs
+++ b/rust/fory-core/src/resolver/type_resolver.rs
@@ -166,7 +166,7 @@ impl TypeInfo {
             TYPE_NAME_ENCODER.encode_with_encodings(type_name, 
TYPE_NAME_ENCODINGS)?;
         Ok(TypeInfo {
             type_def: Rc::from(vec![]),
-            type_meta: Rc::new(TypeMeta::empty()),
+            type_meta: Rc::new(TypeMeta::empty()?),
             type_id,
             namespace: Rc::from(namespace_meta_string),
             type_name: Rc::from(type_name_meta_string),
@@ -180,7 +180,7 @@ impl TypeInfo {
         let namespace = type_meta.get_namespace();
         let type_name = type_meta.get_type_name();
         let register_by_name = !namespace.original.is_empty() || 
!type_name.original.is_empty();
-        let type_def_bytes = type_meta.to_bytes()?;
+        let type_def_bytes = type_meta.get_bytes().to_owned();
         Ok(TypeInfo {
             type_def: Rc::from(type_def_bytes),
             type_meta,
@@ -250,7 +250,7 @@ impl TypeInfo {
         let type_id = remote_meta.get_type_id();
         let namespace = remote_meta.get_namespace();
         let type_name = remote_meta.get_type_name();
-        let type_def_bytes = remote_meta.to_bytes().unwrap_or_default();
+        let type_def_bytes = remote_meta.get_bytes().to_owned();
         let register_by_name = !namespace.original.is_empty() || 
!type_name.original.is_empty();
 
         let harness = if let Some(h) = local_harness {
@@ -347,8 +347,8 @@ fn build_struct_type_infos<T: StructSerializer>(
         (*partial_info.type_name).clone(),
         partial_info.register_by_name,
         sorted_field_infos,
-    );
-    let type_def_bytes = type_meta.to_bytes()?;
+    )?;
+    let type_def_bytes = type_meta.get_bytes().to_owned();
     let main_type_info = TypeInfo {
         type_def: Rc::from(type_def_bytes),
         type_meta: Rc::new(type_meta),
@@ -386,7 +386,7 @@ fn build_struct_type_infos<T: StructSerializer>(
                     type_name_ms,
                     true,
                     fields_info.clone(),
-                )
+                )?
             } else {
                 // add a check to avoid collision with main enum type_id
                 // since internal id is big alealdy, `74<<8 = 18944` is big 
enough to avoid collision most of time
@@ -407,7 +407,7 @@ fn build_struct_type_infos<T: StructSerializer>(
                     MetaString::get_empty().clone(),
                     false,
                     fields_info,
-                )
+                )?
             };
 
             let variant_type_info =
@@ -433,8 +433,8 @@ fn build_serializer_type_infos(
         (*partial_info.type_name).clone(),
         partial_info.register_by_name,
         vec![],
-    );
-    let type_def_bytes = type_meta.to_bytes()?;
+    )?;
+    let type_def_bytes = type_meta.get_bytes().to_owned();
     let type_info = TypeInfo {
         type_def: Rc::from(type_def_bytes),
         type_meta: Rc::new(type_meta),
diff --git a/rust/tests/tests/test_meta.rs b/rust/tests/tests/test_meta.rs
new file mode 100644
index 000000000..dd5e85255
--- /dev/null
+++ b/rust/tests/tests/test_meta.rs
@@ -0,0 +1,39 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use fory_core::meta::{FieldInfo, FieldType, MetaString, TypeMeta};
+
+#[test]
+fn test_meta_hash() {
+    let meta = TypeMeta::new(
+        42,
+        MetaString::get_empty().clone(),
+        MetaString::get_empty().clone(),
+        false,
+        vec![FieldInfo {
+            field_id: 43,
+            field_name: "f1".to_string(),
+            field_type: FieldType {
+                type_id: 44,
+                nullable: true,
+                generics: vec![],
+            },
+        }],
+    )
+    .unwrap();
+    assert_ne!(meta.get_hash(), 0);
+}


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

Reply via email to