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]