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 d008f47aa feat(rust): make type meta resolve return type info directly
(#2789)
d008f47aa is described below
commit d008f47aa8fb01c82371aa5723cdeb122eb7c02d
Author: Shawn Yang <[email protected]>
AuthorDate: Tue Oct 21 00:02:13 2025 +0800
feat(rust): make type meta resolve return type info directly (#2789)
## Why?
<!-- Describe the purpose of this PR. -->
## What does this PR do?
make type meta resolve return type info directly to avoid uncesssary
copy
## Related issues
<!--
Is there any related issue? If this PR closes them you say say
fix/closes:
- #xxxx0
- #xxxx1
- Fixes #xxxx2
-->
## 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.
-->
---
rust/fory-core/src/fory.rs | 2 +-
rust/fory-core/src/resolver/context.rs | 24 +++------
rust/fory-core/src/resolver/meta_resolver.rs | 59 ++++++++++++++++-----
rust/fory-core/src/resolver/type_resolver.rs | 78 ++++++++++++++++++++++++----
rust/fory-core/src/serializer/skip.rs | 10 ++--
5 files changed, 130 insertions(+), 43 deletions(-)
diff --git a/rust/fory-core/src/fory.rs b/rust/fory-core/src/fory.rs
index bb1983ee3..ca3f50096 100644
--- a/rust/fory-core/src/fory.rs
+++ b/rust/fory-core/src/fory.rs
@@ -420,7 +420,7 @@ impl Fory {
if context.is_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_type_meta(meta_offset as usize)?;
}
}
let result = <T as Serializer>::fory_read(context, true, true);
diff --git a/rust/fory-core/src/resolver/context.rs
b/rust/fory-core/src/resolver/context.rs
index 64dca6bd0..a347d54a9 100644
--- a/rust/fory-core/src/resolver/context.rs
+++ b/rust/fory-core/src/resolver/context.rs
@@ -19,7 +19,7 @@ use crate::buffer::{Reader, Writer};
use crate::error::Error;
use crate::fory::Fory;
-use crate::meta::{MetaString, TypeMeta};
+use crate::meta::MetaString;
use crate::resolver::meta_resolver::{MetaReaderResolver, MetaWriterResolver};
use crate::resolver::metastring_resolver::{
MetaStringBytes, MetaStringReaderResolver, MetaStringWriterResolver,
@@ -303,14 +303,14 @@ impl ReadContext {
}
#[inline(always)]
- pub fn get_meta(&self, type_index: usize) -> Result<&Rc<TypeMeta>, Error> {
+ pub fn get_type_info_by_index(&self, type_index: usize) ->
Result<&Rc<TypeInfo>, Error> {
self.meta_resolver.get(type_index).ok_or_else(|| {
- Error::type_error(format!("Meta not found for type index: {}",
type_index))
+ Error::type_error(format!("TypeInfo not found for type index: {}",
type_index))
})
}
#[inline(always)]
- pub fn load_meta(&mut self, offset: usize) -> Result<usize, Error> {
+ pub fn load_type_meta(&mut self, offset: usize) -> Result<usize, Error> {
self.meta_resolver.load(
&self.type_resolver,
&mut Reader::new(&self.reader.slice_after_cursor()[offset..]),
@@ -323,22 +323,14 @@ impl ReadContext {
match fory_type_id & 0xff {
types::NAMED_COMPATIBLE_STRUCT | types::COMPATIBLE_STRUCT => {
let meta_index = self.reader.read_varuint32()? as usize;
- let remote_meta = self.get_meta(meta_index)?.clone();
- let local_type_info = self
- .type_resolver
- .get_type_info_by_id(fory_type_id)
- .ok_or_else(|| Error::type_error("ID harness not found"))?;
- // Create a new TypeInfo with remote metadata but local harness
- // TODO: make self.get_meta return type info
- Ok(Rc::new(local_type_info.with_remote_meta(remote_meta)))
+ let type_info =
self.get_type_info_by_index(meta_index)?.clone();
+ Ok(type_info)
}
types::NAMED_ENUM | types::NAMED_EXT | types::NAMED_STRUCT => {
if self.is_share_meta() {
let meta_index = self.reader.read_varuint32()? as usize;
- self.get_meta(meta_index)?;
- self.type_resolver
- .get_type_info_by_id(fory_type_id)
- .ok_or_else(|| Error::type_error("ID harness not
found"))
+ let type_info =
self.get_type_info_by_index(meta_index)?.clone();
+ Ok(type_info)
} else {
let namespace = self.meta_resolver.read_metastring(&mut
self.reader)?;
let type_name = self.meta_resolver.read_metastring(&mut
self.reader)?;
diff --git a/rust/fory-core/src/resolver/meta_resolver.rs
b/rust/fory-core/src/resolver/meta_resolver.rs
index 525caf702..dbd4db05c 100644
--- a/rust/fory-core/src/resolver/meta_resolver.rs
+++ b/rust/fory-core/src/resolver/meta_resolver.rs
@@ -18,6 +18,7 @@
use crate::buffer::{Reader, Writer};
use crate::error::Error;
use crate::meta::{Encoding, MetaString, TypeMeta, NAMESPACE_DECODER};
+use crate::resolver::type_resolver::TypeInfo;
use crate::TypeResolver;
use std::collections::HashMap;
use std::rc::Rc;
@@ -68,13 +69,13 @@ impl MetaWriterResolver {
#[derive(Default)]
pub struct MetaReaderResolver {
- pub reading_type_defs: Vec<Rc<TypeMeta>>,
- parsed_type_defs: HashMap<i64, Rc<TypeMeta>>,
+ pub reading_type_infos: Vec<Rc<TypeInfo>>,
+ parsed_type_infos: HashMap<i64, Rc<TypeInfo>>,
}
impl MetaReaderResolver {
- pub fn get(&self, index: usize) -> Option<&Rc<TypeMeta>> {
- self.reading_type_defs.get(index)
+ pub fn get(&self, index: usize) -> Option<&Rc<TypeInfo>> {
+ self.reading_type_infos.get(index)
}
pub fn load(
@@ -83,11 +84,11 @@ impl MetaReaderResolver {
reader: &mut Reader,
) -> Result<usize, Error> {
let meta_size = reader.read_varuint32()?;
- // self.reading_type_defs.reserve(meta_size as usize);
+ // self.reading_type_infos.reserve(meta_size as usize);
for _ in 0..meta_size {
let meta_header = reader.read_i64()?;
- if let Some(type_meta) = self.parsed_type_defs.get(&meta_header) {
- self.reading_type_defs.push(type_meta.clone());
+ if let Some(type_info) = self.parsed_type_infos.get(&meta_header) {
+ self.reading_type_infos.push(type_info.clone());
TypeMeta::skip_bytes(reader, meta_header)?;
} else {
let type_meta = Rc::new(TypeMeta::from_bytes_with_header(
@@ -95,11 +96,45 @@ impl MetaReaderResolver {
type_resolver,
meta_header,
)?);
- if self.parsed_type_defs.len() < MAX_PARSED_NUM_TYPE_DEFS {
- // avoid malicious type defs to OOM parsed_type_defs
- self.parsed_type_defs.insert(meta_header,
type_meta.clone());
+
+ // Try to find local type info
+ let type_info = if
type_meta.get_namespace().original.is_empty() {
+ // Registered by ID
+ let type_id = type_meta.get_type_id();
+ if let Some(local_type_info) =
type_resolver.get_type_info_by_id(type_id) {
+ // Use local harness with remote metadata
+ Rc::new(TypeInfo::from_remote_meta(
+ type_meta.clone(),
+ Some(local_type_info.get_harness()),
+ ))
+ } else {
+ // No local type found, use stub harness
+ Rc::new(TypeInfo::from_remote_meta(type_meta.clone(),
None))
+ }
+ } else {
+ // Registered by name
+ let namespace = &type_meta.get_namespace().original;
+ let type_name = &type_meta.get_type_name().original;
+ if let Some(local_type_info) =
+ type_resolver.get_type_info_by_name(namespace,
type_name)
+ {
+ // Use local harness with remote metadata
+ Rc::new(TypeInfo::from_remote_meta(
+ type_meta.clone(),
+ Some(local_type_info.get_harness()),
+ ))
+ } else {
+ // No local type found, use stub harness
+ Rc::new(TypeInfo::from_remote_meta(type_meta.clone(),
None))
+ }
+ };
+
+ if self.parsed_type_infos.len() < MAX_PARSED_NUM_TYPE_DEFS {
+ // avoid malicious type defs to OOM parsed_type_infos
+ self.parsed_type_infos
+ .insert(meta_header, type_info.clone());
}
- self.reading_type_defs.push(type_meta);
+ self.reading_type_infos.push(type_info);
}
}
Ok(reader.get_cursor())
@@ -131,6 +166,6 @@ impl MetaReaderResolver {
}
pub fn reset(&mut self) {
- self.reading_type_defs.clear();
+ self.reading_type_infos.clear();
}
}
diff --git a/rust/fory-core/src/resolver/type_resolver.rs
b/rust/fory-core/src/resolver/type_resolver.rs
index 46c676bcd..7da594172 100644
--- a/rust/fory-core/src/resolver/type_resolver.rs
+++ b/rust/fory-core/src/resolver/type_resolver.rs
@@ -214,22 +214,80 @@ impl TypeInfo {
&self.harness
}
- /// Create a new TypeInfo with the same properties but different type_meta.
- /// This is used during deserialization to create a TypeInfo with remote
metadata
- /// while keeping the local harness for deserialization functions.
- pub fn with_remote_meta(&self, remote_meta: Rc<TypeMeta>) -> TypeInfo {
+ /// Create a TypeInfo from remote TypeMeta with a stub harness
+ /// Used when the type doesn't exist locally during deserialization
+ pub fn from_remote_meta(
+ remote_meta: Rc<TypeMeta>,
+ local_harness: Option<&Harness>,
+ ) -> 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 register_by_name = !namespace.original.is_empty() ||
!type_name.original.is_empty();
+
+ let harness = if let Some(h) = local_harness {
+ h.clone()
+ } else {
+ // Create a stub harness that returns errors when called
+ Harness::new(
+ stub_write_fn,
+ stub_read_fn,
+ stub_write_data_fn,
+ stub_read_data_fn,
+ stub_to_serializer_fn,
+ )
+ };
+
TypeInfo {
- type_def: self.type_def.clone(),
+ type_def: Rc::from(type_def_bytes),
type_meta: remote_meta,
- type_id: self.type_id,
- namespace: self.namespace.clone(),
- type_name: self.type_name.clone(),
- register_by_name: self.register_by_name,
- harness: self.harness.clone(),
+ type_id,
+ namespace,
+ type_name,
+ register_by_name,
+ harness,
}
}
}
+// Stub functions for when a type doesn't exist locally
+fn stub_write_fn(
+ _: &dyn Any,
+ _: &mut WriteContext,
+ _: bool,
+ _: bool,
+ _: bool,
+) -> Result<(), Error> {
+ Err(Error::type_error(
+ "Cannot serialize unknown remote type - type not registered locally",
+ ))
+}
+
+fn stub_read_fn(_: &mut ReadContext, _: bool, _: bool) -> Result<Box<dyn Any>,
Error> {
+ Err(Error::type_error(
+ "Cannot deserialize unknown remote type - type not registered locally",
+ ))
+}
+
+fn stub_write_data_fn(_: &dyn Any, _: &mut WriteContext, _: bool) ->
Result<(), Error> {
+ Err(Error::type_error(
+ "Cannot serialize unknown remote type - type not registered locally",
+ ))
+}
+
+fn stub_read_data_fn(_: &mut ReadContext) -> Result<Box<dyn Any>, Error> {
+ Err(Error::type_error(
+ "Cannot deserialize unknown remote type - type not registered locally",
+ ))
+}
+
+fn stub_to_serializer_fn(_: Box<dyn Any>) -> Result<Box<dyn Serializer>,
Error> {
+ Err(Error::type_error(
+ "Cannot convert unknown remote type to serializer",
+ ))
+}
+
/// TypeResolver is a resolver for fast type/serializer dispatch.
#[derive(Clone)]
pub struct TypeResolver {
diff --git a/rust/fory-core/src/serializer/skip.rs
b/rust/fory-core/src/serializer/skip.rs
index 0b9cac214..8cb0d421a 100644
--- a/rust/fory-core/src/serializer/skip.rs
+++ b/rust/fory-core/src/serializer/skip.rs
@@ -158,8 +158,8 @@ pub fn skip_value(
Error::type_mismatch(type_id_num, remote_type_id)
);
let meta_index = context.reader.read_varuint32()?;
- let type_meta = context.get_meta(meta_index as usize)?;
- let field_infos = type_meta.get_field_infos().to_vec();
+ let type_info = context.get_type_info_by_index(meta_index as
usize)?;
+ let field_infos =
type_info.get_type_meta().get_field_infos().to_vec();
context.inc_depth()?;
for field_info in field_infos.iter() {
let read_ref_flag = util::field_requires_ref_flag(
@@ -177,8 +177,9 @@ pub fn skip_value(
Error::type_mismatch(type_id_num, remote_type_id)
);
let meta_index = context.reader.read_varuint32()?;
- let type_meta = context.get_meta(meta_index as usize)?;
+ let type_info = context.get_type_info_by_index(meta_index as
usize)?;
let type_resolver = context.get_type_resolver();
+ let type_meta = type_info.get_type_meta();
type_resolver
.get_ext_name_harness(&type_meta.get_namespace(),
&type_meta.get_type_name())?
.get_read_data_fn()(context)?;
@@ -195,7 +196,8 @@ pub fn skip_value(
if internal_id == COMPATIBLE_STRUCT_ID {
let remote_type_id = context.reader.read_varuint32()?;
let meta_index = context.reader.read_varuint32()?;
- let type_meta = context.get_meta(meta_index as usize)?;
+ let type_info = context.get_type_info_by_index(meta_index as
usize)?;
+ let type_meta = type_info.get_type_meta();
ensure!(
type_meta.get_type_id() == remote_type_id,
Error::type_mismatch(type_meta.get_type_id(),
remote_type_id)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]