diff --git a/rust/fory-core/src/fory.rs b/rust/fory-core/src/fory.rs index c80b1a2dc2..4e9db958df 100644 --- a/rust/fory-core/src/fory.rs +++ b/rust/fory-core/src/fory.rs @@ -414,6 +414,42 @@ impl Fory { result } + pub fn deserialize_into( + &self, + bf: &[u8], + output: &mut T, + ) -> Result<(), Error> { + let pool = self.read_context_pool.get_or_init(|| { + let type_resolver = self.type_resolver.clone(); + let compatible = self.compatible; + let share_meta = self.share_meta; + let xlang = self.xlang; + let max_dyn_depth = self.max_dyn_depth; + + let factory = move || { + let reader = Reader::new(&[]); + ReadContext::new( + reader, + type_resolver.clone(), + compatible, + share_meta, + xlang, + max_dyn_depth, + ) + }; + Pool::new(factory) + }); + let mut context = pool.get(); + context.init(bf, self.max_dyn_depth); + let result = self.deserialize_into_with_context(&mut context, output); + if result.is_ok() { + assert_eq!(context.reader.slice_after_cursor().len(), 0); + } + context.reset(); + pool.put(context); + result + } + pub fn deserialize_with_context( &self, context: &mut ReadContext, @@ -437,6 +473,30 @@ impl Fory { result } + pub fn deserialize_into_with_context( + &self, + context: &mut ReadContext, + output: &mut T, + ) -> Result<(), Error> { + let is_none = self.read_head(&mut context.reader)?; + if is_none { + return Ok(()); + } + let mut bytes_to_skip = 0; + 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)?; + } + } + ::fory_read_into(context, false, output)?; + if bytes_to_skip > 0 { + context.reader.skip(bytes_to_skip)?; + } + context.ref_reader.resolve_callbacks(); + Ok(()) + } + /// Serializes a value of type `T` into a byte vector. /// /// # Type Parameters diff --git a/rust/fory-core/src/serializer/any.rs b/rust/fory-core/src/serializer/any.rs index 1bbfd5d3a8..64b295113c 100644 --- a/rust/fory-core/src/serializer/any.rs +++ b/rust/fory-core/src/serializer/any.rs @@ -73,10 +73,30 @@ impl Serializer for Box { deserialize_any_box(context) } + fn fory_read_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let new_value = deserialize_any_box(context)?; + *output = new_value; + Ok(()) + } + fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result { deserialize_any_box(context) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let new_value = deserialize_any_box(context)?; + *output = new_value; + Ok(()) + } + fn fory_get_type_id(_: &TypeResolver) -> Result { unreachable!("Box has no static type ID - use fory_type_id_dyn") } @@ -168,10 +188,62 @@ impl Serializer for Rc { } } + fn fory_read_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?; + + match ref_flag { + RefFlag::Null => Err(Error::InvalidRef("Rc cannot be null".into())), + RefFlag::Ref => { + let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?; + *output = context + .ref_reader + .get_rc_ref::(ref_id) + .ok_or_else(|| { + Error::InvalidData( + format!("Rc reference {} not found", ref_id).into(), + ) + })?; + Ok(()) + } + RefFlag::NotNullValue => { + context.inc_depth()?; + let harness = context.read_any_typeinfo()?; + let deserializer_fn = harness.get_read_data_fn(); + let boxed = deserializer_fn(context, true)?; + context.dec_depth(); + *output = Rc::::from(boxed); + Ok(()) + } + RefFlag::RefValue => { + context.inc_depth()?; + let harness = context.read_any_typeinfo()?; + let deserializer_fn = harness.get_read_data_fn(); + let boxed = deserializer_fn(context, true)?; + context.dec_depth(); + let rc: Rc = Rc::from(boxed); + context.ref_reader.store_rc_ref(rc.clone()); + *output = rc; + Ok(()) + } + } + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { Self::fory_read(context, is_field) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + Self::fory_read_into(context, _is_field, output) + } + fn fory_get_type_id(_: &TypeResolver) -> Result { unreachable!("Rc has no static type ID - use fory_type_id_dyn") } @@ -263,10 +335,62 @@ impl Serializer for Arc { } } + fn fory_read_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?; + + match ref_flag { + RefFlag::Null => Err(Error::InvalidRef("Arc cannot be null".into())), + RefFlag::Ref => { + let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?; + *output = context + .ref_reader + .get_arc_ref::(ref_id) + .ok_or_else(|| { + Error::InvalidData( + format!("Arc reference {} not found", ref_id).into(), + ) + })?; + Ok(()) + } + RefFlag::NotNullValue => { + context.inc_depth()?; + let harness = context.read_any_typeinfo()?; + let deserializer_fn = harness.get_read_data_fn(); + let boxed = deserializer_fn(context, true)?; + context.dec_depth(); + *output = Arc::::from(boxed); + Ok(()) + } + RefFlag::RefValue => { + context.inc_depth()?; + let harness = context.read_any_typeinfo()?; + let deserializer_fn = harness.get_read_data_fn(); + let boxed = deserializer_fn(context, true)?; + context.dec_depth(); + let arc: Arc = Arc::from(boxed); + context.ref_reader.store_arc_ref(arc.clone()); + *output = arc; + Ok(()) + } + } + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { Self::fory_read(context, is_field) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + Self::fory_read_into(context, _is_field, output) + } + fn fory_get_type_id(_type_resolver: &TypeResolver) -> Result { unreachable!("Arc has no static type ID - use fory_type_id_dyn") } diff --git a/rust/fory-core/src/serializer/arc.rs b/rust/fory-core/src/serializer/arc.rs index e4cbda85e3..f3fa704151 100644 --- a/rust/fory-core/src/serializer/arc.rs +++ b/rust/fory-core/src/serializer/arc.rs @@ -76,12 +76,56 @@ impl Serializer for Arc }) } + fn fory_read_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?; + + match ref_flag { + RefFlag::Null => Err(Error::InvalidRef("Arc cannot be null".into()))?, + RefFlag::Ref => { + let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?; + *output = context + .ref_reader + .get_arc_ref::(ref_id) + .ok_or(Error::InvalidData( + format!("Arc reference {ref_id} not found").into(), + ))?; + Ok(()) + } + RefFlag::NotNullValue => { + let mut inner = T::fory_default(); + T::fory_read_data_into(context, is_field, &mut inner)?; + *output = Arc::new(inner); + Ok(()) + } + RefFlag::RefValue => { + let ref_id = context.ref_reader.reserve_ref_id(); + let mut inner = T::fory_default(); + T::fory_read_data_into(context, is_field, &mut inner)?; + *output = Arc::new(inner); + context.ref_reader.store_arc_ref_at(ref_id, output.clone()); + Ok(()) + } + } + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { // When Arc is nested inside another shared ref, fory_read_data is called. // Delegate to fory_read which handles ref tracking properly. Self::fory_read(context, is_field) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + Self::fory_read_into(context, is_field, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) } diff --git a/rust/fory-core/src/serializer/bool.rs b/rust/fory-core/src/serializer/bool.rs index 9c1642bcd4..1a0c5188fa 100644 --- a/rust/fory-core/src/serializer/bool.rs +++ b/rust/fory-core/src/serializer/bool.rs @@ -35,6 +35,16 @@ impl Serializer for bool { Ok(context.reader.read_u8()? == 1) } + #[inline(always)] + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + *output = context.reader.read_u8()? == 1; + Ok(()) + } + #[inline(always)] fn fory_reserved_space() -> usize { mem::size_of::() diff --git a/rust/fory-core/src/serializer/box_.rs b/rust/fory-core/src/serializer/box_.rs index 6cf8730079..54ad46d8f5 100644 --- a/rust/fory-core/src/serializer/box_.rs +++ b/rust/fory-core/src/serializer/box_.rs @@ -26,6 +26,15 @@ impl Serializer for Box { Ok(Box::new(T::fory_read_data(context, is_field)?)) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + *output = Box::new(T::fory_read_data(context, is_field)?); + Ok(()) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) } diff --git a/rust/fory-core/src/serializer/collection.rs b/rust/fory-core/src/serializer/collection.rs index 25469c5898..728e0ad19b 100644 --- a/rust/fory-core/src/serializer/collection.rs +++ b/rust/fory-core/src/serializer/collection.rs @@ -151,3 +151,43 @@ where .collect::>() } } + +pub fn read_collection_into(context: &mut ReadContext, output: &mut C) -> Result<(), Error> +where + T: Serializer + ForyDefault, + C: FromIterator + Default + Extend, +{ + let len = context.reader.read_varuint32()?; + *output = C::default(); + if len == 0 { + return Ok(()); + } + let header = context.reader.read_u8()?; + let declared = (header & DECL_ELEMENT_TYPE) != 0; + T::fory_read_type_info(context, declared)?; + let has_null = (header & HAS_NULL) != 0; + let is_same_type = (header & IS_SAME_TYPE) != 0; + if T::fory_is_polymorphic() || T::fory_is_shared_ref() { + (0..len).try_for_each(|_| { + let mut element = T::fory_default(); + T::fory_read_into(context, declared, &mut element)?; + output.extend(std::iter::once(element)); + Ok(()) + }) + } else { + let skip_ref_flag = is_same_type && !has_null; + // let skip_ref_flag = crate::serializer::get_skip_ref_flag::(context.get_fory()); + (0..len).try_for_each(|_| { + let mut element = T::fory_default(); + crate::serializer::read_ref_info_data_into( + context, + declared, + skip_ref_flag, + true, + &mut element, + )?; + output.extend(std::iter::once(element)); + Ok(()) + }) + } +} diff --git a/rust/fory-core/src/serializer/datetime.rs b/rust/fory-core/src/serializer/datetime.rs index 7ef84a3055..e83700fbc1 100644 --- a/rust/fory-core/src/serializer/datetime.rs +++ b/rust/fory-core/src/serializer/datetime.rs @@ -46,6 +46,23 @@ impl Serializer for NaiveDateTime { )) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let micros = context.reader.read_i64()?; + let seconds = micros / 1_000_000; + let subsec_micros = (micros % 1_000_000) as u32; + let nanos = subsec_micros * 1_000; + *output = DateTime::from_timestamp(seconds, nanos) + .map(|dt| dt.naive_utc()) + .ok_or(Error::InvalidData( + format!("Date out of range, timestamp micros: {micros}").into(), + ))?; + Ok(()) + } + fn fory_reserved_space() -> usize { mem::size_of::() } @@ -87,6 +104,20 @@ impl Serializer for NaiveDate { )) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let days = context.reader.read_i32()?; + *output = EPOCH + .checked_add_days(Days::new(days as u64)) + .ok_or(Error::InvalidData( + format!("Date out of range, {days} days since epoch").into(), + ))?; + Ok(()) + } + fn fory_reserved_space() -> usize { mem::size_of::() } diff --git a/rust/fory-core/src/serializer/heap.rs b/rust/fory-core/src/serializer/heap.rs index 7c9af1871a..57d4714bc5 100644 --- a/rust/fory-core/src/serializer/heap.rs +++ b/rust/fory-core/src/serializer/heap.rs @@ -20,7 +20,8 @@ use crate::resolver::context::ReadContext; use crate::resolver::context::WriteContext; use crate::resolver::type_resolver::TypeResolver; use crate::serializer::collection::{ - read_collection, read_collection_type_info, write_collection, write_collection_type_info, + read_collection, read_collection_into, read_collection_type_info, write_collection, + write_collection_type_info, }; use crate::serializer::{ForyDefault, Serializer}; @@ -41,6 +42,15 @@ impl Serializer for BinaryHeap { read_collection(context) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + read_collection_into(context, output)?; + Ok(()) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { read_collection_type_info(context, is_field, TypeId::SET as u32) } diff --git a/rust/fory-core/src/serializer/list.rs b/rust/fory-core/src/serializer/list.rs index ba3a954aff..dc994283cd 100644 --- a/rust/fory-core/src/serializer/list.rs +++ b/rust/fory-core/src/serializer/list.rs @@ -27,7 +27,8 @@ use std::collections::{LinkedList, VecDeque}; use std::mem; use super::collection::{ - read_collection, read_collection_type_info, write_collection, write_collection_type_info, + read_collection, read_collection_into, read_collection_type_info, write_collection, + write_collection_type_info, }; fn check_primitive() -> Option { @@ -65,6 +66,17 @@ impl Serializer for Vec { } } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + match check_primitive::() { + Some(_) => primitive_list::fory_read_data_into(context, output), + None => read_collection_into(context, output), + } + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { match check_primitive::() { Some(type_id) => primitive_list::fory_read_type_info(context, is_field, type_id), @@ -120,6 +132,14 @@ impl Serializer for VecDeque { read_collection(context) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + read_collection_into(context, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { read_collection_type_info(context, is_field, TypeId::LIST as u32) } @@ -160,6 +180,14 @@ impl Serializer for LinkedList { read_collection(context) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + read_collection_into(context, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { read_collection_type_info(context, is_field, TypeId::LIST as u32) } diff --git a/rust/fory-core/src/serializer/map.rs b/rust/fory-core/src/serializer/map.rs index 526ef8927e..5d9ebb3938 100644 --- a/rust/fory-core/src/serializer/map.rs +++ b/rust/fory-core/src/serializer/map.rs @@ -20,8 +20,8 @@ use crate::error::Error; use crate::resolver::context::{ReadContext, WriteContext}; use crate::resolver::type_resolver::TypeResolver; use crate::serializer::{ - read_ref_info_data, read_type_info, write_ref_info_data, write_type_info, ForyDefault, - Serializer, + read_ref_info_data, read_ref_info_data_into, read_type_info, write_ref_info_data, + write_type_info, ForyDefault, Serializer, }; use crate::types::{TypeId, SIZE_OF_REF_AND_TYPE}; use std::collections::{BTreeMap, HashMap}; @@ -241,6 +241,88 @@ impl Result<(), Error> { + let len = context.reader.read_varuint32()?; + output.clear(); + if len > 0 { + output.reserve(len as usize); + } + if len == 0 { + return Ok(()); + } + let mut len_counter = 0; + loop { + if len_counter == len { + break; + } + let header = context.reader.read_u8()?; + if header & KEY_NULL != 0 && header & VALUE_NULL != 0 { + output.insert(K::fory_default(), V::fory_default()); + len_counter += 1; + continue; + } + let key_declared = (header & DECL_KEY_TYPE) != 0; + let value_declared = (header & DECL_VALUE_TYPE) != 0; + if header & KEY_NULL != 0 { + let skip_ref_flag = if value_declared { + crate::serializer::get_skip_ref_flag::(context.get_type_resolver())? + } else { + false + }; + let value = read_ref_info_data(context, value_declared, skip_ref_flag, false)?; + output.insert(K::fory_default(), value); + len_counter += 1; + continue; + } + if header & VALUE_NULL != 0 { + let skip_ref_flag = if key_declared { + crate::serializer::get_skip_ref_flag::(context.get_type_resolver())? + } else { + false + }; + let key = read_ref_info_data(context, key_declared, skip_ref_flag, false)?; + output.insert(key, V::fory_default()); + len_counter += 1; + continue; + } + let chunk_size = context.reader.read_u8()?; + K::fory_read_type_info(context, key_declared)?; + V::fory_read_type_info(context, value_declared)?; + + let cur_len = len_counter + chunk_size as u32; + ensure!( + cur_len <= len, + Error::InvalidData( + format!("current length {} exceeds total length {}", cur_len, len).into() + ) + ); + assert!(len_counter + chunk_size as u32 <= len); + for _ in 0..chunk_size { + let mut key = K::fory_default(); + let mut value = V::fory_default(); + if K::fory_is_polymorphic() { + K::fory_read_into(context, key_declared, &mut key)? + } else { + // let skip_ref_flag = crate::serializer::get_skip_ref_flag::(context.get_fory()); + read_ref_info_data_into(context, key_declared, true, true, &mut key)? + }; + if V::fory_is_polymorphic() { + V::fory_read_into(context, value_declared, &mut value)? + } else { + // let skip_ref_flag = crate::serializer::get_skip_ref_flag::(context.get_fory()); + read_ref_info_data_into(context, value_declared, true, true, &mut value)? + }; + output.insert(key, value); + } + len_counter += chunk_size as u32; + } + Ok(()) + } + fn fory_reserved_space() -> usize { size_of::() } @@ -342,6 +424,75 @@ impl Result<(), Error> { + let len = context.reader.read_varuint32()?; + output.clear(); + if len == 0 { + return Ok(()); + } + let mut len_counter = 0; + loop { + if len_counter == len { + break; + } + let header = context.reader.read_u8()?; + if header & KEY_NULL != 0 && header & VALUE_NULL != 0 { + output.insert(K::fory_default(), V::fory_default()); + len_counter += 1; + continue; + } + let key_declared = (header & DECL_KEY_TYPE) != 0; + let value_declared = (header & DECL_VALUE_TYPE) != 0; + if header & KEY_NULL != 0 { + let skip_ref_flag = if value_declared { + crate::serializer::get_skip_ref_flag::(context.get_type_resolver())? + } else { + false + }; + let value = read_ref_info_data(context, value_declared, skip_ref_flag, false)?; + output.insert(K::fory_default(), value); + len_counter += 1; + continue; + } + if header & VALUE_NULL != 0 { + let skip_ref_flag = if key_declared { + crate::serializer::get_skip_ref_flag::(context.get_type_resolver())? + } else { + false + }; + let key = read_ref_info_data(context, key_declared, skip_ref_flag, false)?; + output.insert(key, V::fory_default()); + len_counter += 1; + continue; + } + let chunk_size = context.reader.read_u8()?; + K::fory_read_type_info(context, key_declared)?; + V::fory_read_type_info(context, value_declared)?; + assert!(len_counter + chunk_size as u32 <= len); + for _ in 0..chunk_size { + let mut key = K::fory_default(); + let mut value = V::fory_default(); + if K::fory_is_polymorphic() { + K::fory_read_into(context, key_declared, &mut key)?; + } else { + read_ref_info_data_into(context, key_declared, true, true, &mut key)?; + } + if V::fory_is_polymorphic() { + V::fory_read_into(context, value_declared, &mut value)?; + } else { + read_ref_info_data_into(context, value_declared, true, true, &mut value)?; + } + output.insert(key, value); + } + len_counter += chunk_size as u32; + } + Ok(()) + } + fn fory_reserved_space() -> usize { size_of::() } diff --git a/rust/fory-core/src/serializer/mod.rs b/rust/fory-core/src/serializer/mod.rs index 4e1eca4044..01e94dc223 100644 --- a/rust/fory-core/src/serializer/mod.rs +++ b/rust/fory-core/src/serializer/mod.rs @@ -105,6 +105,45 @@ pub fn read_ref_info_data( } #[inline(always)] +pub fn read_ref_info_data_into( + context: &mut ReadContext, + is_field: bool, + skip_ref_flag: bool, + skip_type_info: bool, + output: &mut T, +) -> Result<(), Error> { + if !skip_ref_flag { + let ref_flag = context.reader.read_i8()?; + if ref_flag == RefFlag::Null as i8 { + *output = T::fory_default(); + Ok(()) + } else if ref_flag == (RefFlag::NotNullValue as i8) { + if !skip_type_info { + T::fory_read_type_info(context, is_field)?; + } + T::fory_read_data_into(context, is_field, output) + } else if ref_flag == (RefFlag::RefValue as i8) { + // First time seeing this referenceable object + if !skip_type_info { + T::fory_read_type_info(context, is_field)?; + } + T::fory_read_data_into(context, is_field, output) + } else if ref_flag == (RefFlag::Ref as i8) { + // This is a reference to a previously deserialized object + // For now, just return default - this should be handled by specific types + *output = T::fory_default(); + Ok(()) + } else { + unimplemented!("Unknown ref flag: {}", ref_flag) + } + } else { + if !skip_type_info { + T::fory_read_type_info(context, is_field)?; + } + T::fory_read_data_into(context, is_field, output) + } +} + pub fn write_type_info( context: &mut WriteContext, is_field: bool, @@ -169,6 +208,17 @@ pub trait Serializer: 'static { read_ref_info_data(context, is_field, false, false) } + fn fory_read_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> + where + Self: Sized + ForyDefault, + { + read_ref_info_data_into(context, is_field, false, false, output) + } + fn fory_is_option() -> bool where Self: Sized, @@ -314,6 +364,14 @@ pub trait Serializer: 'static { where Self: Sized + ForyDefault; + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> + where + Self: Sized + ForyDefault; + fn fory_concrete_type_id(&self) -> std::any::TypeId { std::any::TypeId::of::() } diff --git a/rust/fory-core/src/serializer/mutex.rs b/rust/fory-core/src/serializer/mutex.rs index b3bb0cb45a..12c4d83d70 100644 --- a/rust/fory-core/src/serializer/mutex.rs +++ b/rust/fory-core/src/serializer/mutex.rs @@ -81,10 +81,37 @@ impl Serializer for Mutex { Ok(Mutex::new(T::fory_read(context, is_field)?)) } + fn fory_read_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> + where + Self: Sized + ForyDefault, + { + let inner = output + .get_mut() + .map_err(|_| Error::InvalidData("Failed to get mutable reference to Mutex".into()))?; + T::fory_read_into(context, is_field, inner)?; + Ok(()) + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { Ok(Mutex::new(T::fory_read_data(context, is_field)?)) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let inner = output + .get_mut() + .map_err(|_| Error::InvalidData("Failed to get mutable reference to Mutex".into()))?; + T::fory_read_data_into(context, is_field, inner)?; + Ok(()) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) } diff --git a/rust/fory-core/src/serializer/number.rs b/rust/fory-core/src/serializer/number.rs index c923bb15f4..5a4bfd5b0e 100644 --- a/rust/fory-core/src/serializer/number.rs +++ b/rust/fory-core/src/serializer/number.rs @@ -42,6 +42,16 @@ macro_rules! impl_num_serializer { $reader(&mut context.reader) } + #[inline] + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + *output = $reader(&mut context.reader)?; + Ok(()) + } + #[inline] fn fory_reserved_space() -> usize { std::mem::size_of::<$ty>() diff --git a/rust/fory-core/src/serializer/option.rs b/rust/fory-core/src/serializer/option.rs index 1a6dc0339f..fdc0ccfe19 100644 --- a/rust/fory-core/src/serializer/option.rs +++ b/rust/fory-core/src/serializer/option.rs @@ -27,6 +27,23 @@ impl Serializer for Option { Ok(Some(T::fory_read_data(context, is_field)?)) } + #[inline(always)] + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + match output { + Some(ref mut inner) => T::fory_read_data_into(context, is_field, inner), + None => { + let mut new_value = T::fory_default(); + T::fory_read_data_into(context, is_field, &mut new_value)?; + *output = Some(new_value); + Ok(()) + } + } + } + #[inline(always)] fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) diff --git a/rust/fory-core/src/serializer/primitive_list.rs b/rust/fory-core/src/serializer/primitive_list.rs index 41b19161a9..38ad039b7c 100644 --- a/rust/fory-core/src/serializer/primitive_list.rs +++ b/rust/fory-core/src/serializer/primitive_list.rs @@ -64,6 +64,23 @@ pub fn fory_read_data(context: &mut ReadContext) -> Result, Error> { Ok(vec) } +pub fn fory_read_data_into(context: &mut ReadContext, output: &mut Vec) -> Result<(), Error> { + let size_bytes = context.reader.read_varuint32()? as usize; + if size_bytes % std::mem::size_of::() != 0 { + return Err(Error::InvalidData("Invalid data length".into())); + } + let len = size_bytes / std::mem::size_of::(); + output.clear(); + output.reserve(len); + unsafe { + let dst_ptr = output.as_mut_ptr() as *mut u8; + let src = context.reader.read_bytes(size_bytes)?; + std::ptr::copy_nonoverlapping(src.as_ptr(), dst_ptr, size_bytes); + output.set_len(len); + } + Ok(()) +} + pub fn fory_read_type_info( context: &mut ReadContext, is_field: bool, diff --git a/rust/fory-core/src/serializer/rc.rs b/rust/fory-core/src/serializer/rc.rs index c8750b4a97..12e3884d5e 100644 --- a/rust/fory-core/src/serializer/rc.rs +++ b/rust/fory-core/src/serializer/rc.rs @@ -72,12 +72,52 @@ impl Serializer for Rc { } } + fn fory_read_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?; + match ref_flag { + RefFlag::Null => Err(Error::InvalidRef("Rc cannot be null".into())), + RefFlag::Ref => { + let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?; + *output = context.ref_reader.get_rc_ref::(ref_id).ok_or_else(|| { + Error::InvalidRef(format!("Rc reference {ref_id} not found").into()) + })?; + Ok(()) + } + RefFlag::NotNullValue => { + let mut inner = T::fory_default(); + T::fory_read_data_into(context, is_field, &mut inner)?; + *output = Rc::new(inner); + Ok(()) + } + RefFlag::RefValue => { + let ref_id = context.ref_reader.reserve_ref_id(); + let mut inner = T::fory_default(); + T::fory_read_data_into(context, is_field, &mut inner)?; + *output = Rc::new(inner); + context.ref_reader.store_rc_ref_at(ref_id, output.clone()); + Ok(()) + } + } + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { // When Rc is nested inside another shared ref, fory_read_data is called. // Delegate to fory_read which handles ref tracking properly. Self::fory_read(context, is_field) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + Self::fory_read_into(context, is_field, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) } diff --git a/rust/fory-core/src/serializer/refcell.rs b/rust/fory-core/src/serializer/refcell.rs index e1c194d8d8..2edeea7c38 100644 --- a/rust/fory-core/src/serializer/refcell.rs +++ b/rust/fory-core/src/serializer/refcell.rs @@ -50,10 +50,45 @@ impl Serializer for RefCell { Ok(RefCell::new(T::fory_read(context, is_field)?)) } + fn fory_read_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> + where + Self: Sized + ForyDefault, + { + if let Ok(mut inner) = output.try_borrow_mut() { + T::fory_read_into(context, is_field, &mut inner)?; + Ok(()) + } else { + let mut inner = T::fory_default(); + T::fory_read_into(context, is_field, &mut inner)?; + *output.try_borrow_mut().unwrap() = inner; + Ok(()) + } + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { Ok(RefCell::new(T::fory_read_data(context, is_field)?)) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + if let Ok(mut inner) = output.try_borrow_mut() { + T::fory_read_data_into(context, is_field, &mut inner)?; + Ok(()) + } else { + let mut inner = T::fory_default(); + T::fory_read_data_into(context, is_field, &mut inner)?; + *output.try_borrow_mut().unwrap() = inner; + Ok(()) + } + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) } diff --git a/rust/fory-core/src/serializer/set.rs b/rust/fory-core/src/serializer/set.rs index dd0bfaa0d6..65ddaf3735 100644 --- a/rust/fory-core/src/serializer/set.rs +++ b/rust/fory-core/src/serializer/set.rs @@ -20,7 +20,8 @@ use crate::resolver::context::ReadContext; use crate::resolver::context::WriteContext; use crate::resolver::type_resolver::TypeResolver; use crate::serializer::collection::{ - read_collection, read_collection_type_info, write_collection, write_collection_type_info, + read_collection, read_collection_into, read_collection_type_info, write_collection, + write_collection_type_info, }; use crate::serializer::{ForyDefault, Serializer}; @@ -41,6 +42,14 @@ impl Serializer for HashSet< read_collection(context) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + read_collection_into(context, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { read_collection_type_info(context, is_field, TypeId::SET as u32) } @@ -81,6 +90,14 @@ impl Serializer for BTreeSet { read_collection(context) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + read_collection_into(context, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { read_collection_type_info(context, is_field, TypeId::SET as u32) } diff --git a/rust/fory-core/src/serializer/string.rs b/rust/fory-core/src/serializer/string.rs index ad9b2c25ce..46da546eb7 100644 --- a/rust/fory-core/src/serializer/string.rs +++ b/rust/fory-core/src/serializer/string.rs @@ -76,6 +76,33 @@ impl Serializer for String { Ok(s) } + #[inline] + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let bitor = context.reader.read_varuint36small()?; + let len = bitor >> 2; + let encoding = bitor & 0b11; + let encoding = match encoding { + 0 => StrEncoding::Latin1, + 1 => StrEncoding::Utf16, + 2 => StrEncoding::Utf8, + _ => { + return Err(Error::EncodingError( + format!("wrong encoding value: {}", encoding).into(), + )) + } + }; + *output = match encoding { + StrEncoding::Latin1 => context.reader.read_latin1_string(len as usize), + StrEncoding::Utf16 => context.reader.read_utf16_string(len as usize), + StrEncoding::Utf8 => context.reader.read_utf8_string(len as usize), + }?; + Ok(()) + } + #[inline] fn fory_reserved_space() -> usize { mem::size_of::() diff --git a/rust/fory-core/src/serializer/trait_object.rs b/rust/fory-core/src/serializer/trait_object.rs index 7ee6daf929..d1db806db6 100644 --- a/rust/fory-core/src/serializer/trait_object.rs +++ b/rust/fory-core/src/serializer/trait_object.rs @@ -99,6 +99,25 @@ macro_rules! resolve_and_deserialize { }}; } +#[macro_export] +macro_rules! resolve_and_deserialize_into { + ($fory_type_id:expr, $context:expr, $is_field:expr, $constructor:expr, $output:expr, $trait_name:ident, $($impl_type:ty),+) => {{ + $( + if let Some(registered_type_id) = $context.get_type_resolver().get_fory_type_id(std::any::TypeId::of::<$impl_type>()) { + if $fory_type_id == registered_type_id { + let mut concrete_obj = <$impl_type as $crate::serializer::ForyDefault>::fory_default(); + <$impl_type as $crate::serializer::Serializer>::fory_read_data_into($context, $is_field, &mut concrete_obj)?; + *$output = $constructor(concrete_obj); + return Ok(()); + } + } + )* + Err($crate::error::Error::TypeError( + format!("Type ID {} not registered for trait {}", $fory_type_id, stringify!($trait_name)).into() + )) + }}; +} + /// Macro to register trait object conversions for custom traits. /// /// This macro automatically generates serializers for `Box` trait objects. @@ -250,12 +269,29 @@ macro_rules! register_trait_type { result } + fn fory_read_into(context: &mut $crate::resolver::context::ReadContext, is_field: bool, output: &mut Self) -> Result<(), $crate::error::Error> { + context.inc_depth()?; + let fory_type_id = $crate::serializer::trait_object::read_trait_object_headers(context)?; + $crate::resolve_and_deserialize_into!( + fory_type_id, context, is_field, + |obj| Box::new(obj) as Box, + output, + $trait_name, $($impl_type),+ + )?; + context.dec_depth(); + Ok(()) + } + fn fory_read_data(_context: &mut $crate::resolver::context::ReadContext, _is_field: bool) -> Result { // This should not be called for polymorphic types like Box // The fory_read method handles the polymorphic dispatch panic!("fory_read_data should not be called directly on polymorphic Box trait object", stringify!($trait_name)); } + fn fory_read_data_into(context: &mut $crate::resolver::context::ReadContext, is_field: bool, output: &mut Self) -> Result<(), $crate::error::Error> { + panic!("fory_read_data_into should not be called directly on polymorphic Box trait object", stringify!($trait_name)); + } + fn fory_get_type_id(_type_resolver: &$crate::resolver::type_resolver::TypeResolver) -> Result { Ok($crate::types::TypeId::STRUCT as u32) } @@ -481,6 +517,71 @@ macro_rules! impl_smart_pointer_serializer { } } } + + fn fory_read_into(context: &mut $crate::resolver::context::ReadContext, is_field: bool, output: &mut Self) -> Result<(), $crate::error::Error> { + use $crate::types::RefFlag; + + let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?; + + match ref_flag { + RefFlag::Null => Err($crate::error::Error::InvalidRef( + format!("{} cannot be null", stringify!($pointer_type), stringify!($trait_name)).into() + )), + RefFlag::Ref => { + let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?; + *output = context.ref_reader.$get_ref::(ref_id) + .map(|ptr| Self::from(ptr)) + .ok_or_else(|| $crate::error::Error::InvalidData( + format!("{} reference {} not found", stringify!($pointer_type), stringify!($trait_name), ref_id).into() + ))?; + Ok(()) + } + RefFlag::NotNullValue => { + context.inc_depth()?; + let harness = context.read_any_typeinfo()?; + let deserializer_fn = harness.get_read_data_fn(); + let boxed_any = deserializer_fn(context, is_field)?; + context.dec_depth(); + + $( + if boxed_any.is::<$impl_type>() { + let concrete = boxed_any.downcast::<$impl_type>() + .map_err(|_| $crate::error::Error::TypeError("Downcast failed".into()))?; + let ptr = $constructor_expr(*concrete) as $pointer_type; + *output = Self::from(ptr); + return Ok(()); + } + )* + + Err($crate::error::Error::TypeError( + format!("Deserialized type does not implement trait {}", stringify!($trait_name)).into() + )) + } + RefFlag::RefValue => { + context.inc_depth()?; + let harness = context.read_any_typeinfo()?; + let deserializer_fn = harness.get_read_data_fn(); + let boxed_any = deserializer_fn(context, is_field)?; + context.dec_depth(); + + $( + if boxed_any.is::<$impl_type>() { + let concrete = boxed_any.downcast::<$impl_type>() + .map_err(|_| $crate::error::Error::TypeError("Downcast failed".into()))?; + let ptr = $constructor_expr(*concrete) as $pointer_type; + context.ref_reader.$store_ref(ptr.clone()); + *output = Self::from(ptr); + return Ok(()); + } + )* + + Err($crate::error::Error::TypeError( + format!("Deserialized type does not implement trait {}", stringify!($trait_name)).into() + )) + } + } + } + fn fory_read_data(context: &mut $crate::resolver::context::ReadContext, is_field: bool) -> Result { let concrete_fory_type_id = context.reader.read_varuint32()?; $crate::resolve_and_deserialize!( @@ -493,6 +594,20 @@ macro_rules! impl_smart_pointer_serializer { ) } + fn fory_read_data_into(context: &mut $crate::resolver::context::ReadContext, is_field: bool, output: &mut Self) -> Result<(), $crate::error::Error> { + let concrete_fory_type_id = context.reader.read_varuint32()?; + $crate::resolve_and_deserialize_into!( + concrete_fory_type_id, context, is_field, + |obj| { + let pointer = $constructor_expr(obj) as $pointer_type; + Self::from(pointer) + }, + output, + $trait_name, $($impl_type),+ + )?; + Ok(()) + } + fn fory_get_type_id(_type_resolver: &$crate::resolver::type_resolver::TypeResolver) -> Result { Ok($crate::types::TypeId::STRUCT as u32) } @@ -616,9 +731,63 @@ impl Serializer for Box { } } } + + fn fory_read_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let fory_type_id = read_trait_object_headers(context)?; + context.inc_depth()?; + let type_resolver = context.get_type_resolver(); + + if let Some(harness) = type_resolver.get_harness(fory_type_id) { + let deserializer_fn = harness.get_read_fn(); + let to_serializer_fn = harness.get_to_serializer(); + let boxed_any = deserializer_fn(context, is_field, true)?; + *output = to_serializer_fn(boxed_any)?; + context.dec_depth(); + Ok(()) + } else { + use crate::types::TypeId; + context.dec_depth(); + match fory_type_id { + id if id == TypeId::LIST as u32 => { + Err(Error::TypeError(format!( + "Cannot deserialize LIST type ID {fory_type_id} as Box without knowing concrete type. \ + Use concrete type instead (e.g., Vec)" + ).into())) + } + id if id == TypeId::MAP as u32 => { + Err(Error::TypeError(format!( + "Cannot deserialize MAP type ID {fory_type_id} as Box without knowing concrete type. \ + Use concrete type instead (e.g., HashMap)" + ).into())) + } + id if id == TypeId::SET as u32 => { + Err(Error::TypeError(format!( + "Cannot deserialize SET type ID {fory_type_id} as Box without knowing concrete type. \ + Use concrete type instead (e.g., HashSet)" + ).into())) + } + _ => { + Err(Error::TypeError(format!("Type ID {fory_type_id} not registered").into())) + } + } + } + } + fn fory_read_data(_context: &mut ReadContext, _is_field: bool) -> Result { panic!("fory_read_data should not be called directly on Box"); } + + fn fory_read_data_into( + _context: &mut ReadContext, + _is_field: bool, + _output: &mut Self, + ) -> Result<(), Error> { + panic!("fory_read_data_into should not be called directly on Box"); + } } /// Helper macros for automatic conversions in derive code diff --git a/rust/fory-core/src/serializer/weak.rs b/rust/fory-core/src/serializer/weak.rs index c04735901b..d2986b347a 100644 --- a/rust/fory-core/src/serializer/weak.rs +++ b/rust/fory-core/src/serializer/weak.rs @@ -373,10 +373,66 @@ impl Serializer for RcWeak { } } + fn fory_read_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?; + + match ref_flag { + RefFlag::Null => { + *output = RcWeak::new(); + Ok(()) + } + RefFlag::RefValue => { + context.inc_depth()?; + let mut data = T::fory_default(); + T::fory_read_data_into(context, is_field, &mut data)?; + context.dec_depth(); + let rc = Rc::new(data); + let ref_id = context.ref_reader.store_rc_ref(rc); + let rc = context.ref_reader.get_rc_ref::(ref_id).unwrap(); + output.update(Rc::downgrade(&rc)); + Ok(()) + } + RefFlag::Ref => { + let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?; + + if let Some(rc) = context.ref_reader.get_rc_ref::(ref_id) { + output.update(Rc::downgrade(&rc)); + Ok(()) + } else { + *output = RcWeak::new(); + let weak_ptr = output.inner.get(); + context.ref_reader.add_callback(Box::new(move |ref_reader| { + if let Some(rc) = ref_reader.get_rc_ref::(ref_id) { + unsafe { + *weak_ptr = Rc::downgrade(&rc); + } + } + })); + Ok(()) + } + } + _ => Err(Error::InvalidRef( + format!("Weak can only be Null, RefValue or Ref, got {:?}", ref_flag).into(), + )), + } + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { Self::fory_read(context, is_field) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + Self::fory_read_into(context, is_field, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) } @@ -479,10 +535,67 @@ impl Serializer for ArcWeak )), } } + + fn fory_read_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?; + + match ref_flag { + RefFlag::Null => { + *output = ArcWeak::new(); + Ok(()) + } + RefFlag::RefValue => { + context.inc_depth()?; + let mut data = T::fory_default(); + T::fory_read_data_into(context, _is_field, &mut data)?; + context.dec_depth(); + let arc = Arc::new(data); + let ref_id = context.ref_reader.store_arc_ref(arc); + let arc = context.ref_reader.get_arc_ref::(ref_id).unwrap(); + *output = ArcWeak::from(&arc); + Ok(()) + } + RefFlag::Ref => { + let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?; + *output = ArcWeak::new(); + + if let Some(arc) = context.ref_reader.get_arc_ref::(ref_id) { + output.update(Arc::downgrade(&arc)); + } else { + // Capture the raw pointer to the UnsafeCell so we can update it in the callback + let weak_ptr = output.inner.get(); + context.ref_reader.add_callback(Box::new(move |ref_reader| { + if let Some(arc) = ref_reader.get_arc_ref::(ref_id) { + unsafe { + *weak_ptr = Arc::downgrade(&arc); + } + } + })); + } + Ok(()) + } + _ => Err(Error::InvalidRef( + format!("Weak can only be Null, RefValue or Ref, got {:?}", ref_flag).into(), + )), + } + } + fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result { Self::fory_read(context, is_field) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + Self::fory_read_into(context, is_field, output) + } + fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> { T::fory_read_type_info(context, is_field) } diff --git a/rust/fory-derive/src/object/derive_enum.rs b/rust/fory-derive/src/object/derive_enum.rs index 61f7c02340..547f7c9f9c 100644 --- a/rust/fory-derive/src/object/derive_enum.rs +++ b/rust/fory-derive/src/object/derive_enum.rs @@ -77,6 +77,23 @@ pub fn gen_read_data(data_enum: &DataEnum) -> TokenStream { } } +pub fn gen_read_data_into(data_enum: &DataEnum) -> TokenStream { + let variant_idents: Vec<_> = data_enum.variants.iter().map(|v| &v.ident).collect(); + let variant_values: Vec<_> = (0..variant_idents.len()).map(|v| v as u32).collect(); + quote! { + let ordinal = context.reader.read_varuint32()?; + match ordinal { + #( + #variant_values => { + *output = Self::#variant_idents; + Ok(()) + }, + )* + _ => return Err(fory_core::error::Error::UnknownEnum("unknown enum value".into())), + } + } +} + pub fn gen_read_compatible() -> TokenStream { quote! { fory_core::serializer::enum_::read_compatible::(context) diff --git a/rust/fory-derive/src/object/read.rs b/rust/fory-derive/src/object/read.rs index e72ff3eed6..2109e9ef15 100644 --- a/rust/fory-derive/src/object/read.rs +++ b/rust/fory-derive/src/object/read.rs @@ -246,6 +246,27 @@ pub fn gen_read_data(fields: &[&Field]) -> TokenStream { } } +pub fn gen_read_data_into(fields: &[&Field]) -> TokenStream { + let sorted_read = if fields.is_empty() { + quote! { Ok(()) } + } else { + let loop_ts = get_fields_loop_ts(fields); + let field_assignments = fields.iter().map(|field| { + let private_ident = create_private_field_name(field); + let original_ident = &field.ident; + quote! { + output.#original_ident = #private_ident; + } + }); + quote! { + #loop_ts + #(#field_assignments)* + Ok(()) + } + }; + sorted_read +} + fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenStream { let ty = &field.ty; diff --git a/rust/fory-derive/src/object/serializer.rs b/rust/fory-derive/src/object/serializer.rs index 2ba9b9513c..14c958e7af 100644 --- a/rust/fory-derive/src/object/serializer.rs +++ b/rust/fory-derive/src/object/serializer.rs @@ -78,6 +78,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream { read_type_info_ts, write_data_ts, read_data_ts, + read_data_into_ts, write_ts, read_ts, ) = match &ast.data { @@ -89,6 +90,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream { read::gen_read_type_info(), write::gen_write_data(&fields), read::gen_read_data(&fields), + read::gen_read_data_into(&fields), write::gen_write(), read::gen_read(name), ) @@ -99,6 +101,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream { derive_enum::gen_read_type_info(), derive_enum::gen_write_data(e), derive_enum::gen_read_data(e), + derive_enum::gen_read_data_into(e), derive_enum::gen_write(e), derive_enum::gen_read(e), ), @@ -165,6 +168,10 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream { #read_data_ts } + fn fory_read_data_into(context: &mut fory_core::resolver::context::ReadContext, is_field: bool, output: &mut Self) -> Result<(), fory_core::error::Error> { + #read_data_into_ts + } + fn fory_write(&self, context: &mut fory_core::resolver::context::WriteContext, is_field: bool) -> Result<(), fory_core::error::Error> { #write_ts } diff --git a/rust/fory/src/lib.rs b/rust/fory/src/lib.rs index b8e6c538fe..abb2101784 100644 --- a/rust/fory/src/lib.rs +++ b/rust/fory/src/lib.rs @@ -731,6 +731,13 @@ //! Ok(Self { value, name }) //! } //! +//! fn fory_read_data_into(context: &mut ReadContext, is_field: bool, output: &mut Self) -> Result<(), Error> { +//! output.value = context.reader.read_i32()?; +//! let len = context.reader.read_varuint32()? as usize; +//! output.name = context.reader.read_utf8_string(len)?; +//! Ok(()) +//! } +//! //! fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result { //! Self::fory_get_type_id(type_resolver) //! } diff --git a/rust/tests/tests/compatible/test_struct_enum.rs b/rust/tests/tests/compatible/test_struct_enum.rs index ca25a0aba8..721e4ff372 100644 --- a/rust/tests/tests/compatible/test_struct_enum.rs +++ b/rust/tests/tests/compatible/test_struct_enum.rs @@ -412,6 +412,15 @@ fn ext() { }) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + output.id = read_data(context, is_field)?; + Ok(()) + } + fn fory_type_id_dyn( &self, type_resolver: &TypeResolver, @@ -467,6 +476,15 @@ fn skip_ext() { }) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + output.id = read_data(context, is_field)?; + Ok(()) + } + fn fory_type_id_dyn( &self, type_resolver: &TypeResolver, @@ -536,6 +554,16 @@ fn compatible_ext() { id: read_data(context, is_field)?, }) } + + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + output.id = read_data(context, is_field)?; + Ok(()) + } + fn fory_type_id_dyn( &self, type_resolver: &TypeResolver, diff --git a/rust/tests/tests/test_cross_language.rs b/rust/tests/tests/test_cross_language.rs index f6bfdc4084..0525152ee4 100644 --- a/rust/tests/tests/test_cross_language.rs +++ b/rust/tests/tests/test_cross_language.rs @@ -630,6 +630,16 @@ impl Serializer for MyExt { }) } + fn fory_read_data_into( + context: &mut ReadContext, + _is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + // set is_field=false to write type_id like in java + output.id = read_data(context, false)?; + Ok(()) + } + fn fory_type_id_dyn( &self, type_resolver: &TypeResolver, diff --git a/rust/tests/tests/test_ext.rs b/rust/tests/tests/test_ext.rs index 3e023622a3..4199c2a893 100644 --- a/rust/tests/tests/test_ext.rs +++ b/rust/tests/tests/test_ext.rs @@ -71,6 +71,16 @@ fn test_use() { }) } + fn fory_read_data_into( + context: &mut ReadContext, + is_field: bool, + output: &mut Self, + ) -> Result<(), Error> { + output.f1 = read_data(context, is_field)?; + output.f2 = 0; + Ok(()) + } + fn fory_type_id_dyn( &self, type_resolver: &TypeResolver,