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 c0138b113 feat(rust): support dyn any trait object serialization for
box/arc/rc (#2704)
c0138b113 is described below
commit c0138b113ff3d5eb28fe77642d17e8bd059c59ec
Author: Shawn Yang <[email protected]>
AuthorDate: Mon Oct 6 18:10:29 2025 +0800
feat(rust): support dyn any trait object serialization for box/arc/rc
(#2704)
## Why?
<!-- Describe the purpose of this PR. -->
## What does this PR do?
suport dyn any trait object serialization for box/arc/rc:
- introduce `ForyDefault` trait to work around orphan rule, so we can
impl `default` for `Rc<dny Any>`
- rename `Fory` derive to `ForyObject` derive
- add serializer impl for `Box/Rc/Arc<any>`
- support shared reference for `Rc/Arc<any>`
- introduce `write_any_typeinfo/read_typeinfo` for dynamic type-meta
read/write
## Related issues
#2691
#1797
#1795
## 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/README.md | 20 +-
rust/benches/src/models/complex.rs | 12 +-
rust/benches/src/models/medium.rs | 8 +-
rust/benches/src/models/realworld.rs | 10 +-
rust/benches/src/models/simple.rs | 8 +-
rust/fory-core/src/fory.rs | 19 +-
rust/fory-core/src/lib.rs | 8 +-
rust/fory-core/src/meta/meta_string.rs | 21 +-
rust/fory-core/src/resolver/context.rs | 84 ++++++++
rust/fory-core/src/resolver/meta_resolver.rs | 27 ++-
rust/fory-core/src/resolver/ref_resolver.rs | 32 +--
rust/fory-core/src/resolver/type_resolver.rs | 113 ++++++++++-
rust/fory-core/src/serializer/any.rs | 247 ++++++++++++++++++++---
rust/fory-core/src/serializer/arc.rs | 10 +-
rust/fory-core/src/serializer/bool.rs | 8 +-
rust/fory-core/src/serializer/box_.rs | 10 +-
rust/fory-core/src/serializer/collection.rs | 4 +-
rust/fory-core/src/serializer/datetime.rs | 13 ++
rust/fory-core/src/serializer/enum_.rs | 8 +-
rust/fory-core/src/serializer/list.rs | 10 +-
rust/fory-core/src/serializer/map.rs | 16 +-
rust/fory-core/src/serializer/mod.rs | 23 ++-
rust/fory-core/src/serializer/number.rs | 7 +-
rust/fory-core/src/serializer/option.rs | 10 +-
rust/fory-core/src/serializer/rc.rs | 10 +-
rust/fory-core/src/serializer/set.rs | 11 +-
rust/fory-core/src/serializer/string.rs | 8 +-
rust/fory-core/src/serializer/trait_object.rs | 144 ++++----------
rust/fory-derive/src/lib.rs | 24 +--
rust/fory-derive/src/object/read.rs | 10 +-
rust/fory-derive/src/object/serializer.rs | 155 ++++++++++-----
rust/fory-derive/src/object/util.rs | 13 +-
rust/fory-derive/src/util.rs | 2 +-
rust/fory/src/lib.rs | 22 +--
rust/tests/tests/test_any.rs | 269 ++++++++++++++++++++++++++
rust/tests/tests/test_box.rs | 6 +-
rust/tests/tests/test_compatible.rs | 56 +++---
rust/tests/tests/test_complex_struct.rs | 16 +-
rust/tests/tests/test_cross_language.rs | 10 +-
rust/tests/tests/test_ext.rs | 15 +-
rust/tests/tests/test_rc_arc_trait_object.rs | 8 +-
rust/tests/tests/test_trait_object.rs | 12 +-
42 files changed, 1148 insertions(+), 371 deletions(-)
diff --git a/rust/README.md b/rust/README.md
index 4ac0c0472..6c74498e7 100644
--- a/rust/README.md
+++ b/rust/README.md
@@ -43,10 +43,10 @@ For complex data structures with full object graph
serialization:
```rust
use fory::{Fory, Error};
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use std::collections::HashMap;
-#[derive(Fory, Debug, PartialEq, Default)]
+#[derive(ForyObject, Debug, PartialEq, Default)]
struct Person {
name: String,
age: i32,
@@ -55,7 +55,7 @@ struct Person {
metadata: HashMap<String, String>,
}
-#[derive(Fory, Debug, PartialEq, Default)]
+#[derive(ForyObject, Debug, PartialEq, Default)]
struct Address {
street: String,
city: String,
@@ -102,7 +102,7 @@ Serialize trait objects using `Box<dyn Trait>`:
```rust
use fory_core::{Fory, register_trait_type};
use fory_core::serializer::Serializer;
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use fory_core::types::Mode;
trait Animal: Serializer {
@@ -110,7 +110,7 @@ trait Animal: Serializer {
fn name(&self) -> &str;
}
-#[derive(Fory)]
+#[derive(ForyObject)]
struct Dog { name: String, breed: String }
impl Animal for Dog {
@@ -118,7 +118,7 @@ impl Animal for Dog {
fn name(&self) -> &str { &self.name }
}
-#[derive(Fory)]
+#[derive(ForyObject)]
struct Cat { name: String, color: String }
impl Animal for Cat {
@@ -128,7 +128,7 @@ impl Animal for Cat {
register_trait_type!(Animal, Dog, Cat);
-#[derive(Fory)]
+#[derive(ForyObject)]
struct Zoo {
star_animal: Box<dyn Animal>,
}
@@ -161,7 +161,7 @@ use std::sync::Arc;
use std::rc::Rc;
use std::collections::HashMap;
-#[derive(Fory)]
+#[derive(ForyObject)]
struct AnimalShelter {
animals_rc: Vec<Rc<dyn Animal>>,
animals_arc: Vec<Arc<dyn Animal>>,
@@ -318,8 +318,8 @@ assert_eq!(prefs.values().get(0), "en");
### Custom Types
-- Structs with `#[derive(Fory)]` or `#[derive(ForyRow)]`
-- Enums with `#[derive(Fory)]`
+- Structs with `#[derive(ForyObject)]` or `#[derive(ForyRow)]`
+- Enums with `#[derive(ForyObject)]`
- Trait objects
## ⚡ Performance
diff --git a/rust/benches/src/models/complex.rs
b/rust/benches/src/models/complex.rs
index 80f9fb3b5..8db31b4a2 100644
--- a/rust/benches/src/models/complex.rs
+++ b/rust/benches/src/models/complex.rs
@@ -17,12 +17,12 @@
use crate::models::{generate_random_string, generate_random_strings,
TestDataGenerator};
use chrono::{DateTime, NaiveDateTime, Utc};
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
// Fory models
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyProduct {
pub id: String,
pub name: String,
@@ -31,7 +31,7 @@ pub struct ForyProduct {
pub attributes: HashMap<String, String>,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyOrderItem {
pub product: ForyProduct,
pub quantity: i32,
@@ -39,7 +39,7 @@ pub struct ForyOrderItem {
pub customizations: HashMap<String, String>,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyCustomer {
pub id: String,
pub name: String,
@@ -49,7 +49,7 @@ pub struct ForyCustomer {
pub member_since: NaiveDateTime,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyOrder {
pub id: String,
pub customer: ForyCustomer,
@@ -60,7 +60,7 @@ pub struct ForyOrder {
pub metadata: HashMap<String, String>,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ECommerceData {
pub orders: Vec<ForyOrder>,
pub customers: Vec<ForyCustomer>,
diff --git a/rust/benches/src/models/medium.rs
b/rust/benches/src/models/medium.rs
index 3c114795e..727ff7cb3 100644
--- a/rust/benches/src/models/medium.rs
+++ b/rust/benches/src/models/medium.rs
@@ -17,12 +17,12 @@
use crate::models::{generate_random_string, generate_random_strings,
TestDataGenerator};
use chrono::{DateTime, NaiveDateTime, Utc};
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
// Fory models
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyAddress {
pub street: String,
pub city: String,
@@ -30,7 +30,7 @@ pub struct ForyAddress {
pub zip_code: String,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct Person {
pub name: String,
pub age: i32,
@@ -40,7 +40,7 @@ pub struct Person {
pub created_at: NaiveDateTime,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct Company {
pub name: String,
pub employees: Vec<Person>,
diff --git a/rust/benches/src/models/realworld.rs
b/rust/benches/src/models/realworld.rs
index 8baa57570..854010e92 100644
--- a/rust/benches/src/models/realworld.rs
+++ b/rust/benches/src/models/realworld.rs
@@ -17,12 +17,12 @@
use crate::models::{generate_random_string, generate_random_strings,
TestDataGenerator};
use chrono::{DateTime, NaiveDateTime, Utc};
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
// Fory models
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyLogEntry {
pub id: String,
pub level: i32, // 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=FATAL
@@ -34,7 +34,7 @@ pub struct ForyLogEntry {
pub duration_ms: f64,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyUserProfile {
pub user_id: String,
pub username: String,
@@ -45,7 +45,7 @@ pub struct ForyUserProfile {
pub is_active: bool,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct ForyAPIMetrics {
pub endpoint: String,
pub request_count: i64,
@@ -55,7 +55,7 @@ pub struct ForyAPIMetrics {
pub measured_at: NaiveDateTime,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct SystemData {
pub logs: Vec<ForyLogEntry>,
pub users: Vec<ForyUserProfile>,
diff --git a/rust/benches/src/models/simple.rs
b/rust/benches/src/models/simple.rs
index cb82c7fac..4635721d8 100644
--- a/rust/benches/src/models/simple.rs
+++ b/rust/benches/src/models/simple.rs
@@ -16,12 +16,12 @@
// under the License.
use crate::models::{generate_random_string, TestDataGenerator};
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
// Fory models
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct SimpleStruct {
pub id: i32,
pub name: String,
@@ -29,13 +29,13 @@ pub struct SimpleStruct {
pub score: f64,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct SimpleList {
pub numbers: Vec<i32>,
pub names: Vec<String>,
}
-#[derive(Fory, Debug, Clone, PartialEq)]
+#[derive(ForyObject, Debug, Clone, PartialEq)]
pub struct SimpleMap {
pub string_to_int: HashMap<String, i32>,
pub int_to_string: HashMap<i32, String>,
diff --git a/rust/fory-core/src/fory.rs b/rust/fory-core/src/fory.rs
index 688a8f34a..f48d69a21 100644
--- a/rust/fory-core/src/fory.rs
+++ b/rust/fory-core/src/fory.rs
@@ -21,6 +21,7 @@ use crate::error::Error;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
+use crate::serializer::ForyDefault;
use crate::serializer::{Serializer, StructSerializer};
use crate::types::config_flags::IS_NULL_FLAG;
use crate::types::{
@@ -143,19 +144,19 @@ impl Fory {
Ok(false)
}
- pub fn deserialize<T: Serializer + Default>(&self, bf: &[u8]) -> Result<T,
Error> {
+ pub fn deserialize<T: Serializer + ForyDefault>(&self, bf: &[u8]) ->
Result<T, Error> {
let reader = Reader::new(bf);
let mut context = ReadContext::new(self, reader);
self.deserialize_with_context(&mut context)
}
- pub fn deserialize_with_context<T: Serializer + Default>(
+ pub fn deserialize_with_context<T: Serializer + ForyDefault>(
&self,
context: &mut ReadContext,
) -> Result<T, Error> {
let is_none = self.read_head(&mut context.reader)?;
if is_none {
- return Ok(T::default());
+ return Ok(T::fory_default());
}
let mut bytes_to_skip = 0;
if self.mode == Mode::Compatible {
@@ -201,14 +202,14 @@ impl Fory {
&self.type_resolver
}
- pub fn register<T: 'static + StructSerializer + Serializer + Default>(&mut
self, id: u32) {
+ pub fn register<T: 'static + StructSerializer + Serializer +
ForyDefault>(&mut self, id: u32) {
let actual_type_id = T::fory_actual_type_id(id, false, &self.mode);
let type_info =
TypeInfo::new::<T>(self, actual_type_id, &EMPTY_STRING,
&EMPTY_STRING, false);
self.type_resolver.register::<T>(&type_info);
}
- pub fn register_by_namespace<T: 'static + StructSerializer + Serializer +
Default>(
+ pub fn register_by_namespace<T: 'static + StructSerializer + Serializer +
ForyDefault>(
&mut self,
namespace: &str,
type_name: &str,
@@ -218,14 +219,14 @@ impl Fory {
self.type_resolver.register::<T>(&type_info);
}
- pub fn register_by_name<T: 'static + StructSerializer + Serializer +
Default>(
+ pub fn register_by_name<T: 'static + StructSerializer + Serializer +
ForyDefault>(
&mut self,
type_name: &str,
) {
self.register_by_namespace::<T>("", type_name);
}
- pub fn register_serializer<T: Serializer + Default>(&mut self, id: u32) {
+ pub fn register_serializer<T: Serializer + ForyDefault>(&mut self, id:
u32) {
let actual_type_id = get_ext_actual_type_id(id, false);
let type_info = TypeInfo::new_with_empty_def::<T>(
self,
@@ -237,7 +238,7 @@ impl Fory {
self.type_resolver.register_serializer::<T>(&type_info);
}
- pub fn register_serializer_by_name<T: Serializer + Default>(
+ pub fn register_serializer_by_name<T: Serializer + ForyDefault>(
&mut self,
type_name: &str,
namespace: &str,
@@ -253,7 +254,7 @@ pub fn write<T: Serializer>(this: &T, context: &mut
WriteContext, is_field: bool
T::fory_write(this, context, is_field);
}
-pub fn read<T: Serializer + Default>(
+pub fn read<T: Serializer + ForyDefault>(
context: &mut ReadContext,
is_field: bool,
) -> Result<T, Error> {
diff --git a/rust/fory-core/src/lib.rs b/rust/fory-core/src/lib.rs
index 9ba480d22..1ada7cdd7 100644
--- a/rust/fory-core/src/lib.rs
+++ b/rust/fory-core/src/lib.rs
@@ -74,10 +74,10 @@
//! fn speak(&self) -> String;
//! }
//!
-//! #[derive(Fory)]
+//! #[derive(ForyObject)]
//! struct Dog { name: String }
//!
-//! #[derive(Fory)]
+//! #[derive(ForyObject)]
//! struct Cat { name: String }
//!
//! impl Animal for Dog {
@@ -93,7 +93,7 @@
//! register_trait_type!(Animal, Dog, Cat);
//!
//! // Use in struct fields
-//! #[derive(Fory)]
+//! #[derive(ForyObject)]
//! struct Zoo {
//! star_animal: Box<dyn Animal>,
//! }
@@ -104,7 +104,7 @@
//! For reference-counted trait objects, use them directly in struct fields:
//!
//! ```ignore
-//! #[derive(Fory)]
+//! #[derive(ForyObject)]
//! struct Shelter {
//! animals_rc: Vec<Rc<dyn Animal>>,
//! animals_arc: Vec<Arc<dyn Animal>>,
diff --git a/rust/fory-core/src/meta/meta_string.rs
b/rust/fory-core/src/meta/meta_string.rs
index 7d2c34cb2..bddc8f11a 100644
--- a/rust/fory-core/src/meta/meta_string.rs
+++ b/rust/fory-core/src/meta/meta_string.rs
@@ -67,7 +67,7 @@ impl MetaStringBytes {
}
}
-#[derive(Debug, PartialEq, Hash, Eq, Clone, Default)]
+#[derive(Debug, Clone, Default)]
pub struct MetaString {
pub original: String,
pub encoding: Encoding,
@@ -77,6 +77,20 @@ pub struct MetaString {
pub special_char2: char,
}
+impl PartialEq for MetaString {
+ fn eq(&self, other: &Self) -> bool {
+ self.bytes == other.bytes
+ }
+}
+
+impl Eq for MetaString {}
+
+impl std::hash::Hash for MetaString {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.bytes.hash(state);
+ }
+}
+
impl MetaString {
pub fn new(
original: String,
@@ -100,6 +114,11 @@ impl MetaString {
special_char2,
})
}
+
+ pub fn write_to(&self, writer: &mut crate::buffer::Writer) {
+ writer.write_varuint32(self.bytes.len() as u32);
+ writer.write_bytes(&self.bytes);
+ }
}
#[derive(Clone)]
diff --git a/rust/fory-core/src/resolver/context.rs
b/rust/fory-core/src/resolver/context.rs
index bf93c48e1..c6704689d 100644
--- a/rust/fory-core/src/resolver/context.rs
+++ b/rust/fory-core/src/resolver/context.rs
@@ -21,6 +21,8 @@ use crate::fory::Fory;
use crate::meta::TypeMeta;
use crate::resolver::meta_resolver::{MetaReaderResolver, MetaWriterResolver};
use crate::resolver::ref_resolver::{RefReader, RefWriter};
+use crate::resolver::type_resolver::Harness;
+use std::any::TypeId;
use std::rc::Rc;
pub struct WriteContext<'se> {
@@ -59,6 +61,49 @@ impl<'se> WriteContext<'se> {
pub fn get_fory(&self) -> &Fory {
self.fory
}
+
+ pub fn write_any_typeinfo(&mut self, concrete_type_id: TypeId) -> &'se
Harness {
+ use crate::types::TypeId as ForyTypeId;
+
+ let type_resolver = self.fory.get_type_resolver();
+ let type_info = type_resolver.get_type_info(concrete_type_id);
+ let fory_type_id = type_info.get_type_id();
+
+ if type_info.is_registered_by_name() {
+ if fory_type_id & 0xff == ForyTypeId::NAMED_STRUCT as u32 {
+ self.writer.write_varuint32(fory_type_id);
+ if self.fory.is_share_meta() {
+ let meta_index = self.push_meta(concrete_type_id) as u32;
+ self.writer.write_varuint32(meta_index);
+ } else {
+ type_info.get_namespace().write_to(self.writer);
+ type_info.get_type_name().write_to(self.writer);
+ }
+ } else if fory_type_id & 0xff ==
ForyTypeId::NAMED_COMPATIBLE_STRUCT as u32 {
+ self.writer.write_varuint32(fory_type_id);
+ let meta_index = self.push_meta(concrete_type_id) as u32;
+ self.writer.write_varuint32(meta_index);
+ } else {
+ self.writer.write_varuint32(u32::MAX);
+ type_info.get_namespace().write_to(self.writer);
+ type_info.get_type_name().write_to(self.writer);
+ }
+ type_resolver
+ .get_name_harness(type_info.get_namespace(),
type_info.get_type_name())
+ .expect("Name harness not found")
+ } else {
+ if fory_type_id & 0xff == ForyTypeId::COMPATIBLE_STRUCT as u32 {
+ self.writer.write_varuint32(fory_type_id);
+ let meta_index = self.push_meta(concrete_type_id) as u32;
+ self.writer.write_varuint32(meta_index);
+ } else {
+ self.writer.write_varuint32(fory_type_id);
+ }
+ type_resolver
+ .get_harness(fory_type_id)
+ .expect("ID harness not found")
+ }
+ }
}
pub struct ReadContext<'de, 'bf: 'de> {
@@ -91,4 +136,43 @@ impl<'de, 'bf: 'de> ReadContext<'de, 'bf> {
&self.reader.slice_after_cursor()[offset..],
))
}
+
+ pub fn read_any_typeinfo(&mut self) -> &'de Harness {
+ use crate::types::TypeId as ForyTypeId;
+
+ let fory_type_id = self.reader.read_varuint32();
+ let type_resolver = self.fory.get_type_resolver();
+
+ if fory_type_id == u32::MAX {
+ let namespace = self.meta_resolver.read_metastring(&mut
self.reader);
+ let type_name = self.meta_resolver.read_metastring(&mut
self.reader);
+ type_resolver
+ .get_name_harness(&namespace, &type_name)
+ .expect("Name harness not found")
+ } else if fory_type_id & 0xff == ForyTypeId::NAMED_STRUCT as u32 {
+ if self.fory.is_share_meta() {
+ let _meta_index = self.reader.read_varuint32();
+ } else {
+ let namespace = self.meta_resolver.read_metastring(&mut
self.reader);
+ let type_name = self.meta_resolver.read_metastring(&mut
self.reader);
+ return type_resolver
+ .get_name_harness(&namespace, &type_name)
+ .expect("Name harness not found");
+ }
+ type_resolver
+ .get_harness(fory_type_id)
+ .expect("ID harness not found")
+ } else if fory_type_id & 0xff == ForyTypeId::NAMED_COMPATIBLE_STRUCT
as u32
+ || fory_type_id & 0xff == ForyTypeId::COMPATIBLE_STRUCT as u32
+ {
+ let _meta_index = self.reader.read_varuint32();
+ type_resolver
+ .get_harness(fory_type_id)
+ .expect("ID harness not found")
+ } else {
+ type_resolver
+ .get_harness(fory_type_id)
+ .expect("ID harness not found")
+ }
+ }
}
diff --git a/rust/fory-core/src/resolver/meta_resolver.rs
b/rust/fory-core/src/resolver/meta_resolver.rs
index d61d28f9e..6434d9c06 100644
--- a/rust/fory-core/src/resolver/meta_resolver.rs
+++ b/rust/fory-core/src/resolver/meta_resolver.rs
@@ -18,7 +18,7 @@
use crate::buffer::{Reader, Writer};
use crate::error::Error;
use crate::fory::Fory;
-use crate::meta::TypeMeta;
+use crate::meta::{Encoding, MetaString, TypeMeta, NAMESPACE_DECODER};
use std::collections::HashMap;
use std::rc::Rc;
@@ -41,6 +41,31 @@ impl MetaReaderResolver {
}
reader.get_cursor()
}
+
+ pub fn read_metastring(&self, reader: &mut Reader) -> MetaString {
+ let len = reader.read_varuint32() as usize;
+ if len == 0 {
+ return MetaString {
+ bytes: vec![],
+ encoding: Encoding::Utf8,
+ original: String::new(),
+ strip_last_char: false,
+ special_char1: '\0',
+ special_char2: '\0',
+ };
+ }
+ let bytes = reader.read_bytes(len);
+ let encoding_byte = bytes[0] & 0x07;
+ let encoding = match encoding_byte {
+ 0x00 => Encoding::Utf8,
+ 0x01 => Encoding::LowerSpecial,
+ 0x02 => Encoding::LowerUpperDigitSpecial,
+ 0x03 => Encoding::FirstToLowerSpecial,
+ 0x04 => Encoding::AllToLowerSpecial,
+ _ => Encoding::Utf8,
+ };
+ NAMESPACE_DECODER.decode(bytes, encoding).unwrap()
+ }
}
#[derive(Default)]
diff --git a/rust/fory-core/src/resolver/ref_resolver.rs
b/rust/fory-core/src/resolver/ref_resolver.rs
index 07e0d9a6f..458e8d7d2 100644
--- a/rust/fory-core/src/resolver/ref_resolver.rs
+++ b/rust/fory-core/src/resolver/ref_resolver.rs
@@ -76,8 +76,8 @@ impl RefWriter {
///
/// * `true` if a reference was written
/// * `false` if this is the first occurrence of the object
- pub fn try_write_rc_ref<T>(&mut self, writer: &mut Writer, rc: &Rc<T>) ->
bool {
- let ptr_addr = Rc::as_ptr(rc) as usize;
+ pub fn try_write_rc_ref<T: ?Sized>(&mut self, writer: &mut Writer, rc:
&Rc<T>) -> bool {
+ let ptr_addr = Rc::as_ptr(rc) as *const () as usize;
if let Some(&ref_id) = self.refs.get(&ptr_addr) {
// This object has been seen before, write a reference
@@ -109,8 +109,8 @@ impl RefWriter {
///
/// * `true` if a reference was written
/// * `false` if this is the first occurrence of the object
- pub fn try_write_arc_ref<T>(&mut self, writer: &mut Writer, arc: &Arc<T>)
-> bool {
- let ptr_addr = Arc::as_ptr(arc) as usize;
+ pub fn try_write_arc_ref<T: ?Sized>(&mut self, writer: &mut Writer, arc:
&Arc<T>) -> bool {
+ let ptr_addr = Arc::as_ptr(arc) as *const () as usize;
if let Some(&ref_id) = self.refs.get(&ptr_addr) {
// This object has been seen before, write a reference
@@ -180,7 +180,7 @@ impl RefReader {
/// # Returns
///
/// The reference ID that can be used to retrieve this object later
- pub fn store_rc_ref<T: 'static>(&mut self, rc: Rc<T>) -> u32 {
+ pub fn store_rc_ref<T: 'static + ?Sized>(&mut self, rc: Rc<T>) -> u32 {
let ref_id = self.refs.len() as u32;
self.refs.push(Box::new(rc));
ref_id
@@ -195,7 +195,7 @@ impl RefReader {
/// # Returns
///
/// The reference ID that can be used to retrieve this object later
- pub fn store_arc_ref<T: 'static>(&mut self, arc: Arc<T>) -> u32 {
+ pub fn store_arc_ref<T: 'static + ?Sized>(&mut self, arc: Arc<T>) -> u32 {
let ref_id = self.refs.len() as u32;
self.refs.push(Box::new(arc));
ref_id
@@ -211,7 +211,7 @@ impl RefReader {
///
/// * `Some(Rc<T>)` if the reference ID is valid and the type matches
/// * `None` if the reference ID is invalid or the type doesn't match
- pub fn get_rc_ref<T: 'static>(&self, ref_id: u32) -> Option<Rc<T>> {
+ pub fn get_rc_ref<T: 'static + ?Sized>(&self, ref_id: u32) ->
Option<Rc<T>> {
let any_box = self.refs.get(ref_id as usize)?;
any_box.downcast_ref::<Rc<T>>().cloned()
}
@@ -226,7 +226,7 @@ impl RefReader {
///
/// * `Some(Arc<T>)` if the reference ID is valid and the type matches
/// * `None` if the reference ID is invalid or the type doesn't match
- pub fn get_arc_ref<T: 'static>(&self, ref_id: u32) -> Option<Arc<T>> {
+ pub fn get_arc_ref<T: 'static + ?Sized>(&self, ref_id: u32) ->
Option<Arc<T>> {
let any_box = self.refs.get(ref_id as usize)?;
any_box.downcast_ref::<Arc<T>>().cloned()
}
@@ -303,8 +303,8 @@ impl RefResolver {
/// Attempt to write a reference for an Rc<T>. Returns true if reference
was written,
/// false if this is the first occurrence and should be serialized
normally.
- pub fn try_write_rc_ref<T>(&mut self, writer: &mut Writer, rc: &Rc<T>) ->
bool {
- let ptr_addr = Rc::as_ptr(rc) as usize;
+ pub fn try_write_rc_ref<T: ?Sized>(&mut self, writer: &mut Writer, rc:
&Rc<T>) -> bool {
+ let ptr_addr = Rc::as_ptr(rc) as *const () as usize;
if let Some(&ref_id) = self.write_refs.get(&ptr_addr) {
// This object has been seen before, write a reference
@@ -323,8 +323,8 @@ impl RefResolver {
/// Attempt to write a reference for an Arc<T>. Returns true if reference
was written,
/// false if this is the first occurrence and should be serialized
normally.
- pub fn try_write_arc_ref<T>(&mut self, writer: &mut Writer, arc: &Arc<T>)
-> bool {
- let ptr_addr = Arc::as_ptr(arc) as usize;
+ pub fn try_write_arc_ref<T: ?Sized>(&mut self, writer: &mut Writer, arc:
&Arc<T>) -> bool {
+ let ptr_addr = Arc::as_ptr(arc) as *const () as usize;
if let Some(&ref_id) = self.write_refs.get(&ptr_addr) {
// This object has been seen before, write a reference
@@ -342,27 +342,27 @@ impl RefResolver {
}
/// Store an Rc<T> for later reference resolution during deserialization
- pub fn store_rc_ref<T: 'static>(&mut self, rc: Rc<T>) -> u32 {
+ pub fn store_rc_ref<T: 'static + ?Sized>(&mut self, rc: Rc<T>) -> u32 {
let ref_id = self.read_refs.len() as u32;
self.read_refs.push(Box::new(rc));
ref_id
}
/// Store an Arc<T> for later reference resolution during deserialization
- pub fn store_arc_ref<T: 'static>(&mut self, arc: Arc<T>) -> u32 {
+ pub fn store_arc_ref<T: 'static + ?Sized>(&mut self, arc: Arc<T>) -> u32 {
let ref_id = self.read_refs.len() as u32;
self.read_refs.push(Box::new(arc));
ref_id
}
/// Get an Rc<T> by reference ID during deserialization
- pub fn get_rc_ref<T: 'static>(&self, ref_id: u32) -> Option<Rc<T>> {
+ pub fn get_rc_ref<T: 'static + ?Sized>(&self, ref_id: u32) ->
Option<Rc<T>> {
let any_box = self.read_refs.get(ref_id as usize)?;
any_box.downcast_ref::<Rc<T>>().cloned()
}
/// Get an Arc<T> by reference ID during deserialization
- pub fn get_arc_ref<T: 'static>(&self, ref_id: u32) -> Option<Arc<T>> {
+ pub fn get_arc_ref<T: 'static + ?Sized>(&self, ref_id: u32) ->
Option<Arc<T>> {
let any_box = self.read_refs.get(ref_id as usize)?;
any_box.downcast_ref::<Arc<T>>().cloned()
}
diff --git a/rust/fory-core/src/resolver/type_resolver.rs
b/rust/fory-core/src/resolver/type_resolver.rs
index 63bf513aa..d6f3f58ad 100644
--- a/rust/fory-core/src/resolver/type_resolver.rs
+++ b/rust/fory-core/src/resolver/type_resolver.rs
@@ -21,7 +21,7 @@ use crate::fory::Fory;
use crate::meta::{
MetaString, NAMESPACE_ENCODER, NAMESPACE_ENCODINGS, TYPE_NAME_ENCODER,
TYPE_NAME_ENCODINGS,
};
-use crate::serializer::{Serializer, StructSerializer};
+use crate::serializer::{ForyDefault, Serializer, StructSerializer};
use std::cell::RefCell;
use std::sync::Arc;
use std::{any::Any, collections::HashMap};
@@ -29,6 +29,8 @@ use std::{any::Any, collections::HashMap};
type SerializerFn = fn(&dyn Any, &mut WriteContext, is_field: bool);
type DeserializerFn =
fn(&mut ReadContext, is_field: bool, skip_ref_flag: bool) ->
Result<Box<dyn Any>, Error>;
+type SerializerNoRefFn = fn(&dyn Any, &mut WriteContext, is_field: bool);
+type DeserializerNoRefFn = fn(&mut ReadContext, is_field: bool) ->
Result<Box<dyn Any>, Error>;
type ToSerializerFn = fn(Box<dyn Any>) -> Result<Box<dyn
crate::serializer::Serializer>, Error>;
pub type ExtWriteFn = dyn Fn(&dyn Any, &mut WriteContext, bool) + Send + Sync;
@@ -37,6 +39,8 @@ pub type ExtReadFn = dyn Fn(&mut ReadContext, bool) ->
Result<Box<dyn Any>, Erro
pub struct Harness {
serializer: SerializerFn,
deserializer: DeserializerFn,
+ serializer_no_ref: SerializerNoRefFn,
+ deserializer_no_ref: DeserializerNoRefFn,
to_serializer: ToSerializerFn,
}
@@ -44,11 +48,15 @@ impl Harness {
pub fn new(
serializer: SerializerFn,
deserializer: DeserializerFn,
+ serializer_no_ref: SerializerNoRefFn,
+ deserializer_no_ref: DeserializerNoRefFn,
to_serializer: ToSerializerFn,
) -> Harness {
Harness {
serializer,
deserializer,
+ serializer_no_ref,
+ deserializer_no_ref,
to_serializer,
}
}
@@ -61,6 +69,14 @@ impl Harness {
self.deserializer
}
+ pub fn get_serializer_no_ref(&self) -> SerializerNoRefFn {
+ self.serializer_no_ref
+ }
+
+ pub fn get_deserializer_no_ref(&self) -> DeserializerNoRefFn {
+ self.deserializer_no_ref
+ }
+
pub fn get_to_serializer(&self) -> ToSerializerFn {
self.to_serializer
}
@@ -171,6 +187,10 @@ impl TypeInfo {
pub fn get_type_def(&self) -> &Vec<u8> {
&self.type_def
}
+
+ pub fn is_registered_by_name(&self) -> bool {
+ self.register_by_name
+ }
}
pub struct TypeResolver {
@@ -269,7 +289,10 @@ impl TypeResolver {
)
}
- pub fn register<T: StructSerializer + Serializer + Default>(&mut self,
type_info: &TypeInfo) {
+ pub fn register<T: StructSerializer + Serializer + ForyDefault>(
+ &mut self,
+ type_info: &TypeInfo,
+ ) {
fn serializer<T2: 'static + Serializer>(
this: &dyn Any,
context: &mut WriteContext,
@@ -292,7 +315,7 @@ impl TypeResolver {
}
}
- fn deserializer<T2: 'static + Serializer + Default>(
+ fn deserializer<T2: 'static + Serializer + ForyDefault>(
context: &mut ReadContext,
is_field: bool,
skip_ref_flag: bool,
@@ -308,6 +331,30 @@ impl TypeResolver {
}
}
+ fn serializer_no_ref<T2: 'static + Serializer>(
+ this: &dyn Any,
+ context: &mut WriteContext,
+ is_field: bool,
+ ) {
+ let this = this.downcast_ref::<T2>();
+ match this {
+ Some(v) => {
+ T2::fory_write_data(v, context, is_field);
+ }
+ None => todo!(),
+ }
+ }
+
+ fn deserializer_no_ref<T2: 'static + Serializer + ForyDefault>(
+ context: &mut ReadContext,
+ is_field: bool,
+ ) -> Result<Box<dyn Any>, Error> {
+ match T2::fory_read_data(context, is_field) {
+ Ok(v) => Ok(Box::new(v)),
+ Err(e) => Err(e),
+ }
+ }
+
fn to_serializer<T2: 'static + Serializer>(
boxed_any: Box<dyn Any>,
) -> Result<Box<dyn crate::serializer::Serializer>, Error> {
@@ -345,7 +392,13 @@ impl TypeResolver {
self.type_name_map.insert(rs_type_id, key.clone());
self.name_serializer_map.insert(
key,
- Harness::new(serializer::<T>, deserializer::<T>,
to_serializer::<T>),
+ Harness::new(
+ serializer::<T>,
+ deserializer::<T>,
+ serializer_no_ref::<T>,
+ deserializer_no_ref::<T>,
+ to_serializer::<T>,
+ ),
);
} else {
let type_id = type_info.type_id;
@@ -355,12 +408,18 @@ impl TypeResolver {
self.type_id_map.insert(rs_type_id, type_id);
self.serializer_map.insert(
type_id,
- Harness::new(serializer::<T>, deserializer::<T>,
to_serializer::<T>),
+ Harness::new(
+ serializer::<T>,
+ deserializer::<T>,
+ serializer_no_ref::<T>,
+ deserializer_no_ref::<T>,
+ to_serializer::<T>,
+ ),
);
}
}
- pub fn register_serializer<T: Serializer + Default>(&mut self, type_info:
&TypeInfo) {
+ pub fn register_serializer<T: Serializer + ForyDefault>(&mut self,
type_info: &TypeInfo) {
fn serializer<T2: 'static + Serializer>(
this: &dyn Any,
context: &mut WriteContext,
@@ -375,7 +434,7 @@ impl TypeResolver {
}
}
- fn deserializer<T2: 'static + Serializer + Default>(
+ fn deserializer<T2: 'static + Serializer + ForyDefault>(
context: &mut ReadContext,
is_field: bool,
skip_ref_flag: bool,
@@ -393,6 +452,30 @@ impl TypeResolver {
}
}
+ fn serializer_no_ref<T2: 'static + Serializer>(
+ this: &dyn Any,
+ context: &mut WriteContext,
+ is_field: bool,
+ ) {
+ let this = this.downcast_ref::<T2>();
+ match this {
+ Some(v) => {
+ T2::fory_write_data(v, context, is_field);
+ }
+ None => todo!(),
+ }
+ }
+
+ fn deserializer_no_ref<T2: 'static + Serializer + ForyDefault>(
+ context: &mut ReadContext,
+ is_field: bool,
+ ) -> Result<Box<dyn Any>, Error> {
+ match T2::fory_read_data(context, is_field) {
+ Ok(v) => Ok(Box::new(v)),
+ Err(e) => Err(e),
+ }
+ }
+
fn to_serializer<T2: 'static + Serializer>(
boxed_any: Box<dyn Any>,
) -> Result<Box<dyn crate::serializer::Serializer>, Error> {
@@ -422,7 +505,13 @@ impl TypeResolver {
self.type_name_map.insert(rs_type_id, key.clone());
self.name_serializer_map.insert(
key,
- Harness::new(serializer::<T>, deserializer::<T>,
to_serializer::<T>),
+ Harness::new(
+ serializer::<T>,
+ deserializer::<T>,
+ serializer_no_ref::<T>,
+ deserializer_no_ref::<T>,
+ to_serializer::<T>,
+ ),
);
} else {
let type_id = type_info.type_id;
@@ -432,7 +521,13 @@ impl TypeResolver {
self.type_id_map.insert(rs_type_id, type_id);
self.serializer_map.insert(
type_id,
- Harness::new(serializer::<T>, deserializer::<T>,
to_serializer::<T>),
+ Harness::new(
+ serializer::<T>,
+ deserializer::<T>,
+ serializer_no_ref::<T>,
+ deserializer_no_ref::<T>,
+ to_serializer::<T>,
+ ),
);
}
}
diff --git a/rust/fory-core/src/serializer/any.rs
b/rust/fory-core/src/serializer/any.rs
index 690579dee..98931cd9f 100644
--- a/rust/fory-core/src/serializer/any.rs
+++ b/rust/fory-core/src/serializer/any.rs
@@ -16,31 +16,21 @@
// under the License.
use crate::error::Error;
+use crate::fory::Fory;
use crate::resolver::context::{ReadContext, WriteContext};
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::RefFlag;
use std::any::Any;
+use std::rc::Rc;
+use std::sync::Arc;
/// Helper function to serialize a Box<dyn Any>
pub fn serialize_any_box(any_box: &Box<dyn Any>, context: &mut WriteContext,
is_field: bool) {
context.writer.write_i8(RefFlag::NotNullValue as i8);
let concrete_type_id = (**any_box).type_id();
-
- let fory_type_id = context
- .get_fory()
- .get_type_resolver()
- .get_fory_type_id(concrete_type_id)
- .expect("Type not registered");
-
- context.writer.write_varuint32(fory_type_id);
-
- let harness = context
- .get_fory()
- .get_type_resolver()
- .get_harness(fory_type_id)
- .expect("Harness not found");
-
- let serializer_fn = harness.get_serializer();
+ let harness = context.write_any_typeinfo(concrete_type_id);
+ let serializer_fn = harness.get_serializer_no_ref();
serializer_fn(&**any_box, context, is_field);
}
@@ -52,15 +42,224 @@ pub fn deserialize_any_box(context: &mut ReadContext) ->
Result<Box<dyn Any>, Er
"Expected NotNullValue for Box<dyn Any>"
)));
}
+ let harness = context.read_any_typeinfo();
+ let deserializer_fn = harness.get_deserializer_no_ref();
+ deserializer_fn(context, true)
+}
+
+impl ForyDefault for Box<dyn Any> {
+ fn fory_default() -> Self {
+ Box::new(())
+ }
+}
+
+impl Serializer for Box<dyn Any> {
+ fn fory_write(&self, context: &mut WriteContext, is_field: bool) {
+ serialize_any_box(self, context, is_field);
+ }
+
+ fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
+ serialize_any_box(self, context, is_field);
+ }
+
+ fn fory_read(context: &mut ReadContext, _is_field: bool) -> Result<Self,
Error> {
+ deserialize_any_box(context)
+ }
+
+ fn fory_read_data(context: &mut ReadContext, _is_field: bool) ->
Result<Self, Error> {
+ deserialize_any_box(context)
+ }
+
+ fn fory_get_type_id(_fory: &Fory) -> u32 {
+ panic!("Box<dyn Any> has no static type ID - use fory_type_id_dyn")
+ }
+
+ fn fory_type_id_dyn(&self, fory: &Fory) -> u32 {
+ let concrete_type_id = (**self).type_id();
+ fory.get_type_resolver()
+ .get_fory_type_id(concrete_type_id)
+ .expect("Type not registered")
+ }
+
+ fn fory_is_polymorphic() -> bool {
+ true
+ }
+
+ fn fory_write_type_info(_context: &mut WriteContext, _is_field: bool) {
+ // Box<dyn Any> is polymorphic - type info is written per element
+ }
- let fory_type_id = context.reader.read_varuint32();
+ fn fory_read_type_info(_context: &mut ReadContext, _is_field: bool) {
+ // Box<dyn Any> is polymorphic - type info is read per element
+ }
- let harness = context
- .get_fory()
- .get_type_resolver()
- .get_harness(fory_type_id)
- .ok_or_else(|| Error::Other(anyhow::anyhow!("Type {} not registered",
fory_type_id)))?;
+ fn as_any(&self) -> &dyn Any {
+ &**self
+ }
+}
- let deserializer_fn = harness.get_deserializer();
- deserializer_fn(context, true, true)
+impl ForyDefault for Rc<dyn Any> {
+ fn fory_default() -> Self {
+ Rc::new(())
+ }
+}
+
+impl Serializer for Rc<dyn Any> {
+ fn fory_write(&self, context: &mut WriteContext, is_field: bool) {
+ if !context.ref_writer.try_write_rc_ref(context.writer, self) {
+ let concrete_type_id = (**self).type_id();
+ let harness = context.write_any_typeinfo(concrete_type_id);
+ let serializer_fn = harness.get_serializer_no_ref();
+ serializer_fn(&**self, context, is_field);
+ }
+ }
+
+ fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
+ self.fory_write(context, is_field);
+ }
+
+ fn fory_read(context: &mut ReadContext, _is_field: bool) -> Result<Self,
Error> {
+ let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader);
+
+ match ref_flag {
+ RefFlag::Null => Err(anyhow::anyhow!("Rc<dyn Any> cannot be
null").into()),
+ RefFlag::Ref => {
+ let ref_id = context.ref_reader.read_ref_id(&mut
context.reader);
+ context
+ .ref_reader
+ .get_rc_ref::<dyn Any>(ref_id)
+ .ok_or_else(|| {
+ anyhow::anyhow!("Rc<dyn Any> reference {} not found",
ref_id).into()
+ })
+ }
+ RefFlag::NotNullValue => {
+ let harness = context.read_any_typeinfo();
+ let deserializer_fn = harness.get_deserializer_no_ref();
+ let boxed = deserializer_fn(context, true)?;
+ Ok(Rc::<dyn Any>::from(boxed))
+ }
+ RefFlag::RefValue => {
+ let harness = context.read_any_typeinfo();
+ let deserializer_fn = harness.get_deserializer_no_ref();
+ let boxed = deserializer_fn(context, true)?;
+ let rc: Rc<dyn Any> = Rc::from(boxed);
+ context.ref_reader.store_rc_ref(rc.clone());
+ Ok(rc)
+ }
+ }
+ }
+
+ fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
+ Self::fory_read(context, is_field)
+ }
+
+ fn fory_get_type_id(_fory: &Fory) -> u32 {
+ panic!("Rc<dyn Any> has no static type ID - use fory_type_id_dyn")
+ }
+
+ fn fory_type_id_dyn(&self, fory: &Fory) -> u32 {
+ let concrete_type_id = (**self).type_id();
+ fory.get_type_resolver()
+ .get_fory_type_id(concrete_type_id)
+ .expect("Type not registered")
+ }
+
+ fn fory_is_polymorphic() -> bool {
+ true
+ }
+
+ fn fory_write_type_info(_context: &mut WriteContext, _is_field: bool) {
+ // Rc<dyn Any> is polymorphic - type info is written per element
+ }
+
+ fn fory_read_type_info(_context: &mut ReadContext, _is_field: bool) {
+ // Rc<dyn Any> is polymorphic - type info is read per element
+ }
+
+ fn as_any(&self) -> &dyn Any {
+ &**self
+ }
+}
+
+impl ForyDefault for Arc<dyn Any> {
+ fn fory_default() -> Self {
+ Arc::new(())
+ }
+}
+
+impl Serializer for Arc<dyn Any> {
+ fn fory_write(&self, context: &mut WriteContext, is_field: bool) {
+ if !context.ref_writer.try_write_arc_ref(context.writer, self) {
+ let concrete_type_id = (**self).type_id();
+ let harness = context.write_any_typeinfo(concrete_type_id);
+ let serializer_fn = harness.get_serializer_no_ref();
+ serializer_fn(&**self, context, is_field);
+ }
+ }
+
+ fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
+ self.fory_write(context, is_field);
+ }
+
+ fn fory_read(context: &mut ReadContext, _is_field: bool) -> Result<Self,
Error> {
+ let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader);
+
+ match ref_flag {
+ RefFlag::Null => Err(anyhow::anyhow!("Arc<dyn Any> cannot be
null").into()),
+ RefFlag::Ref => {
+ let ref_id = context.ref_reader.read_ref_id(&mut
context.reader);
+ context
+ .ref_reader
+ .get_arc_ref::<dyn Any>(ref_id)
+ .ok_or_else(|| {
+ anyhow::anyhow!("Arc<dyn Any> reference {} not found",
ref_id).into()
+ })
+ }
+ RefFlag::NotNullValue => {
+ let harness = context.read_any_typeinfo();
+ let deserializer_fn = harness.get_deserializer_no_ref();
+ let boxed = deserializer_fn(context, true)?;
+ Ok(Arc::<dyn Any>::from(boxed))
+ }
+ RefFlag::RefValue => {
+ let harness = context.read_any_typeinfo();
+ let deserializer_fn = harness.get_deserializer_no_ref();
+ let boxed = deserializer_fn(context, true)?;
+ let arc: Arc<dyn Any> = Arc::from(boxed);
+ context.ref_reader.store_arc_ref(arc.clone());
+ Ok(arc)
+ }
+ }
+ }
+
+ fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
+ Self::fory_read(context, is_field)
+ }
+
+ fn fory_get_type_id(_fory: &Fory) -> u32 {
+ panic!("Arc<dyn Any> has no static type ID - use fory_type_id_dyn")
+ }
+
+ fn fory_type_id_dyn(&self, fory: &Fory) -> u32 {
+ let concrete_type_id = (**self).type_id();
+ fory.get_type_resolver()
+ .get_fory_type_id(concrete_type_id)
+ .expect("Type not registered")
+ }
+
+ fn fory_is_polymorphic() -> bool {
+ true
+ }
+
+ fn fory_write_type_info(_context: &mut WriteContext, _is_field: bool) {
+ // Arc<dyn Any> is polymorphic - type info is written per element
+ }
+
+ fn fory_read_type_info(_context: &mut ReadContext, _is_field: bool) {
+ // Arc<dyn Any> is polymorphic - type info is read per element
+ }
+
+ fn as_any(&self) -> &dyn Any {
+ &**self
+ }
}
diff --git a/rust/fory-core/src/serializer/arc.rs
b/rust/fory-core/src/serializer/arc.rs
index 812dee35d..af2b13cf7 100644
--- a/rust/fory-core/src/serializer/arc.rs
+++ b/rust/fory-core/src/serializer/arc.rs
@@ -18,12 +18,12 @@
use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::{ReadContext, WriteContext};
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::RefFlag;
use anyhow::anyhow;
use std::sync::Arc;
-impl<T: Serializer + Default + Send + Sync + 'static> Serializer for Arc<T> {
+impl<T: Serializer + ForyDefault + Send + Sync + 'static> Serializer for
Arc<T> {
fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader);
@@ -79,3 +79,9 @@ impl<T: Serializer + Default + Send + Sync + 'static>
Serializer for Arc<T> {
self
}
}
+
+impl<T: ForyDefault> ForyDefault for Arc<T> {
+ fn fory_default() -> Self {
+ Arc::new(T::fory_default())
+ }
+}
diff --git a/rust/fory-core/src/serializer/bool.rs
b/rust/fory-core/src/serializer/bool.rs
index 3568d3950..541de9bd3 100644
--- a/rust/fory-core/src/serializer/bool.rs
+++ b/rust/fory-core/src/serializer/bool.rs
@@ -19,7 +19,7 @@ use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::TypeId;
use std::mem;
@@ -48,3 +48,9 @@ impl Serializer for bool {
self
}
}
+
+impl ForyDefault for bool {
+ fn fory_default() -> Self {
+ false
+ }
+}
diff --git a/rust/fory-core/src/serializer/box_.rs
b/rust/fory-core/src/serializer/box_.rs
index 8a63236d6..3715f802c 100644
--- a/rust/fory-core/src/serializer/box_.rs
+++ b/rust/fory-core/src/serializer/box_.rs
@@ -19,9 +19,9 @@ use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
-impl<T: Serializer + Default> Serializer for Box<T> {
+impl<T: Serializer + ForyDefault> Serializer for Box<T> {
fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
Ok(Box::new(T::fory_read_data(context, is_field)?))
}
@@ -54,3 +54,9 @@ impl<T: Serializer + Default> Serializer for Box<T> {
self
}
}
+
+impl<T: ForyDefault> ForyDefault for Box<T> {
+ fn fory_default() -> Self {
+ Box::new(T::fory_default())
+ }
+}
diff --git a/rust/fory-core/src/serializer/collection.rs
b/rust/fory-core/src/serializer/collection.rs
index b3ddf77ec..0a95f16c0 100644
--- a/rust/fory-core/src/serializer/collection.rs
+++ b/rust/fory-core/src/serializer/collection.rs
@@ -18,7 +18,7 @@
use crate::error::Error;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::Mode;
// const TRACKING_REF: u8 = 0b1;
@@ -101,7 +101,7 @@ pub fn read_collection_type_info(
pub fn read_collection<C, T>(context: &mut ReadContext) -> Result<C, Error>
where
- T: Serializer + Default,
+ T: Serializer + ForyDefault,
C: FromIterator<T>,
{
let len = context.reader.read_varuint32();
diff --git a/rust/fory-core/src/serializer/datetime.rs
b/rust/fory-core/src/serializer/datetime.rs
index 7a5c1bd38..b1d47a2f5 100644
--- a/rust/fory-core/src/serializer/datetime.rs
+++ b/rust/fory-core/src/serializer/datetime.rs
@@ -19,6 +19,7 @@ use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
+use crate::serializer::ForyDefault;
use crate::serializer::Serializer;
use crate::types::TypeId;
use crate::util::EPOCH;
@@ -93,3 +94,15 @@ impl Serializer for NaiveDate {
self
}
}
+
+impl ForyDefault for NaiveDateTime {
+ fn fory_default() -> Self {
+ NaiveDateTime::default()
+ }
+}
+
+impl ForyDefault for NaiveDate {
+ fn fory_default() -> Self {
+ NaiveDate::default()
+ }
+}
diff --git a/rust/fory-core/src/serializer/enum_.rs
b/rust/fory-core/src/serializer/enum_.rs
index caa9800f7..fc95494f8 100644
--- a/rust/fory-core/src/serializer/enum_.rs
+++ b/rust/fory-core/src/serializer/enum_.rs
@@ -19,7 +19,7 @@ use crate::error::Error;
use crate::fory::Fory;
use crate::meta::{MetaString, TypeMeta};
use crate::resolver::context::{ReadContext, WriteContext};
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::{Mode, RefFlag, TypeId};
#[inline(always)]
@@ -89,7 +89,7 @@ pub fn read_type_info<T: Serializer>(context: &mut
ReadContext, is_field: bool)
}
#[inline(always)]
-pub fn read_compatible<T: Serializer + Default>(context: &mut ReadContext) ->
Result<T, Error> {
+pub fn read_compatible<T: Serializer + ForyDefault>(context: &mut ReadContext)
-> Result<T, Error> {
T::fory_read_type_info(context, true);
T::fory_read_data(context, true)
}
@@ -102,13 +102,13 @@ pub fn write<T: Serializer>(this: &T, context: &mut
WriteContext, is_field: bool
}
#[inline(always)]
-pub fn read<T: Serializer + Default>(
+pub fn read<T: Serializer + ForyDefault>(
context: &mut ReadContext,
is_field: bool,
) -> Result<T, Error> {
let ref_flag = context.reader.read_i8();
if ref_flag == RefFlag::Null as i8 {
- Ok(T::default())
+ Ok(T::fory_default())
} else if ref_flag == (RefFlag::NotNullValue as i8) {
T::fory_read_type_info(context, false);
T::fory_read_data(context, is_field)
diff --git a/rust/fory-core/src/serializer/list.rs
b/rust/fory-core/src/serializer/list.rs
index 89d699a8c..23c51823d 100644
--- a/rust/fory-core/src/serializer/list.rs
+++ b/rust/fory-core/src/serializer/list.rs
@@ -20,7 +20,7 @@ use crate::fory::Fory;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
use crate::serializer::primitive_list;
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::TypeId;
use std::any::TypeId as RsTypeId;
use std::mem;
@@ -42,7 +42,7 @@ fn check_primitive<T: 'static>() -> Option<TypeId> {
})
}
-impl<T: Serializer + Default> Serializer for Vec<T> {
+impl<T: Serializer + ForyDefault> Serializer for Vec<T> {
fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
match check_primitive::<T>() {
Some(_) => {
@@ -107,3 +107,9 @@ impl<T: Serializer + Default> Serializer for Vec<T> {
self
}
}
+
+impl<T> ForyDefault for Vec<T> {
+ fn fory_default() -> Self {
+ Vec::new()
+ }
+}
diff --git a/rust/fory-core/src/serializer/map.rs
b/rust/fory-core/src/serializer/map.rs
index 5a4bc875e..6e07e0749 100644
--- a/rust/fory-core/src/serializer/map.rs
+++ b/rust/fory-core/src/serializer/map.rs
@@ -19,7 +19,7 @@ use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
-use crate::serializer::{read_ref_info_data, write_ref_info_data, Serializer};
+use crate::serializer::{read_ref_info_data, write_ref_info_data, ForyDefault,
Serializer};
use crate::types::{TypeId, SIZE_OF_REF_AND_TYPE};
use std::collections::HashMap;
use std::mem;
@@ -80,7 +80,7 @@ fn write_chunk_size(context: &mut WriteContext,
header_offset: usize, size: u8)
context.writer.set_bytes(header_offset + 1, &[size]);
}
-impl<K: Serializer + Default + Eq + std::hash::Hash, V: Serializer + Default>
Serializer
+impl<K: Serializer + ForyDefault + Eq + std::hash::Hash, V: Serializer +
ForyDefault> Serializer
for HashMap<K, V>
{
fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
@@ -169,7 +169,7 @@ impl<K: Serializer + Default + Eq + std::hash::Hash, V:
Serializer + Default> Se
}
let header = context.reader.read_u8();
if header & KEY_NULL != 0 && header & VALUE_NULL != 0 {
- map.insert(K::default(), V::default());
+ map.insert(K::fory_default(), V::fory_default());
len_counter += 1;
continue;
}
@@ -185,7 +185,7 @@ impl<K: Serializer + Default + Eq + std::hash::Hash, V:
Serializer + Default> Se
false
};
let value = read_ref_info_data(context, value_declared,
skip_ref_flag, false)?;
- map.insert(K::default(), value);
+ map.insert(K::fory_default(), value);
len_counter += 1;
continue;
}
@@ -197,7 +197,7 @@ impl<K: Serializer + Default + Eq + std::hash::Hash, V:
Serializer + Default> Se
false
};
let key = read_ref_info_data(context, key_declared,
skip_ref_flag, false)?;
- map.insert(key, V::default());
+ map.insert(key, V::fory_default());
len_counter += 1;
continue;
}
@@ -241,3 +241,9 @@ impl<K: Serializer + Default + Eq + std::hash::Hash, V:
Serializer + Default> Se
self
}
}
+
+impl<K, V> ForyDefault for HashMap<K, V> {
+ fn fory_default() -> Self {
+ HashMap::new()
+ }
+}
diff --git a/rust/fory-core/src/serializer/mod.rs
b/rust/fory-core/src/serializer/mod.rs
index bc9c66599..3e632502a 100644
--- a/rust/fory-core/src/serializer/mod.rs
+++ b/rust/fory-core/src/serializer/mod.rs
@@ -60,7 +60,7 @@ pub fn write_ref_info_data<T: Serializer + 'static>(
}
}
-pub fn read_ref_info_data<T: Serializer + Default>(
+pub fn read_ref_info_data<T: Serializer + ForyDefault>(
context: &mut ReadContext,
is_field: bool,
skip_ref_flag: bool,
@@ -69,7 +69,7 @@ pub fn read_ref_info_data<T: Serializer + Default>(
if !skip_ref_flag {
let ref_flag = context.reader.read_i8();
if ref_flag == RefFlag::Null as i8 {
- Ok(T::default())
+ Ok(T::fory_default())
} else if ref_flag == (RefFlag::NotNullValue as i8) {
if !skip_type_info {
T::fory_read_type_info(context, is_field);
@@ -84,7 +84,7 @@ pub fn read_ref_info_data<T: Serializer + Default>(
} 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
- Ok(T::default())
+ Ok(T::fory_default())
} else {
unimplemented!("Unknown ref flag: {}", ref_flag)
}
@@ -101,6 +101,19 @@ pub fn get_skip_ref_flag<T: Serializer>(fory: &Fory) ->
bool {
!T::fory_is_option() && PRIMITIVE_TYPES.contains(&elem_type_id)
}
+pub trait ForyDefault: Sized {
+ fn fory_default() -> Self;
+}
+
+// We can't add blanket impl for all T: Default because it conflicts with
other impls.
+// For example, upstream crates may add a new impl of trait
`std::default::Default` for
+// type `std::rc::Rc<(dyn std::any::Any + 'static)>` in future versions.
+// impl<T: Default + Sized> ForyDefault for T {
+// fn fory_default() -> Self {
+// Default::default()
+// }
+// }
+
pub trait Serializer: 'static {
/// Entry point of the serialization.
fn fory_write(&self, context: &mut WriteContext, is_field: bool)
@@ -112,7 +125,7 @@ pub trait Serializer: 'static {
fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self,
Error>
where
- Self: Sized + Default,
+ Self: Sized + ForyDefault,
{
read_ref_info_data(context, is_field, false, false)
}
@@ -181,7 +194,7 @@ pub trait Serializer: 'static {
fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error>
where
- Self: Sized + Default;
+ Self: Sized + ForyDefault;
fn fory_concrete_type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<Self>()
diff --git a/rust/fory-core/src/serializer/number.rs
b/rust/fory-core/src/serializer/number.rs
index 352e9c0bb..ca4c8c5ed 100644
--- a/rust/fory-core/src/serializer/number.rs
+++ b/rust/fory-core/src/serializer/number.rs
@@ -20,7 +20,7 @@ use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::TypeId;
macro_rules! impl_num_serializer {
@@ -50,6 +50,11 @@ macro_rules! impl_num_serializer {
self
}
}
+ impl ForyDefault for $ty {
+ fn fory_default() -> Self {
+ 0 as $ty
+ }
+ }
};
}
diff --git a/rust/fory-core/src/serializer/option.rs
b/rust/fory-core/src/serializer/option.rs
index ad59fa9a9..8726c94b5 100644
--- a/rust/fory-core/src/serializer/option.rs
+++ b/rust/fory-core/src/serializer/option.rs
@@ -19,9 +19,9 @@ use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
-impl<T: Serializer + Default> Serializer for Option<T> {
+impl<T: Serializer + ForyDefault> Serializer for Option<T> {
fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
Ok(Some(T::fory_read_data(context, is_field)?))
}
@@ -69,3 +69,9 @@ impl<T: Serializer + Default> Serializer for Option<T> {
self
}
}
+
+impl<T: ForyDefault> ForyDefault for Option<T> {
+ fn fory_default() -> Self {
+ None
+ }
+}
diff --git a/rust/fory-core/src/serializer/rc.rs
b/rust/fory-core/src/serializer/rc.rs
index 8fd1b1c26..45a12ffa3 100644
--- a/rust/fory-core/src/serializer/rc.rs
+++ b/rust/fory-core/src/serializer/rc.rs
@@ -18,12 +18,12 @@
use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::{ReadContext, WriteContext};
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::RefFlag;
use anyhow::anyhow;
use std::rc::Rc;
-impl<T: Serializer + Default + 'static> Serializer for Rc<T> {
+impl<T: Serializer + ForyDefault + 'static> Serializer for Rc<T> {
fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader);
@@ -79,3 +79,9 @@ impl<T: Serializer + Default + 'static> Serializer for Rc<T> {
self
}
}
+
+impl<T: ForyDefault> ForyDefault for Rc<T> {
+ fn fory_default() -> Self {
+ Rc::new(T::fory_default())
+ }
+}
diff --git a/rust/fory-core/src/serializer/set.rs
b/rust/fory-core/src/serializer/set.rs
index 79db7af4c..c87d8e1b9 100644
--- a/rust/fory-core/src/serializer/set.rs
+++ b/rust/fory-core/src/serializer/set.rs
@@ -22,12 +22,13 @@ use crate::resolver::context::WriteContext;
use crate::serializer::collection::{
read_collection, read_collection_type_info, write_collection,
write_collection_type_info,
};
-use crate::serializer::Serializer;
+
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::TypeId;
use std::collections::HashSet;
use std::mem;
-impl<T: Serializer + Default + Eq + std::hash::Hash> Serializer for HashSet<T>
{
+impl<T: Serializer + ForyDefault + Eq + std::hash::Hash> Serializer for
HashSet<T> {
fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
write_collection(self, context, is_field);
}
@@ -60,3 +61,9 @@ impl<T: Serializer + Default + Eq + std::hash::Hash>
Serializer for HashSet<T> {
self
}
}
+
+impl<T> ForyDefault for HashSet<T> {
+ fn fory_default() -> Self {
+ HashSet::new()
+ }
+}
diff --git a/rust/fory-core/src/serializer/string.rs
b/rust/fory-core/src/serializer/string.rs
index f8c0d390a..b82811079 100644
--- a/rust/fory-core/src/serializer/string.rs
+++ b/rust/fory-core/src/serializer/string.rs
@@ -20,7 +20,7 @@ use crate::fory::Fory;
use crate::meta::get_latin1_length;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
use crate::types::TypeId;
use std::mem;
@@ -96,3 +96,9 @@ impl Serializer for String {
self
}
}
+
+impl ForyDefault for String {
+ fn fory_default() -> Self {
+ String::new()
+ }
+}
diff --git a/rust/fory-core/src/serializer/trait_object.rs
b/rust/fory-core/src/serializer/trait_object.rs
index cf850536b..b94d2f31a 100644
--- a/rust/fory-core/src/serializer/trait_object.rs
+++ b/rust/fory-core/src/serializer/trait_object.rs
@@ -18,7 +18,7 @@
use crate::error::Error;
use crate::fory::Fory;
use crate::resolver::context::{ReadContext, WriteContext};
-use crate::serializer::Serializer;
+use crate::serializer::{ForyDefault, Serializer};
/// Helper functions for trait object serialization to reduce code duplication
///
@@ -118,17 +118,17 @@ macro_rules! resolve_and_deserialize {
/// ```rust,ignore
/// use fory_core::register_trait_type;
/// use fory_core::serializer::Serializer;
-/// use fory_derive::Fory;
+/// use fory_derive::ForyObject;
///
/// trait Animal: Serializer {
/// fn speak(&self) -> String;
/// fn name(&self) -> &str;
/// }
///
-/// #[derive(Fory)]
+/// #[derive(ForyObject)]
/// struct Dog { name: String }
///
-/// #[derive(Fory)]
+/// #[derive(ForyObject)]
/// struct Cat { name: String }
///
/// impl Animal for Dog {
@@ -155,6 +155,12 @@ macro_rules! register_trait_type {
}
}
+ impl $crate::serializer::ForyDefault for Box<dyn $trait_name> {
+ fn fory_default() -> Self {
+ Box::new(<register_trait_type!(@first_type $($impl_type),+) as
std::default::Default>::default())
+ }
+ }
+
// 2. Auto-generate Rc wrapper type and conversions
$crate::generate_smart_pointer_wrapper!(Rc, $trait_name,
$($impl_type),+);
@@ -202,10 +208,7 @@ macro_rules! register_trait_type {
// Box<dyn Trait> is polymorphic - type info is read per
element
}
- fn fory_read(context: &mut $crate::resolver::context::ReadContext,
is_field: bool) -> Result<Self, $crate::error::Error>
- where
- Self: Sized + Default,
- {
+ fn fory_read(context: &mut $crate::resolver::context::ReadContext,
is_field: bool) -> Result<Self, $crate::error::Error> {
let fory_type_id =
$crate::serializer::trait_object::read_trait_object_headers(context)?;
$crate::resolve_and_deserialize!(
fory_type_id, context, is_field,
@@ -214,10 +217,7 @@ macro_rules! register_trait_type {
)
}
- fn fory_read_data(_context: &mut
$crate::resolver::context::ReadContext, _is_field: bool) -> Result<Self,
$crate::error::Error>
- where
- Self: Sized + Default,
- {
+ fn fory_read_data(_context: &mut
$crate::resolver::context::ReadContext, _is_field: bool) -> Result<Self,
$crate::error::Error> {
// This should not be called for polymorphic types like
Box<dyn Trait>
// The fory_read method handles the polymorphic dispatch
panic!("fory_read_data should not be called directly on
polymorphic Box<dyn {}> trait object", stringify!($trait_name));
@@ -318,6 +318,12 @@ macro_rules! generate_smart_pointer_wrapper {
}
}
+ impl $crate::serializer::ForyDefault for [<$trait_name Rc>] {
+ fn fory_default() -> Self {
+ Self(std::rc::Rc::new(<register_trait_type!(@first_type
$($impl_type),+) as std::default::Default>::default()))
+ }
+ }
+
impl std::fmt::Debug for [<$trait_name Rc>] {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
let any_obj = <dyn $trait_name as
$crate::serializer::Serializer>::as_any(&*self.0);
@@ -375,6 +381,12 @@ macro_rules! generate_smart_pointer_wrapper {
}
}
+ impl $crate::serializer::ForyDefault for [<$trait_name Arc>] {
+ fn fory_default() -> Self {
+ Self(std::sync::Arc::new(<register_trait_type!(@first_type
$($impl_type),+) as std::default::Default>::default()))
+ }
+ }
+
impl std::fmt::Debug for [<$trait_name Arc>] {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
let any_obj = <dyn $trait_name as
$crate::serializer::Serializer>::as_any(&*self.0);
@@ -414,10 +426,7 @@ macro_rules! impl_smart_pointer_serializer {
$crate::downcast_and_serialize!(any_obj, context, is_field,
$trait_name, $($impl_type),+);
}
- fn fory_read(context: &mut $crate::resolver::context::ReadContext,
is_field: bool) -> Result<Self, $crate::error::Error>
- where
- Self: Sized + Default,
- {
+ fn fory_read(context: &mut $crate::resolver::context::ReadContext,
is_field: bool) -> Result<Self, $crate::error::Error> {
let fory_type_id =
$crate::serializer::trait_object::read_trait_object_headers(context)?;
// Use type resolver to deserialize any registered type
@@ -451,10 +460,7 @@ macro_rules! impl_smart_pointer_serializer {
)))
}
- fn fory_read_data(context: &mut
$crate::resolver::context::ReadContext, is_field: bool) -> Result<Self,
$crate::error::Error>
- where
- Self: Sized + Default,
- {
+ fn fory_read_data(context: &mut
$crate::resolver::context::ReadContext, is_field: bool) -> Result<Self,
$crate::error::Error> {
let concrete_fory_type_id = context.reader.read_varuint32();
$crate::resolve_and_deserialize!(
concrete_fory_type_id, context, is_field,
@@ -505,15 +511,18 @@ macro_rules! impl_smart_pointer_serializer {
// Keep the existing Box<dyn Serializer> implementation as is
impl Default for Box<dyn Serializer> {
fn default() -> Self {
- panic!("Box<dyn Serializer> cannot be default-constructed")
+ Box::new(0)
+ }
+}
+
+impl ForyDefault for Box<dyn Serializer> {
+ fn fory_default() -> Self {
+ Box::new(0)
}
}
impl Serializer for Box<dyn Serializer> {
- fn fory_write(&self, context: &mut WriteContext, is_field: bool)
- where
- Self: Sized,
- {
+ fn fory_write(&self, context: &mut WriteContext, is_field: bool) {
let fory_type_id = (**self).fory_type_id_dyn(context.get_fory());
let concrete_type_id = (**self).fory_concrete_type_id();
@@ -545,10 +554,7 @@ impl Serializer for Box<dyn Serializer> {
// Box<dyn Serializer> is polymorphic - type info is read per element
}
- fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self,
Error>
- where
- Self: Sized + Default,
- {
+ fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self,
Error> {
let fory_type_id = read_trait_object_headers(context)?;
let type_resolver = context.get_fory().get_type_resolver();
@@ -590,89 +596,11 @@ impl Serializer for Box<dyn Serializer> {
}
}
- fn fory_read_data(_context: &mut ReadContext, _is_field: bool) ->
Result<Self, Error>
- where
- Self: Sized + Default,
- {
+ fn fory_read_data(_context: &mut ReadContext, _is_field: bool) ->
Result<Self, Error> {
panic!("fory_read_data should not be called directly on Box<dyn
Serializer>");
}
}
-// Note: The macro invocations are moved to the end of the file after macro
definitions
-
-/// Macro to generate serializer implementations for smart pointer types with
Serializer trait
-#[macro_export]
-macro_rules! generate_smart_pointer_serializer {
- ($pointer_type:ident, $trait_name:ident) => {
- impl Default for $pointer_type<dyn $crate::serializer::$trait_name> {
- fn default() -> Self {
- panic!("{}<<dyn {}>> cannot be default-constructed",
stringify!($pointer_type), stringify!($trait_name))
- }
- }
-
- impl $crate::serializer::Serializer for $pointer_type<dyn
$crate::serializer::$trait_name> {
- fn fory_write(&self, context: &mut
$crate::resolver::context::WriteContext, is_field: bool) {
- use $crate::types::{Mode, RefFlag, TypeId};
-
- context.writer.write_i8(RefFlag::NotNullValue as i8);
-
- let fory_type_id =
(**self).fory_type_id_dyn(context.get_fory());
- context.writer.write_varuint32(fory_type_id);
-
- if context.get_fory().get_mode() == &Mode::Compatible
- && (fory_type_id & 0xff == TypeId::NAMED_COMPATIBLE_STRUCT
as u32
- || fory_type_id & 0xff == TypeId::COMPATIBLE_STRUCT as
u32)
- {
- let concrete_type_id = (**self).fory_concrete_type_id();
- let meta_index = context.push_meta(concrete_type_id) as
u32;
- context.writer.write_varuint32(meta_index);
- }
-
- (**self).fory_write_data(context, is_field);
- }
-
- fn fory_write_data(&self, _context: &mut
$crate::resolver::context::WriteContext, _is_field: bool) {
- panic!("fory_write_data should not be called directly on
{}<<dyn {}>>", stringify!($pointer_type), stringify!($trait_name));
- }
-
- fn fory_type_id_dyn(&self, fory: &$crate::fory::Fory) -> u32 {
- (**self).fory_type_id_dyn(fory)
- }
-
- fn fory_is_polymorphic() -> bool {
- true
- }
-
- fn fory_write_type_info(_context: &mut
$crate::resolver::context::WriteContext, _is_field: bool) {
- // Pointer<dyn Trait> is polymorphic - type info is written
per element
- }
-
- fn fory_read_type_info(_context: &mut
$crate::resolver::context::ReadContext, _is_field: bool) {
- // Pointer<dyn Trait> is polymorphic - type info is read per
element
- }
-
- fn fory_read(_context: &mut
$crate::resolver::context::ReadContext, _is_field: bool) -> Result<Self,
$crate::error::Error>
- where
- Self: Sized + Default,
- {
- // For now, Rc and Arc deserialization is not implemented
- // This would require complex reference counting logic
-
Err($crate::error::Error::Other($crate::error::AnyhowError::msg(
- format!("{}<<dyn {}>> deserialization not yet implemented
- use Box<dyn {}> instead",
- stringify!($pointer_type), stringify!($trait_name),
stringify!($trait_name))
- )))
- }
-
- fn fory_read_data(_context: &mut
$crate::resolver::context::ReadContext, _is_field: bool) -> Result<Self,
$crate::error::Error>
- where
- Self: Sized + Default,
- {
- panic!("fory_read_data should not be called directly on
{}<<dyn {}>>", stringify!($pointer_type), stringify!($trait_name));
- }
- }
- };
-}
-
/// Helper macros for automatic conversions in derive code
/// These are used by fory-derive to generate transparent conversions
///
diff --git a/rust/fory-derive/src/lib.rs b/rust/fory-derive/src/lib.rs
index e6f86ec3d..7eb3ea78a 100644
--- a/rust/fory-derive/src/lib.rs
+++ b/rust/fory-derive/src/lib.rs
@@ -22,7 +22,7 @@
//!
//! ## Available Macros
//!
-//! ### `#[derive(Fory)]`
+//! ### `#[derive(ForyObject)]`
//!
//! Generates object serialization code for structs and enums. This macro
//! implements the `Serializer` trait, enabling full object graph serialization
@@ -36,10 +36,10 @@
//!
//! **Example:**
//! ```rust
-//! use fory_derive::Fory;
+//! use fory_derive::ForyObject;
//! use std::collections::HashMap;
//!
-//! #[derive(Fory, Debug, PartialEq)]
+//! #[derive(ForyObject, Debug, PartialEq)]
//! struct Person {
//! name: String,
//! age: i32,
@@ -48,13 +48,13 @@
//! metadata: HashMap<String, String>,
//! }
//!
-//! #[derive(Fory, Debug, PartialEq)]
+//! #[derive(ForyObject, Debug, PartialEq)]
//! struct Address {
//! street: String,
//! city: String,
//! }
//!
-//! #[derive(Fory, Debug, PartialEq, Default)]
+//! #[derive(ForyObject, Debug, PartialEq, Default)]
//! enum Status {
//! #[default]
//! Active,
@@ -90,7 +90,7 @@
//!
//! ## Generated Code
//!
-//! ### For `#[derive(Fory)]`
+//! ### For `#[derive(ForyObject)]`
//!
//! The macro generates:
//! - `Serializer` trait implementation
@@ -134,9 +134,9 @@
//!
//! ```rust
//! use fory_core::{fory::Fory, error::Error};
-//! use fory_derive::Fory;
+//! use fory_derive::ForyObject;
//!
-//! #[derive(Fory, Debug, PartialEq)]
+//! #[derive(ForyObject, Debug, PartialEq)]
//! struct MyData {
//! value: i32,
//! text: String,
@@ -183,22 +183,22 @@ mod util;
/// # Example
///
/// ```rust
-/// use fory_derive::Fory;
+/// use fory_derive::ForyObject;
///
-/// #[derive(Fory, Debug, PartialEq)]
+/// #[derive(ForyObject, Debug, PartialEq)]
/// struct Person {
/// name: String,
/// age: i32,
/// address: Address,
/// }
///
-/// #[derive(Fory, Debug, PartialEq)]
+/// #[derive(ForyObject, Debug, PartialEq)]
/// struct Address {
/// street: String,
/// city: String,
/// }
/// ```
-#[proc_macro_derive(Fory)]
+#[proc_macro_derive(ForyObject)]
pub fn proc_macro_derive_fory_object(input: proc_macro::TokenStream) ->
TokenStream {
let input = parse_macro_input!(input as DeriveInput);
diff --git a/rust/fory-derive/src/object/read.rs
b/rust/fory-derive/src/object/read.rs
index 133dace90..0bd037783 100644
--- a/rust/fory-derive/src/object/read.rs
+++ b/rust/fory-derive/src/object/read.rs
@@ -43,7 +43,7 @@ fn declare_var(fields: &[&Field]) -> Vec<TokenStream> {
| TraitObjectField::RcDyn(_)
| TraitObjectField::ArcDyn(_) => {
quote! {
- let mut #var_name: #ty = Default::default();
+ let mut #var_name: #ty = <#ty as
fory_core::serializer::ForyDefault>::fory_default();
}
}
_ => {
@@ -218,7 +218,7 @@ pub fn gen_read_data(fields: &[&Field]) -> TokenStream {
| TraitObjectField::RcDyn(_)
| TraitObjectField::ArcDyn(_) => {
quote! {
- let mut #private_ident: #ty =
Default::default();
+ let mut #private_ident: #ty = <#ty as
fory_core::serializer::ForyDefault>::fory_default();
}
}
_ => {
@@ -383,7 +383,7 @@ fn gen_read_compatible_match_arm(field: &Field, var_name:
&Ident) -> TokenStream
let generic_token = generic_tree_to_tokens(&generic_tree, true);
let read_nullable_fn_name = create_read_nullable_fn_name(field);
- let base_ty = match &ty {
+ let _base_ty = match &ty {
Type::Path(type_path) =>
&type_path.path.segments.first().unwrap().ident,
_ => panic!("Unsupported type"),
};
@@ -402,7 +402,7 @@ fn gen_read_compatible_match_arm(field: &Field, var_name:
&Ident) -> TokenStream
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(context, &remote_nullable_type,
read_ref_flag).unwrap();
- #var_name = Some(#base_ty::default());
+ #var_name = Some(<#ty as
fory_core::serializer::ForyDefault>::fory_default());
} else {
println!("Try to deserialize_compatible: {}",
#field_name_str);
#var_name = Some(
@@ -437,7 +437,7 @@ pub fn gen_read(struct_ident: &Ident) -> TokenStream {
_ => unreachable!()
}
} else if ref_flag == (fory_core::types::RefFlag::Null as i8) {
- Ok(Self::default())
+ Ok(<Self as fory_core::serializer::ForyDefault>::fory_default())
// Err(fory_core::error::AnyhowError::msg("Try to read non-option
type to null"))?
} else if ref_flag == (fory_core::types::RefFlag::Ref as i8) {
Err(fory_core::error::Error::Ref)
diff --git a/rust/fory-derive/src/object/serializer.rs
b/rust/fory-derive/src/object/serializer.rs
index a4cea60bb..6646dd617 100644
--- a/rust/fory-derive/src/object/serializer.rs
+++ b/rust/fory-derive/src/object/serializer.rs
@@ -21,23 +21,26 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::Data;
-pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
- let name = &ast.ident;
-
- // Check if Default is already derived/implemented
- let has_existing_default = ast.attrs.iter().any(|attr| {
+fn has_existing_default(ast: &syn::DeriveInput, trait_name: &str) -> bool {
+ ast.attrs.iter().any(|attr| {
attr.path().is_ident("derive") && {
let mut has_default = false;
let _ = attr.parse_nested_meta(|meta| {
- if meta.path.is_ident("Default") {
+ if meta.path.is_ident(trait_name) {
has_default = true;
}
Ok(())
});
has_default
}
- });
+ })
+}
+pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
+ let name = &ast.ident;
+
+ // Check if ForyDefault is already derived/implemented
+ let has_existing_default = has_existing_default(ast, "ForyDefault");
let default_impl = if !has_existing_default {
generate_default_impl(ast)
} else {
@@ -117,6 +120,8 @@ pub fn derive_serializer(ast: &syn::DeriveInput) ->
TokenStream {
let type_idx = misc::allocate_type_id();
let gen = quote! {
+ use fory_core::serializer::ForyDefault as _;
+
#default_impl
impl fory_core::serializer::StructSerializer for #name {
@@ -190,60 +195,120 @@ pub fn derive_serializer(ast: &syn::DeriveInput) ->
TokenStream {
fn generate_default_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
let name = &ast.ident;
+ let has_existing_default = has_existing_default(ast, "Default");
- if let Data::Struct(s) = &ast.data {
- let fields = sorted_fields(&s.fields);
+ match &ast.data {
+ Data::Struct(s) => {
+ let fields = sorted_fields(&s.fields);
- use super::util::{
- classify_trait_object_field, create_wrapper_types_arc,
create_wrapper_types_rc,
- TraitObjectField,
- };
+ use super::util::{
+ classify_trait_object_field, create_wrapper_types_arc,
create_wrapper_types_rc,
+ TraitObjectField,
+ };
- let field_inits = fields.iter().map(|field| {
- let ident = &field.ident;
- let ty = &field.ty;
+ let field_inits = fields.iter().map(|field| {
+ let ident = &field.ident;
+ let ty = &field.ty;
- match classify_trait_object_field(ty) {
- TraitObjectField::RcDyn(trait_name) => {
- let types = create_wrapper_types_rc(&trait_name);
- let wrapper_ty = types.wrapper_ty;
- let trait_ident = types.trait_ident;
- quote! {
- #ident: {
- let wrapper = #wrapper_ty::default();
- std::rc::Rc::<dyn #trait_ident>::from(wrapper)
+ match classify_trait_object_field(ty) {
+ TraitObjectField::RcDyn(trait_name) => {
+ let types = create_wrapper_types_rc(&trait_name);
+ let wrapper_ty = types.wrapper_ty;
+ let trait_ident = types.trait_ident;
+ quote! {
+ #ident: {
+ let wrapper = #wrapper_ty::default();
+ std::rc::Rc::<dyn #trait_ident>::from(wrapper)
+ }
+ }
+ }
+ TraitObjectField::ArcDyn(trait_name) => {
+ let types = create_wrapper_types_arc(&trait_name);
+ let wrapper_ty = types.wrapper_ty;
+ let trait_ident = types.trait_ident;
+ quote! {
+ #ident: {
+ let wrapper = #wrapper_ty::default();
+ std::sync::Arc::<dyn
#trait_ident>::from(wrapper)
+ }
+ }
+ }
+ _ => {
+ quote! {
+ #ident: <#ty as
fory_core::serializer::ForyDefault>::fory_default()
}
}
}
- TraitObjectField::ArcDyn(trait_name) => {
- let types = create_wrapper_types_arc(&trait_name);
- let wrapper_ty = types.wrapper_ty;
- let trait_ident = types.trait_ident;
- quote! {
- #ident: {
- let wrapper = #wrapper_ty::default();
- std::sync::Arc::<dyn #trait_ident>::from(wrapper)
+ });
+
+ if has_existing_default {
+ quote! {
+ impl fory_core::serializer::ForyDefault for #name {
+ fn fory_default() -> Self {
+ Self::default()
}
}
}
- _ => {
- quote! {
- #ident: Default::default()
+ } else {
+ quote! {
+ impl fory_core::serializer::ForyDefault for #name {
+ fn fory_default() -> Self {
+ Self {
+ #(#field_inits),*
+ }
+ }
+ }
+ impl std::default::Default for #name {
+ fn default() -> Self {
+ Self::fory_default()
+ }
}
}
}
- });
+ }
+ Data::Enum(e) => {
+ // Check if any variant has #[default] attribute (indicates user
is deriving Default)
+ let has_default_variant = e
+ .variants
+ .iter()
+ .any(|v| v.attrs.iter().any(|attr|
attr.path().is_ident("default")));
+
+ // For C-like enums, implement Default by returning the first
variant
+ // Only if there's no #[default] attribute (which means Default is
being derived)
+ if !has_default_variant {
+ if let Some(first_variant) = e.variants.first() {
+ let variant_ident = &first_variant.ident;
+ quote! {
+ impl fory_core::serializer::ForyDefault for #name {
+ fn fory_default() -> Self {
+ Self::#variant_ident
+ }
+ }
- return quote! {
- impl std::default::Default for #name {
- fn default() -> Self {
- Self {
- #(#field_inits),*
+ impl std::default::Default for #name {
+ fn default() -> Self {
+ Self::#variant_ident
+ }
+ }
+ }
+ } else {
+ // impl fory_core::serializer::ForyDefault for #name {
+ // fn fory_default() -> Self {
+ // panic!("No unit-like variants found in enum
{}", stringify!(#name));
+ // }
+ // }
+ quote! {}
+ }
+ } else {
+ quote! {
+ impl fory_core::serializer::ForyDefault for #name {
+ fn fory_default() -> Self {
+ Self::default()
+ }
}
}
}
- };
+ }
+ Data::Union(_) => quote! {},
}
-
- quote! {}
}
diff --git a/rust/fory-derive/src/object/util.rs
b/rust/fory-derive/src/object/util.rs
index 381dd232e..dfdc42431 100644
--- a/rust/fory-derive/src/object/util.rs
+++ b/rust/fory-derive/src/object/util.rs
@@ -72,7 +72,6 @@ pub(super) fn create_wrapper_types_arc(trait_name: &str) ->
WrapperTypes {
}
}
-#[derive(Debug)]
pub(super) enum TraitObjectField {
BoxDyn,
RcDyn(String),
@@ -266,7 +265,7 @@ impl NullableTypeNode {
fory_core::types::RefFlag::NotNullValue as
i8
};
let element = if ref_flag ==
fory_core::types::RefFlag::Null as i8 {
- <#element_ty>::default()
+ <#element_ty as
fory_core::serializer::ForyDefault>::fory_default()
} else {
#element_tokens?
};
@@ -317,7 +316,7 @@ impl NullableTypeNode {
fory_core::types::RefFlag::NotNullValue as
i8
};
let element = if ref_flag ==
fory_core::types::RefFlag::Null as i8 {
- <#element_ty>::default()
+ <#element_ty as
fory_core::serializer::ForyDefault>::fory_default()
} else {
#element_tokens?
};
@@ -372,19 +371,19 @@ impl NullableTypeNode {
}
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>::default(),
<#val_ty>::default());
+ 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>::default(), value);
+ 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>::default());
+ map.insert(key, <#val_ty as
fory_core::serializer::ForyDefault>::fory_default());
len_counter += 1;
continue;
}
@@ -449,7 +448,7 @@ impl NullableTypeNode {
} else {
quote! {
let res2 = if cur_remote_nullable_type.nullable &&
ref_flag == (fory_core::types::RefFlag::Null as i8) {
- #ty::default()
+ <#ty as
fory_core::serializer::ForyDefault>::fory_default()
} else {
let type_id = cur_remote_nullable_type.type_id;
let internal_id = type_id & 0xff;
diff --git a/rust/fory-derive/src/util.rs b/rust/fory-derive/src/util.rs
index 43f7be242..2cdecc274 100644
--- a/rust/fory-derive/src/util.rs
+++ b/rust/fory-derive/src/util.rs
@@ -93,7 +93,7 @@ pub fn is_arc_dyn_trait(ty: &Type) ->
Option<(&TypeTraitObject, String)> {
None
}
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub enum CollectionTraitInfo {
VecRc(String),
VecArc(String),
diff --git a/rust/fory/src/lib.rs b/rust/fory/src/lib.rs
index 9edcf6a16..ceb369d3e 100644
--- a/rust/fory/src/lib.rs
+++ b/rust/fory/src/lib.rs
@@ -42,9 +42,9 @@
//!
//! ```rust
//! use fory::{Fory, Error};
-//! use fory_derive::Fory;
+//! use fory_derive::ForyObject;
//! use std::collections::HashMap;
-//! #[derive(Fory, Debug, PartialEq)]
+//! #[derive(ForyObject, Debug, PartialEq)]
//! struct Person {
//! name: String,
//! age: i32,
@@ -53,7 +53,7 @@
//! metadata: HashMap<String, String>,
//! }
//!
-//! #[derive(Fory, Debug, PartialEq)]
+//! #[derive(ForyObject, Debug, PartialEq)]
//! struct Address {
//! street: String,
//! city: String,
@@ -168,8 +168,8 @@
//! - `chrono::NaiveDateTime` for timestamps
//!
//! ### Custom Types
-//! - Structs with `#[derive(Fory)]` or `#[derive(ForyRow)]`
-//! - Enums with `#[derive(Fory)]`
+//! - Structs with `#[derive(ForyObject)]` or `#[derive(ForyRow)]`
+//! - Enums with `#[derive(ForyObject)]`
//!
//! ## Serialization Modes
//!
@@ -183,9 +183,9 @@
//! ```rust
//! use fory::Fory;
//! use fory_core::types::Mode;
-//! use fory_derive::Fory;
+//! use fory_derive::ForyObject;
//!
-//! #[derive(Fory, Debug)]
+//! #[derive(ForyObject, Debug)]
//! struct Config {
//! name: String,
//! value: i32,
@@ -202,9 +202,9 @@
//!
//! ```rust
//! use fory::{Fory, Error};
-//! use fory_derive::Fory;
+//! use fory_derive::ForyObject;
//!
-//! #[derive(Fory)]
+//! #[derive(ForyObject)]
//! struct Data {
//! value: i32,
//! }
@@ -246,9 +246,9 @@
//! Then use the derive macros to make your types serializable:
//!
//! ```rust
-//! use fory_derive::{Fory, ForyRow};
+//! use fory_derive::{ForyObject, ForyRow};
//!
-//! #[derive(Fory)] // For object serialization
+//! #[derive(ForyObject)] // For object serialization
//! #[derive(ForyRow)] // For row-based serialization
//! struct MyData {
//! field1: String,
diff --git a/rust/tests/tests/test_any.rs b/rust/tests/tests/test_any.rs
new file mode 100644
index 000000000..169876731
--- /dev/null
+++ b/rust/tests/tests/test_any.rs
@@ -0,0 +1,269 @@
+// 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::fory::Fory;
+use fory_derive::ForyObject;
+use std::any::Any;
+use std::rc::Rc;
+use std::sync::Arc;
+use std::vec;
+
+#[test]
+fn test_box_dyn_any() {
+ let fory = Fory::default();
+
+ let value: Box<dyn Any> = Box::new("hello".to_string());
+ let bytes = fory.serialize(&value);
+ let deserialized: Box<dyn Any> = fory.deserialize(&bytes).unwrap();
+ assert_eq!(
+ deserialized.downcast_ref::<String>().unwrap(),
+ &"hello".to_string()
+ );
+
+ let value2: Box<dyn Any> = Box::new(42i32);
+ let bytes2 = fory.serialize(&value2);
+ let deserialized2: Box<dyn Any> = fory.deserialize(&bytes2).unwrap();
+ assert_eq!(deserialized2.downcast_ref::<i32>().unwrap(), &42i32);
+
+ let value3: Box<dyn Any> = Box::new("".to_string());
+ let bytes3 = fory.serialize(&value3);
+ let deserialized3: Box<dyn Any> = fory.deserialize(&bytes3).unwrap();
+ assert_eq!(deserialized3.downcast_ref::<String>().unwrap(), "");
+
+ let value5: Box<dyn Any> = Box::new(3.15f64);
+ let bytes5 = fory.serialize(&value5);
+ let deserialized5: Box<dyn Any> = fory.deserialize(&bytes5).unwrap();
+ assert_eq!(deserialized5.downcast_ref::<f64>().unwrap(), &3.15f64);
+}
+
+#[test]
+fn test_rc_dyn_any() {
+ let fory = Fory::default();
+ let value: Rc<dyn Any> = Rc::new("world".to_string());
+ let bytes = fory.serialize(&value);
+ let deserialized: Rc<dyn Any> = fory.deserialize(&bytes).unwrap();
+ assert_eq!(
+ deserialized.downcast_ref::<String>().unwrap(),
+ &"world".to_string()
+ );
+
+ let value2: Rc<dyn Any> = Rc::new(99i32);
+ let bytes2 = fory.serialize(&value2);
+ let deserialized2: Rc<dyn Any> = fory.deserialize(&bytes2).unwrap();
+ assert_eq!(deserialized2.downcast_ref::<i32>().unwrap(), &99i32);
+
+ let value3: Rc<dyn Any> = Rc::new(true);
+ let bytes3 = fory.serialize(&value3);
+ let deserialized3: Rc<dyn Any> = fory.deserialize(&bytes3).unwrap();
+ assert_eq!(deserialized3.downcast_ref::<bool>().unwrap(), &true);
+}
+
+#[test]
+fn test_arc_dyn_any() {
+ let fory = Fory::default();
+
+ let value: Arc<dyn Any> = Arc::new("arc test".to_string());
+ let bytes = fory.serialize(&value);
+ let deserialized: Arc<dyn Any> = fory.deserialize(&bytes).unwrap();
+ assert_eq!(
+ deserialized.downcast_ref::<String>().unwrap(),
+ &"arc test".to_string()
+ );
+
+ let value2: Arc<dyn Any> = Arc::new(123i32);
+ let bytes2 = fory.serialize(&value2);
+ let deserialized2: Arc<dyn Any> = fory.deserialize(&bytes2).unwrap();
+ assert_eq!(deserialized2.downcast_ref::<i32>().unwrap(), &123i32);
+
+ let value3: Arc<dyn Any> = Arc::new(vec![1, 2, 3]);
+ let bytes3 = fory.serialize(&value3);
+ let deserialized3: Arc<dyn Any> = fory.deserialize(&bytes3).unwrap();
+ assert_eq!(
+ deserialized3.downcast_ref::<Vec<i32>>().unwrap(),
+ &vec![1, 2, 3]
+ );
+}
+
+#[test]
+fn test_rc_dyn_any_shared_reference() {
+ let fory = Fory::default();
+
+ let shared_str: Rc<dyn Any> = Rc::new("shared".to_string());
+
+ let data = vec![shared_str.clone(), shared_str.clone()];
+
+ let bytes = fory.serialize(&data);
+ let deserialized: Vec<Rc<dyn Any>> = fory.deserialize(&bytes).unwrap();
+
+ let first_str = deserialized[0].downcast_ref::<String>().unwrap();
+ let second_str = deserialized[1].downcast_ref::<String>().unwrap();
+
+ assert_eq!(first_str, "shared");
+ assert_eq!(second_str, "shared");
+ assert_eq!(Rc::strong_count(&shared_str), 3);
+}
+
+#[test]
+fn test_arc_dyn_any_shared_reference() {
+ let fory = Fory::default();
+
+ let shared_vec: Arc<dyn Any> = Arc::new(vec![1, 2, 3]);
+
+ let data = vec![shared_vec.clone(), shared_vec.clone()];
+
+ let bytes = fory.serialize(&data);
+ let deserialized: Vec<Arc<dyn Any>> = fory.deserialize(&bytes).unwrap();
+
+ let first_vec = deserialized[0].downcast_ref::<Vec<i32>>().unwrap();
+ let second_vec = deserialized[1].downcast_ref::<Vec<i32>>().unwrap();
+ assert_eq!(first_vec, &vec![1, 2, 3]);
+ assert_eq!(second_vec, &vec![1, 2, 3]);
+ assert_eq!(Arc::strong_count(&shared_vec), 3);
+}
+
+#[test]
+fn test_any_registered_by_name() {
+ use fory_derive::ForyObject;
+
+ #[derive(ForyObject, PartialEq, Debug)]
+ struct Person {
+ name: String,
+ age: i32,
+ }
+
+ let mut fory = Fory::default();
+ fory.register_by_namespace::<Person>("test", "Person");
+
+ let person = Person {
+ name: "Alice".to_string(),
+ age: 30,
+ };
+
+ let value: Box<dyn Any> = Box::new(person);
+ let bytes = fory.serialize(&value);
+ let deserialized: Box<dyn Any> = fory.deserialize(&bytes).unwrap();
+
+ let result = deserialized.downcast_ref::<Person>().unwrap();
+ assert_eq!(result.name, "Alice");
+ assert_eq!(result.age, 30);
+}
+
+#[test]
+fn test_mixed_any_types() {
+ use fory_derive::ForyObject;
+
+ #[derive(ForyObject, PartialEq, Debug)]
+ struct Item {
+ id: i32,
+ value: String,
+ }
+
+ let mut fory = Fory::default();
+ fory.register_by_name::<Item>("Item");
+
+ let item = Item {
+ id: 123,
+ value: "test".to_string(),
+ };
+
+ let mixed: Vec<Box<dyn Any>> = vec![
+ Box::new(42i32),
+ Box::new("hello".to_string()),
+ Box::new(item),
+ Box::new(3.15f64),
+ ];
+
+ let bytes = fory.serialize(&mixed);
+ let deserialized: Vec<Box<dyn Any>> = fory.deserialize(&bytes).unwrap();
+
+ assert_eq!(deserialized[0].downcast_ref::<i32>().unwrap(), &42i32);
+ assert_eq!(deserialized[1].downcast_ref::<String>().unwrap(), "hello");
+
+ let item_result = deserialized[2].downcast_ref::<Item>().unwrap();
+ assert_eq!(item_result.id, 123);
+ assert_eq!(item_result.value, "test");
+
+ assert_eq!(deserialized[3].downcast_ref::<f64>().unwrap(), &3.15f64);
+}
+
+#[derive(ForyObject, PartialEq, Debug)]
+struct Container {
+ id: i32,
+ items: Vec<String>,
+}
+
+#[test]
+fn test_arc_by_name() {
+ let mut fory = Fory::default();
+ fory.register_by_name::<Container>("Container");
+
+ let container = Container {
+ id: 999,
+ items: vec!["a".to_string(), "b".to_string(), "c".to_string()],
+ };
+
+ let value: Arc<dyn Any> = Arc::new(container);
+ let bytes = fory.serialize(&value);
+ let deserialized: Arc<dyn Any> = fory.deserialize(&bytes).unwrap();
+
+ let result = deserialized.downcast_ref::<Container>().unwrap();
+ assert_eq!(result.id, 999);
+ assert_eq!(result.items, vec!["a", "b", "c"]);
+
+ let container_vec: Vec<Arc<dyn Any>> = vec![value.clone(), value.clone()];
+ let bytes_vec = fory.serialize(&container_vec);
+ let deserialized_vec: Vec<Arc<dyn Any>> =
fory.deserialize(&bytes_vec).unwrap();
+ assert_eq!(deserialized_vec.len(), 2);
+ let first = deserialized_vec[0].downcast_ref::<Container>().unwrap();
+ let second = deserialized_vec[1].downcast_ref::<Container>().unwrap();
+ assert_eq!(first, second);
+ assert!(std::sync::Arc::ptr_eq(
+ &deserialized_vec[0],
+ &deserialized_vec[1]
+ ));
+}
+
+#[test]
+fn test_rc_by_name() {
+ let mut fory = Fory::default();
+ fory.register_by_name::<Container>("Container");
+
+ let container = Container {
+ id: 555,
+ items: vec!["x".to_string(), "y".to_string()],
+ };
+
+ let value: Rc<dyn Any> = Rc::new(container);
+ let bytes = fory.serialize(&value);
+ let deserialized: Rc<dyn Any> = fory.deserialize(&bytes).unwrap();
+
+ let result = deserialized.downcast_ref::<Container>().unwrap();
+ assert_eq!(result.id, 555);
+ assert_eq!(result.items, vec!["x", "y"]);
+
+ let container_vec: Vec<Rc<dyn Any>> = vec![value.clone(), value.clone()];
+ let bytes_vec = fory.serialize(&container_vec);
+ let deserialized_vec: Vec<Rc<dyn Any>> =
fory.deserialize(&bytes_vec).unwrap();
+ assert_eq!(deserialized_vec.len(), 2);
+ let first = deserialized_vec[0].downcast_ref::<Container>().unwrap();
+ let second = deserialized_vec[1].downcast_ref::<Container>().unwrap();
+ assert_eq!(first, second);
+ assert!(std::rc::Rc::ptr_eq(
+ &deserialized_vec[0],
+ &deserialized_vec[1]
+ ));
+}
diff --git a/rust/tests/tests/test_box.rs b/rust/tests/tests/test_box.rs
index 536069560..3f37d5a19 100644
--- a/rust/tests/tests/test_box.rs
+++ b/rust/tests/tests/test_box.rs
@@ -16,7 +16,7 @@
// under the License.
use fory_core::fory::Fory;
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use std::collections::HashMap;
#[test]
@@ -46,7 +46,7 @@ fn test_box_primitive() {
#[test]
fn test_box_struct() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Person {
name: String,
age: i32,
@@ -69,7 +69,7 @@ fn test_box_struct() {
#[test]
fn test_box_struct_separate() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Person {
name: String,
age: i32,
diff --git a/rust/tests/tests/test_compatible.rs
b/rust/tests/tests/test_compatible.rs
index 102831e41..0dc3dbd10 100644
--- a/rust/tests/tests/test_compatible.rs
+++ b/rust/tests/tests/test_compatible.rs
@@ -17,13 +17,13 @@
use fory_core::fory::Fory;
use fory_core::types::Mode::Compatible;
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use std::collections::{HashMap, HashSet};
// RUSTFLAGS="-Awarnings" cargo expand -p fory-tests --test test_compatible
#[test]
fn simple() {
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
struct Animal1 {
f1: HashMap<i8, Vec<i8>>,
f2: String,
@@ -34,7 +34,7 @@ fn simple() {
last: i8,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
struct Animal2 {
f1: HashMap<i8, Vec<i8>>,
f3: Vec<i8>,
@@ -70,14 +70,14 @@ fn simple() {
#[test]
fn skip_option() {
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
struct Item1 {
f1: Option<i32>,
f2: Option<String>,
last: i64,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
struct Item2 {
f1: i8,
f2: i8,
@@ -102,21 +102,21 @@ fn skip_option() {
#[test]
fn nonexistent_struct() {
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Item1 {
f1: i8,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
pub struct Item2 {
f1: i64,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
struct Person1 {
f2: Item1,
f3: i8,
last: String,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
struct Person2 {
f2: Item2,
f3: i64,
@@ -142,7 +142,7 @@ fn nonexistent_struct() {
#[test]
fn option() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Animal {
f1: Option<String>,
f2: Option<String>,
@@ -176,7 +176,7 @@ fn nullable() {
f5: Option(None) -> Option(None)
f6: Option(None) -> value_default
*/
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Item1 {
f2: i8,
f3: Option<i8>,
@@ -186,7 +186,7 @@ fn nullable() {
last: i64,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Item2 {
f2: Option<i8>,
f3: i8,
@@ -222,7 +222,7 @@ fn nullable() {
#[test]
fn nullable_container() {
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Item1 {
f1: Vec<i8>,
f2: Option<Vec<i8>>,
@@ -236,7 +236,7 @@ fn nullable_container() {
last: i64,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Item2 {
f1: Option<Vec<i8>>,
f2: Vec<i8>,
@@ -285,7 +285,7 @@ fn nullable_container() {
#[test]
fn inner_nullable() {
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Item1 {
f1: Vec<Option<String>>,
f2: HashSet<Option<i8>>,
@@ -293,7 +293,7 @@ fn inner_nullable() {
last: i64,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Item2 {
f1: Vec<String>,
f2: HashSet<i8>,
@@ -322,14 +322,14 @@ fn inner_nullable() {
#[test]
fn nullable_struct() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
pub struct Item {
name: String,
data: Vec<Option<String>>,
last: i64,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Person1 {
f1: Item,
f2: Option<Item>,
@@ -337,7 +337,7 @@ fn nullable_struct() {
last: i64,
}
- #[derive(Fory, Debug)]
+ #[derive(ForyObject, Debug)]
pub struct Person2 {
f1: Option<Item>,
f2: Item,
@@ -376,7 +376,7 @@ fn nullable_struct() {
#[test]
fn enum_without_payload() {
- #[derive(Fory, Debug, PartialEq, Default)]
+ #[derive(ForyObject, Debug, PartialEq, Default)]
enum Color1 {
#[default]
Green,
@@ -384,14 +384,14 @@ fn enum_without_payload() {
Blue,
White,
}
- #[derive(Fory, Debug, PartialEq, Default)]
+ #[derive(ForyObject, Debug, PartialEq, Default)]
enum Color2 {
#[default]
Green,
Red,
Blue,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Person1 {
f1: Color1,
f2: Color1,
@@ -403,7 +403,7 @@ fn enum_without_payload() {
f8: Color1,
last: i8,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Person2 {
// same
f1: Color1,
@@ -450,7 +450,7 @@ fn enum_without_payload() {
#[test]
fn named_enum() {
- #[derive(Fory, Debug, PartialEq, Default)]
+ #[derive(ForyObject, Debug, PartialEq, Default)]
enum Color {
#[default]
Green,
@@ -458,7 +458,7 @@ fn named_enum() {
Blue,
White,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Item1 {
f1: Color,
f2: Color,
@@ -472,7 +472,7 @@ fn named_enum() {
f9: Option<Color>,
last: i8,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Item2 {
f1: Color,
f2: Option<Color>,
@@ -517,7 +517,7 @@ fn named_enum() {
#[test]
#[allow(clippy::unnecessary_literal_unwrap)]
fn boxed() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Item1 {
f1: i32,
f2: i32,
@@ -527,7 +527,7 @@ fn boxed() {
f6: Option<i32>,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Item2 {
f1: i32,
f2: Option<i32>,
diff --git a/rust/tests/tests/test_complex_struct.rs
b/rust/tests/tests/test_complex_struct.rs
index b5b21455c..58158c845 100644
--- a/rust/tests/tests/test_complex_struct.rs
+++ b/rust/tests/tests/test_complex_struct.rs
@@ -16,7 +16,7 @@
// under the License.
use fory_core::fory::Fory;
-use fory_derive::Fory;
+use fory_derive::ForyObject;
// use std::any::Any;
use chrono::{DateTime, NaiveDate, NaiveDateTime};
use std::collections::HashMap;
@@ -24,12 +24,12 @@ use std::collections::HashMap;
// RUSTFLAGS="-Awarnings" cargo expand -p fory-tests --test test_complex_struct
// #[test]
// fn any() {
-// #[derive(Fory, Debug)]
+// #[derive(ForyObject, Debug)]
// struct Animal {
// f3: String,
// }
//
-// #[derive(Fory, Debug)]
+// #[derive(ForyObject, Debug)]
// struct Person {
// f1: Box<dyn Any>,
// }
@@ -50,7 +50,7 @@ use std::collections::HashMap;
#[test]
fn enum_without_payload() {
- #[derive(Fory, Debug, PartialEq, Default)]
+ #[derive(ForyObject, Debug, PartialEq, Default)]
enum Color {
#[default]
Green,
@@ -67,12 +67,12 @@ fn enum_without_payload() {
#[test]
fn complex_struct() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Animal {
category: String,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Person {
// c1: Vec<u8>, // binary
c2: Vec<i16>, // primitive array
@@ -118,12 +118,12 @@ fn complex_struct() {
#[test]
fn encode_to_obin() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Animal {
category: String,
}
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Person {
f1: String,
f2: HashMap<String, i8>,
diff --git a/rust/tests/tests/test_cross_language.rs
b/rust/tests/tests/test_cross_language.rs
index 21daa199a..27bfe7995 100644
--- a/rust/tests/tests/test_cross_language.rs
+++ b/rust/tests/tests/test_cross_language.rs
@@ -22,7 +22,7 @@ use fory_core::meta::murmurhash3_x64_128;
use fory_core::resolver::context::{ReadContext, WriteContext};
use fory_core::serializer::Serializer;
use fory_core::types::Mode::Compatible;
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use std::collections::{HashMap, HashSet};
use std::fs;
@@ -31,7 +31,7 @@ fn get_data_file() -> String {
std::env::var("DATA_FILE").expect("DATA_FILE not set")
}
-#[derive(Fory, Debug, PartialEq, Default)]
+#[derive(ForyObject, Debug, PartialEq, Default)]
enum Color {
#[default]
Green,
@@ -40,12 +40,12 @@ enum Color {
White,
}
-#[derive(Fory, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct Item {
name: Option<String>,
}
-#[derive(Fory, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct SimpleStruct {
// field_order != sorted_order
f1: HashMap<i32, f64>,
@@ -532,7 +532,7 @@ fn test_map() {
#[test]
#[ignore]
fn test_integer() {
- #[derive(Fory, Debug, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Item2 {
f1: i32,
f2: Option<i32>,
diff --git a/rust/tests/tests/test_ext.rs b/rust/tests/tests/test_ext.rs
index b7cb20b45..fe68cfd4f 100644
--- a/rust/tests/tests/test_ext.rs
+++ b/rust/tests/tests/test_ext.rs
@@ -18,14 +18,14 @@
use fory_core::error::Error;
use fory_core::fory::Fory;
use fory_core::resolver::context::{ReadContext, WriteContext};
-use fory_core::serializer::Serializer;
+use fory_core::serializer::{ForyDefault, Serializer};
use fory_core::types::Mode::Compatible;
-use fory_derive::Fory;
+use fory_derive::ForyObject;
#[test]
#[allow(dead_code)]
fn test_duplicate_impl() {
- #[derive(Debug, Fory, PartialEq)]
+ #[derive(ForyObject, Debug, PartialEq)]
struct Item1 {
f1: i32,
}
@@ -47,11 +47,18 @@ fn test_duplicate_impl() {
#[test]
fn test_use() {
use fory_core::fory::{read, write};
- #[derive(Debug, PartialEq, Default)]
+ #[derive(Debug, PartialEq)]
struct Item {
f1: i32,
f2: i8,
}
+
+ impl ForyDefault for Item {
+ fn fory_default() -> Self {
+ Self { f1: 0, f2: 0 }
+ }
+ }
+
impl Serializer for Item {
fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
write(&self.f1, context, is_field);
diff --git a/rust/tests/tests/test_rc_arc_trait_object.rs
b/rust/tests/tests/test_rc_arc_trait_object.rs
index 118b83e20..7b0b538e5 100644
--- a/rust/tests/tests/test_rc_arc_trait_object.rs
+++ b/rust/tests/tests/test_rc_arc_trait_object.rs
@@ -20,7 +20,7 @@ use fory_core::register_trait_type;
use fory_core::serializer::Serializer;
use fory_core::types::Mode;
use fory_core::{unwrap_rc, wrap_rc, wrap_vec_rc};
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
@@ -34,7 +34,7 @@ trait Animal: Serializer + Send + Sync {
fn name(&self) -> &str;
}
-#[derive(Fory, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct Dog {
name: String,
breed: String,
@@ -50,7 +50,7 @@ impl Animal for Dog {
}
}
-#[derive(Fory, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct Cat {
name: String,
color: String,
@@ -298,7 +298,7 @@ fn test_empty_wrapper_collections() {
assert_eq!(deserialized.len(), 0);
}
-#[derive(Fory)]
+#[derive(ForyObject)]
struct AnimalShelter {
animals_rc: Vec<Rc<dyn Animal>>,
animals_arc: Vec<Arc<dyn Animal>>,
diff --git a/rust/tests/tests/test_trait_object.rs
b/rust/tests/tests/test_trait_object.rs
index 628055303..bc1e5a299 100644
--- a/rust/tests/tests/test_trait_object.rs
+++ b/rust/tests/tests/test_trait_object.rs
@@ -19,7 +19,7 @@ use fory_core::fory::Fory;
use fory_core::register_trait_type;
use fory_core::serializer::Serializer;
use fory_core::types::Mode;
-use fory_derive::Fory;
+use fory_derive::ForyObject;
use std::collections::{HashMap, HashSet};
fn fory_compatible() -> Fory {
@@ -149,13 +149,13 @@ fn test_hashmap_string_to_trait_objects() {
assert_eq!(deserialized.len(), 3);
}
-#[derive(Fory, Debug, PartialEq, Clone)]
+#[derive(ForyObject, Debug, PartialEq, Clone)]
struct Person {
name: String,
age: i32,
}
-#[derive(Fory, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct Company {
name: String,
employees: Vec<Person>,
@@ -248,7 +248,7 @@ trait Animal: Serializer {
fn name(&self) -> &str;
}
-#[derive(Fory, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct Dog {
name: String,
breed: String,
@@ -264,7 +264,7 @@ impl Animal for Dog {
}
}
-#[derive(Fory, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct Cat {
name: String,
color: String,
@@ -282,7 +282,7 @@ impl Animal for Cat {
register_trait_type!(Animal, Dog, Cat);
-#[derive(Fory)]
+#[derive(ForyObject)]
struct Zoo {
star_animal: Box<dyn Animal>,
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]