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 9811e018a docs(rust): add detailed rust api doc and readme (#2728)
9811e018a is described below
commit 9811e018adfad085f43b90945990038fd998de60
Author: Shawn Yang <[email protected]>
AuthorDate: Thu Oct 9 13:47:34 2025 +0800
docs(rust): add detailed rust api doc and readme (#2728)
## Why?
<!-- Describe the purpose of this PR. -->
## What does this PR do?
1. update rust api doc and readme
2. re-export core API
3. fix `Vec` with `Rc/Arc` trait
## Related issues
#2723
## 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 | 307 ++++----
rust/fory-core/src/lib.rs | 45 +-
rust/fory-core/src/serializer/mutex.rs | 4 +-
rust/fory-core/src/serializer/trait_object.rs | 19 +-
rust/fory-core/src/serializer/weak.rs | 31 +-
rust/fory-derive/src/object/misc.rs | 17 +-
rust/fory/src/lib.rs | 993 +++++++++++++++++++++++---
rust/tests/tests/test_complex_refs.rs | 30 +-
rust/tests/tests/test_mutex.rs | 18 +-
rust/tests/tests/test_rc_arc.rs | 128 ++--
rust/tests/tests/test_rc_arc_trait_object.rs | 1 -
rust/tests/tests/test_refcell.rs | 18 +-
rust/tests/tests/test_weak.rs | 60 +-
13 files changed, 1255 insertions(+), 416 deletions(-)
diff --git a/rust/README.md b/rust/README.md
index 51b78f838..8b2dbdc84 100644
--- a/rust/README.md
+++ b/rust/README.md
@@ -1,14 +1,14 @@
-# Apache Fury™ Rust
+# Apache Fory™ Rust
-[](https://crates.io/crates/fury)
-[](https://docs.rs/fury)
+[](https://crates.io/crates/fory)
+[](https://docs.rs/fory)
[](LICENSE)
-**Apache Fury™** is a blazing fast multi-language serialization framework
powered by **JIT compilation** and **zero-copy** techniques, providing up to
**ultra-fast performance** while maintaining ease of use and safety.
+**Apache Fory™** is a blazing fast multi-language serialization framework
powered by **JIT compilation** and **zero-copy** techniques, providing up to
**ultra-fast performance** while maintaining ease of use and safety.
The Rust implementation provides versatile and high-performance serialization
with automatic memory management and compile-time type safety.
-## 🚀 Why Apache Fury™ Rust?
+## 🚀 Why Apache Fory™ Rust?
- **🔥 Blazingly Fast**: Zero-copy deserialization and optimized binary
protocols
- **🌍 Cross-Language**: Seamlessly serialize/deserialize data across Java,
Python, C++, Go, JavaScript, and Rust
@@ -22,27 +22,26 @@ The Rust implementation provides versatile and
high-performance serialization wi
| Crate | Description | Version
|
| ----------------------------- | --------------------------------- |
-----------------------------------------------------------------------------------------------------
|
-| [`fury`](fury/) | High-level API with derive macros |
[](https://crates.io/crates/fury)
|
-| [`fury-core`](fury-core/) | Core serialization engine |
[](https://crates.io/crates/fury-core)
|
-| [`fury-derive`](fury-derive/) | Procedural macros |
[](https://crates.io/crates/fury-derive)
|
+| [`fory`](fory/) | High-level API with derive macros |
[](https://crates.io/crates/fory)
|
+| [`fory-core`](fory-core/) | Core serialization engine |
[](https://crates.io/crates/fory-core)
|
+| [`fory-derive`](fory-derive/) | Procedural macros |
[](https://crates.io/crates/fory-derive)
|
## 🏃 Quick Start
-Add Apache Fury™ to your `Cargo.toml`:
+Add Apache Fory™ to your `Cargo.toml`:
```toml
[dependencies]
-fury = "0.13"
-fury-derive = "0.13"
+fory = "0.13"
```
### Basic Example
```rust
-use fury::{Fury, Error};
-use fury_derive::FuryObject;
+use fory::{Fory, Error};
+use fory::ForyObject;
-#[derive(FuryObject, Debug, PartialEq)]
+#[derive(ForyObject, Debug, PartialEq)]
struct User {
name: String,
age: i32,
@@ -50,8 +49,8 @@ struct User {
}
fn main() -> Result<(), Error> {
- let mut fury = Fury::default();
- fury.register::<User>(1);
+ let mut fory = Fory::default();
+ fory.register::<User>(1);
let user = User {
name: "Alice".to_string(),
@@ -60,10 +59,10 @@ fn main() -> Result<(), Error> {
};
// Serialize
- let bytes = fury.serialize(&user);
+ let bytes = fory.serialize(&user);
// Deserialize
- let decoded: User = fury.deserialize(&bytes)?;
+ let decoded: User = fory.deserialize(&bytes)?;
assert_eq!(user, decoded);
Ok(())
@@ -74,7 +73,7 @@ fn main() -> Result<(), Error> {
### 1. Object Graph Serialization
-Apache Fury™ provides automatic serialization of complex object graphs,
preserving the structure and relationships between objects. The
`#[derive(FuryObject)]` macro generates efficient serialization code at compile
time, eliminating runtime overhead.
+Apache Fory™ provides automatic serialization of complex object graphs,
preserving the structure and relationships between objects. The
`#[derive(ForyObject)]` macro generates efficient serialization code at compile
time, eliminating runtime overhead.
**Key capabilities:**
@@ -85,11 +84,11 @@ Apache Fury™ provides automatic serialization of complex
object graphs, preser
- Efficient binary encoding with variable-length integers
```rust
-use fury::{Fury, Error};
-use fury_derive::FuryObject;
+use fory::{Fory, Error};
+use fory::ForyObject;
use std::collections::HashMap;
-#[derive(FuryObject, Debug, PartialEq, Default)]
+#[derive(ForyObject, Debug, PartialEq, Default)]
struct Person {
name: String,
age: i32,
@@ -98,16 +97,16 @@ struct Person {
metadata: HashMap<String, String>,
}
-#[derive(FuryObject, Debug, PartialEq, Default)]
+#[derive(ForyObject, Debug, PartialEq, Default)]
struct Address {
street: String,
city: String,
country: String,
}
-let mut fury = Fury::default();
-fury.register::<Address>(100);
-fury.register::<Person>(200);
+let mut fory = Fory::default();
+fory.register::<Address>(100);
+fory.register::<Person>(200);
let person = Person {
name: "John Doe".to_string(),
@@ -123,14 +122,14 @@ let person = Person {
]),
};
-let bytes = fury.serialize(&person);
-let decoded: Person = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&person);
+let decoded: Person = fory.deserialize(&bytes)?;
assert_eq!(person, decoded);
```
### 2. Shared and Circular References
-Apache Fury™ automatically tracks and preserves reference identity for shared
objects using `Rc<T>` and `Arc<T>`. When the same object is referenced multiple
times, Fury serializes it only once and uses reference IDs for subsequent
occurrences. This ensures:
+Apache Fory™ automatically tracks and preserves reference identity for shared
objects using `Rc<T>` and `Arc<T>`. When the same object is referenced multiple
times, Fory serializes it only once and uses reference IDs for subsequent
occurrences. This ensures:
- **Space efficiency**: No data duplication in serialized output
- **Reference identity preservation**: Deserialized objects maintain the same
sharing relationships
@@ -139,10 +138,10 @@ Apache Fury™ automatically tracks and preserves reference
identity for shared
#### Shared References with Rc/Arc
```rust
-use fury::Fury;
+use fory::Fory;
use std::rc::Rc;
-let fury = Fury::default();
+let fory = Fory::default();
// Create a shared value
let shared = Rc::new(String::from("shared_value"));
@@ -151,8 +150,8 @@ let shared = Rc::new(String::from("shared_value"));
let data = vec![shared.clone(), shared.clone(), shared.clone()];
// The shared value is serialized only once
-let bytes = fury.serialize(&data);
-let decoded: Vec<Rc<String>> = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&data);
+let decoded: Vec<Rc<String>> = fory.deserialize(&bytes)?;
// Verify reference identity is preserved
assert_eq!(decoded.len(), 3);
@@ -171,8 +170,8 @@ use std::sync::Arc;
let shared = Arc::new(String::from("shared_value"));
let data = vec![shared.clone(), shared.clone(), shared.clone()];
-let bytes = fury.serialize(&data);
-let decoded: Vec<Arc<String>> = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&data);
+let decoded: Vec<Arc<String>> = fory.deserialize(&bytes)?;
// Reference identity is preserved with Arc too
assert!(Arc::ptr_eq(&decoded[0], &decoded[1]));
@@ -190,21 +189,21 @@ To serialize circular references like parent-child
relationships or doubly-linke
- All clones of a weak pointer share the same internal cell for automatic
updates
```rust
-use fury::{Fury, Error};
-use fury_derive::FuryObject;
-use fury_core::serializer::weak::RcWeak;
+use fory::{Fory, Error};
+use fory::ForyObject;
+use fory::RcWeak;
use std::rc::Rc;
use std::cell::RefCell;
-#[derive(FuryObject, Debug)]
+#[derive(ForyObject, Debug)]
struct Node {
value: i32,
parent: RcWeak<RefCell<Node>>,
children: Vec<Rc<RefCell<Node>>>,
}
-let mut fury = Fury::default();
-fury.register::<Node>(2000);
+let mut fory = Fory::default();
+fory.register::<Node>(2000);
// Build a parent-child tree
let parent = Rc::new(RefCell::new(Node {
@@ -229,8 +228,8 @@ parent.borrow_mut().children.push(child1.clone());
parent.borrow_mut().children.push(child2.clone());
// Serialize and deserialize the circular structure
-let bytes = fury.serialize(&parent);
-let decoded: Rc<RefCell<Node>> = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&parent);
+let decoded: Rc<RefCell<Node>> = fory.deserialize(&bytes)?;
// Verify the circular relationship
assert_eq!(decoded.borrow().children.len(), 2);
@@ -243,20 +242,20 @@ for child in &decoded.borrow().children {
**Thread-Safe Circular Graphs with Arc:**
```rust
-use fury::{Fury, Error};
-use fury_derive::FuryObject;
-use fury_core::serializer::weak::ArcWeak;
+use fory::{Fory, Error};
+use fory::ForyObject;
+use fory::ArcWeak;
use std::sync::{Arc, Mutex};
-#[derive(FuryObject)]
+#[derive(ForyObject)]
struct Node {
val: i32,
parent: ArcWeak<Mutex<Node>>,
children: Vec<Arc<Mutex<Node>>>,
}
-let mut fury = Fury::default();
-fury.register::<Node>(6000);
+let mut fory = Fory::default();
+fory.register::<Node>(6000);
let parent = Arc::new(Mutex::new(Node {
val: 10,
@@ -279,8 +278,8 @@ let child2 = Arc::new(Mutex::new(Node {
parent.lock().unwrap().children.push(child1.clone());
parent.lock().unwrap().children.push(child2.clone());
-let bytes = fury.serialize(&parent);
-let decoded: Arc<Mutex<Node>> = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&parent);
+let decoded: Arc<Mutex<Node>> = fory.deserialize(&bytes)?;
assert_eq!(decoded.lock().unwrap().children.len(), 2);
for child in &decoded.lock().unwrap().children {
@@ -291,7 +290,7 @@ for child in &decoded.lock().unwrap().children {
### 3. Trait Object Serialization
-Apache Fury™ supports polymorphic serialization through trait objects,
enabling dynamic dispatch and type flexibility. This is essential for plugin
systems, heterogeneous collections, and extensible architectures.
+Apache Fory™ supports polymorphic serialization through trait objects,
enabling dynamic dispatch and type flexibility. This is essential for plugin
systems, heterogeneous collections, and extensible architectures.
**Supported trait object types:**
@@ -303,17 +302,17 @@ Apache Fury™ supports polymorphic serialization through
trait objects, enablin
#### Basic Trait Object Serialization
```rust
-use fury_core::{Fury, register_trait_type};
-use fury_core::serializer::Serializer;
-use fury_derive::FuryObject;
-use fury_core::types::Mode;
+use fory::{Fory, register_trait_type};
+use fory::Serializer;
+use fory::ForyObject;
+use fory::Mode;
trait Animal: Serializer {
fn speak(&self) -> String;
fn name(&self) -> &str;
}
-#[derive(FuryObject)]
+#[derive(ForyObject)]
struct Dog { name: String, breed: String }
impl Animal for Dog {
@@ -321,7 +320,7 @@ impl Animal for Dog {
fn name(&self) -> &str { &self.name }
}
-#[derive(FuryObject)]
+#[derive(ForyObject)]
struct Cat { name: String, color: String }
impl Animal for Cat {
@@ -332,15 +331,15 @@ impl Animal for Cat {
// Register trait implementations
register_trait_type!(Animal, Dog, Cat);
-#[derive(FuryObject)]
+#[derive(ForyObject)]
struct Zoo {
star_animal: Box<dyn Animal>,
}
-let mut fury = Fury::default().mode(Mode::Compatible);
-fury.register::<Dog>(100);
-fury.register::<Cat>(101);
-fury.register::<Zoo>(102);
+let mut fory = Fory::default().mode(Mode::Compatible);
+fory.register::<Dog>(100);
+fory.register::<Cat>(101);
+fory.register::<Zoo>(102);
let zoo = Zoo {
star_animal: Box::new(Dog {
@@ -349,8 +348,8 @@ let zoo = Zoo {
}),
};
-let bytes = fury.serialize(&zoo);
-let decoded: Zoo = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&zoo);
+let decoded: Zoo = fory.deserialize(&bytes)?;
assert_eq!(decoded.star_animal.name(), "Buddy");
assert_eq!(decoded.star_animal.speak(), "Woof!");
@@ -358,7 +357,7 @@ assert_eq!(decoded.star_animal.speak(), "Woof!");
#### Serializing `dyn Any` Trait Objects
-Apache Fury™ supports serializing `Rc<dyn Any>` and `Arc<dyn Any>` for runtime
type dispatch. This is useful when you need maximum flexibility and don't want
to define a custom trait.
+Apache Fory™ supports serializing `Rc<dyn Any>` and `Arc<dyn Any>` for runtime
type dispatch. This is useful when you need maximum flexibility and don't want
to define a custom trait.
**Key points:**
@@ -380,8 +379,8 @@ let dog_rc: Rc<dyn Animal> = Rc::new(Dog {
let dog_any: Rc<dyn Any> = dog_rc.clone();
// Serialize the Any wrapper
-let bytes = fury.serialize(&dog_any);
-let decoded: Rc<dyn Any> = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&dog_any);
+let decoded: Rc<dyn Any> = fory.deserialize(&bytes)?;
// Downcast back to the concrete type
let unwrapped = decoded.downcast_ref::<Dog>().unwrap();
@@ -402,8 +401,8 @@ let dog_arc: Arc<dyn Animal> = Arc::new(Dog {
// Convert to Arc<dyn Any>
let dog_any: Arc<dyn Any> = dog_arc.clone();
-let bytes = fury.serialize(&dog_any);
-let decoded: Arc<dyn Any> = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&dog_any);
+let decoded: Arc<dyn Any> = fory.deserialize(&bytes)?;
// Downcast to concrete type
let unwrapped = decoded.downcast_ref::<Dog>().unwrap();
@@ -412,24 +411,24 @@ assert_eq!(unwrapped.name, "Buddy");
#### Rc/Arc-Based Trait Objects in Structs
-For fields with `Rc<dyn Trait>` or `Arc<dyn Trait>`, Fury automatically
handles the conversion:
+For fields with `Rc<dyn Trait>` or `Arc<dyn Trait>`, Fory automatically
handles the conversion:
```rust
use std::sync::Arc;
use std::rc::Rc;
use std::collections::HashMap;
-#[derive(FuryObject)]
+#[derive(ForyObject)]
struct AnimalShelter {
animals_rc: Vec<Rc<dyn Animal>>,
animals_arc: Vec<Arc<dyn Animal>>,
registry: HashMap<String, Arc<dyn Animal>>,
}
-let mut fury = Fury::default().mode(Mode::Compatible);
-fury.register::<Dog>(100);
-fury.register::<Cat>(101);
-fury.register::<AnimalShelter>(102);
+let mut fory = Fory::default().mode(Mode::Compatible);
+fory.register::<Dog>(100);
+fory.register::<Cat>(101);
+fory.register::<AnimalShelter>(102);
let shelter = AnimalShelter {
animals_rc: vec![
@@ -447,8 +446,8 @@ let shelter = AnimalShelter {
]),
};
-let bytes = fury.serialize(&shelter);
-let decoded: AnimalShelter = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&shelter);
+let decoded: AnimalShelter = fory.deserialize(&bytes)?;
assert_eq!(decoded.animals_rc[0].name(), "Rex");
assert_eq!(decoded.animals_arc[0].speak(), "Woof!");
@@ -470,8 +469,8 @@ let dog_rc: Rc<dyn Animal> = Rc::new(Dog {
});
let wrapper = AnimalRc::from(dog_rc);
-let bytes = fury.serialize(&wrapper);
-let decoded: AnimalRc = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&wrapper);
+let decoded: AnimalRc = fory.deserialize(&bytes)?;
// Unwrap back to Rc<dyn Animal>
let unwrapped: Rc<dyn Animal> = decoded.unwrap();
@@ -484,8 +483,8 @@ let dog_arc: Arc<dyn Animal> = Arc::new(Dog {
});
let wrapper = AnimalArc::from(dog_arc);
-let bytes = fury.serialize(&wrapper);
-let decoded: AnimalArc = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&wrapper);
+let decoded: AnimalArc = fory.deserialize(&bytes)?;
let unwrapped: Arc<dyn Animal> = decoded.unwrap();
assert_eq!(unwrapped.name(), "Buddy");
@@ -493,7 +492,7 @@ assert_eq!(unwrapped.name(), "Buddy");
### 4. Schema Evolution
-Apache Fury™ supports schema evolution in **Compatible mode**, allowing
serialization and deserialization peers to have different type definitions.
This enables independent evolution of services in distributed systems without
breaking compatibility.
+Apache Fory™ supports schema evolution in **Compatible mode**, allowing
serialization and deserialization peers to have different type definitions.
This enables independent evolution of services in distributed systems without
breaking compatibility.
**Features:**
@@ -510,19 +509,19 @@ Apache Fury™ supports schema evolution in **Compatible
mode**, allowing serial
- Nested struct types must be registered on both sides
```rust
-use fury::Fury;
-use fury_core::types::Mode;
-use fury_derive::FuryObject;
+use fory::Fory;
+use fory::Mode;
+use fory::ForyObject;
use std::collections::HashMap;
-#[derive(FuryObject, Debug)]
+#[derive(ForyObject, Debug)]
struct PersonV1 {
name: String,
age: i32,
address: String,
}
-#[derive(FuryObject, Debug)]
+#[derive(ForyObject, Debug)]
struct PersonV2 {
name: String,
age: i32,
@@ -532,11 +531,11 @@ struct PersonV2 {
metadata: HashMap<String, String>,
}
-let mut fury1 = Fury::default().mode(Mode::Compatible);
-fury1.register::<PersonV1>(1);
+let mut fory1 = Fory::default().mode(Mode::Compatible);
+fory1.register::<PersonV1>(1);
-let mut fury2 = Fury::default().mode(Mode::Compatible);
-fury2.register::<PersonV2>(1);
+let mut fory2 = Fory::default().mode(Mode::Compatible);
+fory2.register::<PersonV2>(1);
let person_v1 = PersonV1 {
name: "Alice".to_string(),
@@ -545,10 +544,10 @@ let person_v1 = PersonV1 {
};
// Serialize with V1
-let bytes = fury1.serialize(&person_v1);
+let bytes = fory1.serialize(&person_v1);
// Deserialize with V2 - missing fields get default values
-let person_v2: PersonV2 = fury2.deserialize(&bytes)?;
+let person_v2: PersonV2 = fory2.deserialize(&bytes)?;
assert_eq!(person_v2.name, "Alice");
assert_eq!(person_v2.age, 30);
assert_eq!(person_v2.phone, None);
@@ -556,7 +555,7 @@ assert_eq!(person_v2.phone, None);
### 5. Enum Support
-Apache Fury™ supports enums without data payloads (C-style enums). Each
variant is assigned an ordinal value (0, 1, 2, ...) during serialization.
+Apache Fory™ supports enums without data payloads (C-style enums). Each
variant is assigned an ordinal value (0, 1, 2, ...) during serialization.
**Features:**
@@ -566,9 +565,9 @@ Apache Fury™ supports enums without data payloads (C-style
enums). Each varian
- Default variant support with `#[default]`
```rust
-use fury_derive::FuryObject;
+use fory::ForyObject;
-#[derive(FuryObject, Debug, PartialEq, Default)]
+#[derive(ForyObject, Debug, PartialEq, Default)]
enum Status {
#[default]
Pending,
@@ -577,18 +576,18 @@ enum Status {
Deleted,
}
-let mut fury = Fury::default();
-fury.register::<Status>(1);
+let mut fory = Fory::default();
+fory.register::<Status>(1);
let status = Status::Active;
-let bytes = fury.serialize(&status);
-let decoded: Status = fury.deserialize(&bytes)?;
+let bytes = fory.serialize(&status);
+let decoded: Status = fory.deserialize(&bytes)?;
assert_eq!(status, decoded);
```
### 6. Custom Serializers
-For types that don't support `#[derive(FuryObject)]`, implement the
`Serializer` trait manually. This is useful for:
+For types that don't support `#[derive(ForyObject)]`, implement the
`Serializer` trait manually. This is useful for:
- External types from other crates
- Types with special serialization requirements
@@ -596,30 +595,31 @@ For types that don't support `#[derive(FuryObject)]`,
implement the `Serializer`
- Performance-critical custom encoding
```rust
-use fury_core::fury::{Fury, read_data, write_data};
-use fury_core::resolver::context::{ReadContext, WriteContext};
-use fury_core::serializer::{Serializer, FuryDefault};
-use fury_core::error::Error;
+use fory::{Fory, ReadContext, WriteContext, Serializer, ForyDefault, Error};
use std::any::Any;
#[derive(Debug, PartialEq, Default)]
struct CustomType {
value: i32,
+ name: String,
}
impl Serializer for CustomType {
- fn fury_write_data(&self, context: &mut WriteContext, is_field: bool) {
- write_data(&self.value, context, is_field);
+ fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
+ context.writer.write_i32(self.value);
+ context.writer.write_varuint32(self.name.len() as u32);
+ context.writer.write_utf8_string(&self.name);
}
- fn fury_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
- Ok(Self {
- value: read_data(context, is_field)?,
- })
+ fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
+ let value = context.reader.read_i32();
+ let len = context.reader.read_varuint32() as usize;
+ let name = context.reader.read_utf8_string(len);
+ Ok(Self { value, name })
}
- fn fury_type_id_dyn(&self, fury: &Fury) -> u32 {
- Self::fury_get_type_id(fury)
+ fn fory_type_id_dyn(&self, fory: &Fory) -> u32 {
+ Self::fory_get_type_id(fory)
}
fn as_any(&self) -> &dyn Any {
@@ -627,24 +627,27 @@ impl Serializer for CustomType {
}
}
-impl FuryDefault for CustomType {
- fn fury_default() -> Self {
+impl ForyDefault for CustomType {
+ fn fory_default() -> Self {
Self::default()
}
}
-let mut fury = Fury::default();
-fury.register_serializer::<CustomType>(100);
+let mut fory = Fory::default();
+fory.register_serializer::<CustomType>(100);
-let custom = CustomType { value: 42 };
-let bytes = fury.serialize(&custom);
-let decoded: CustomType = fury.deserialize(&bytes)?;
+let custom = CustomType {
+ value: 42,
+ name: "test".to_string(),
+};
+let bytes = fory.serialize(&custom);
+let decoded: CustomType = fory.deserialize(&bytes)?;
assert_eq!(custom, decoded);
```
### 7. Row-Based Serialization
-Apache Fury™ provides a high-performance **row format** for zero-copy
deserialization. Unlike traditional object serialization that reconstructs
entire objects in memory, row format enables **random access** to fields
directly from binary data without full deserialization.
+Apache Fory™ provides a high-performance **row format** for zero-copy
deserialization. Unlike traditional object serialization that reconstructs
entire objects in memory, row format enables **random access** to fields
directly from binary data without full deserialization.
**Key benefits:**
@@ -670,11 +673,11 @@ Apache Fury™ provides a high-performance **row format**
for zero-copy deserial
- Nested structures supported through recursive row encoding
```rust
-use fury::{to_row, from_row};
-use fury_derive::FuryRow;
+use fory::{to_row, from_row};
+use fory::ForyRow;
use std::collections::BTreeMap;
-#[derive(FuryRow)]
+#[derive(ForyRow)]
struct UserProfile {
id: i64,
username: String,
@@ -773,34 +776,34 @@ assert_eq!(prefs.values().get(0), "en");
| Macro | Description |
| ----------------------- | -------------------------- |
-| `#[derive(FuryObject)]` | Object graph serialization |
-| `#[derive(FuryRow)]` | Row-based serialization |
+| `#[derive(ForyObject)]` | Object graph serialization |
+| `#[derive(ForyRow)]` | Row-based serialization |
## 🌍 Cross-Language Serialization
-Apache Fury™ supports seamless data exchange across multiple languages:
+Apache Fory™ supports seamless data exchange across multiple languages:
```rust
-use fury::Fury;
-use fury_core::types::Mode;
+use fory::Fory;
+use fory::Mode;
// Enable cross-language mode
-let mut fury = Fury::default()
+let mut fory = Fory::default()
.mode(Mode::Compatible)
.xlang(true);
// Register types with consistent IDs across languages
-fury.register::<MyStruct>(100);
+fory.register::<MyStruct>(100);
// Or use namespace-based registration
-fury.register_by_namespace::<MyStruct>("com.example", "MyStruct");
+fory.register_by_namespace::<MyStruct>("com.example", "MyStruct");
```
See [xlang_type_mapping.md](../docs/guide/xlang_type_mapping.md) for type
mapping across languages.
## ⚡ Performance
-Apache Fury™ Rust is designed for maximum performance:
+Apache Fory™ Rust is designed for maximum performance:
- **Zero-Copy Deserialization**: Row format enables direct memory access
without copying
- **Buffer Pre-allocation**: Minimizes memory allocations during serialization
@@ -812,12 +815,12 @@ Run benchmarks:
```bash
cd rust
-cargo bench --package fury-benchmarks
+cargo bench --package fory-benchmarks
```
## 📖 Documentation
-- **[API Documentation](https://docs.rs/fury)** - Complete API reference
+- **[API Documentation](https://docs.rs/fory)** - Complete API reference
- **[Protocol
Specification](../docs/specification/xlang_serialization_spec.md)** -
Serialization protocol details
- **[Row Format Specification](../docs/specification/row_format_spec.md)** -
Row format details
- **[Type Mapping](../docs/guide/xlang_type_mapping.md)** - Cross-language
type mappings
@@ -845,12 +848,12 @@ cargo bench --package fury-benchmarks
The Rust implementation consists of three main crates:
```
-fury/ # High-level API
+fory/ # High-level API
├── src/lib.rs # Public API exports
-fury-core/ # Core serialization engine
+fory-core/ # Core serialization engine
├── src/
-│ ├── fury.rs # Main serialization entry point
+│ ├── fory.rs # Main serialization entry point
│ ├── buffer.rs # Binary buffer management
│ ├── serializer/ # Type-specific serializers
│ ├── resolver/ # Type resolution and metadata
@@ -858,22 +861,22 @@ fury-core/ # Core serialization engine
│ ├── row/ # Row format implementation
│ └── types.rs # Type definitions
-fury-derive/ # Procedural macros
+fory-derive/ # Procedural macros
├── src/
-│ ├── object/ # FuryObject macro
-│ └── fury_row.rs # FuryRow macro
+│ ├── object/ # ForyObject macro
+│ └── fory_row.rs # ForyRow macro
```
## 🔄 Serialization Modes
-Apache Fury™ supports two serialization modes:
+Apache Fory™ supports two serialization modes:
### SchemaConsistent Mode (Default)
Type declarations must match exactly between peers:
```rust
-let fury = Fury::default(); // SchemaConsistent by default
+let fory = Fory::default(); // SchemaConsistent by default
```
### Compatible Mode
@@ -881,9 +884,9 @@ let fury = Fury::default(); // SchemaConsistent by default
Allows independent schema evolution:
```rust
-use fury_core::types::Mode;
+use fory::Mode;
-let fury = Fury::default().mode(Mode::Compatible);
+let fory = Fory::default().mode(Mode::Compatible);
```
## 🛠️ Development
@@ -902,7 +905,7 @@ cargo build
cargo test --features tests
# Run specific test
-cargo test -p fury-tests --test test_complex_struct
+cargo test -p fory-tests --test test_complex_struct
```
### Code Quality
@@ -941,11 +944,11 @@ We welcome contributions! Please see our [Contributing
Guide](../CONTRIBUTING.md
## 📞 Support
-- **Documentation**: [docs.rs/fury](https://docs.rs/fury)
-- **Issues**: [GitHub Issues](https://github.com/apache/fury/issues)
-- **Discussions**: [GitHub
Discussions](https://github.com/apache/fury/discussions)
-- **Slack**: [Apache Fury
Slack](https://join.slack.com/t/fury-project/shared_invite/zt-1u8soj4qc-ieYEu7ciHOqA2mo47llS8A)
+- **Documentation**: [docs.rs/fory](https://docs.rs/fory)
+- **Issues**: [GitHub Issues](https://github.com/apache/fory/issues)
+- **Discussions**: [GitHub
Discussions](https://github.com/apache/fory/discussions)
+- **Slack**: [Apache Fory
Slack](https://join.slack.com/t/fory-project/shared_invite/zt-1u8soj4qc-ieYEu7ciHOqA2mo47llS8A)
---
-**Apache Fury™** - Blazingly fast multi-language serialization framework.
+**Apache Fory™** - Blazingly fast multi-language serialization framework.
diff --git a/rust/fory-core/src/lib.rs b/rust/fory-core/src/lib.rs
index d3049f604..e25ee4ba6 100644
--- a/rust/fory-core/src/lib.rs
+++ b/rust/fory-core/src/lib.rs
@@ -69,41 +69,61 @@
//!
//! Define custom traits and register implementations:
//!
-//! ```ignore
-//! trait Animal {
+//! ```rust,ignore
+//! use fory_core::{Fory, register_trait_type, Serializer, Mode};
+//! use fory_derive::ForyObject;
+//!
+//! trait Animal: Serializer {
//! fn speak(&self) -> String;
//! }
//!
-//! #[derive(ForyObject)]
+//! #[derive(ForyObject, Debug)]
//! struct Dog { name: String }
//!
-//! #[derive(ForyObject)]
+//! #[derive(ForyObject, Debug)]
//! struct Cat { name: String }
//!
//! impl Animal for Dog {
//! fn speak(&self) -> String { "Woof!".to_string() }
-//! fn as_any(&self) -> &dyn std::any::Any { self }
//! }
//!
//! impl Animal for Cat {
//! fn speak(&self) -> String { "Meow!".to_string() }
-//! fn as_any(&self) -> &dyn std::any::Any { self }
//! }
//!
//! register_trait_type!(Animal, Dog, Cat);
//!
-//! // Use in struct fields
//! #[derive(ForyObject)]
//! struct Zoo {
//! star_animal: Box<dyn Animal>,
//! }
+//!
+//! # fn main() {
+//! let mut fory = Fory::default().mode(Mode::Compatible);
+//! fory.register::<Dog>(100);
+//! fory.register::<Cat>(101);
+//! fory.register::<Zoo>(102);
+//!
+//! let zoo = Zoo {
+//! star_animal: Box::new(Dog { name: "Buddy".to_string() }),
+//! };
+//!
+//! let bytes = fory.serialize(&zoo);
+//! let decoded: Zoo = fory.deserialize(&bytes).unwrap();
+//! assert_eq!(decoded.star_animal.speak(), "Woof!");
+//! # }
//! ```
//!
//! #### Rc/Arc-Based Trait Objects
//!
//! For reference-counted trait objects, use them directly in struct fields:
//!
-//! ```ignore
+//! ```rust,ignore
+//! # use fory_core::Serializer;
+//! # use fory_derive::ForyObject;
+//! # use std::rc::Rc;
+//! # use std::sync::Arc;
+//! # trait Animal: Serializer { fn speak(&self) -> String; }
//! #[derive(ForyObject)]
//! struct Shelter {
//! animals_rc: Vec<Rc<dyn Animal>>,
@@ -121,7 +141,9 @@
//! you can use the core types directly for advanced use cases.
//!
//! ```rust
-//! use fory_core::{fory::Fory, error::Error, types::Mode};
+//! use fory_core::fory::Fory;
+//! use fory_core::error::Error;
+//! use fory_core::types::Mode;
//! use fory_core::row::{to_row, from_row};
//!
//! // Create a Fory instance
@@ -148,4 +170,9 @@ pub mod util;
// Re-export paste for use in macros
pub use paste;
+pub use crate::buffer::{Reader, Writer};
+pub use crate::fory::Fory;
+pub use crate::resolver::context::{ReadContext, WriteContext};
+pub use crate::resolver::type_resolver::TypeResolver;
pub use crate::serializer::weak::{ArcWeak, RcWeak};
+pub use crate::serializer::{ForyDefault, Serializer};
diff --git a/rust/fory-core/src/serializer/mutex.rs
b/rust/fory-core/src/serializer/mutex.rs
index 5879625b6..b7d8c540e 100644
--- a/rust/fory-core/src/serializer/mutex.rs
+++ b/rust/fory-core/src/serializer/mutex.rs
@@ -20,7 +20,7 @@
//! This module implements [`Serializer`] and [`ForyDefault`] for
[`std::sync::Mutex<T>`].
//! It allows thread-safe mutable containers to be part of serialized graphs.
//!
-//! Unlike [`Rc`] and [`Arc`], `Mutex` does not do reference counting, so this
wrapper relies
+//! Unlike [`std::rc::Rc`] and [`std::sync::Arc`], `Mutex` does not do
reference counting, so this wrapper relies
//! on the serialization of the contained `T` only.
//!
//! This is commonly used together with `Arc<Mutex<T>>` in threaded graph
structures.
@@ -28,7 +28,7 @@
//! # Example
//! ```rust
//! use std::sync::Mutex;
-//! use fory_core::serializer::{Serializer, ForyDefault};
+//! use fory_core::{Serializer, ForyDefault};
//!
//! let mutex = Mutex::new(42);
//! // Can be serialized by the Fory framework
diff --git a/rust/fory-core/src/serializer/trait_object.rs
b/rust/fory-core/src/serializer/trait_object.rs
index 96533e1ff..ba454b3ff 100644
--- a/rust/fory-core/src/serializer/trait_object.rs
+++ b/rust/fory-core/src/serializer/trait_object.rs
@@ -120,8 +120,7 @@ macro_rules! resolve_and_deserialize {
/// # Example
///
/// ```rust,ignore
-/// use fory_core::register_trait_type;
-/// use fory_core::serializer::Serializer;
+/// use fory_core::{fory::Fory, register_trait_type, serializer::Serializer,
types::Mode};
/// use fory_derive::ForyObject;
///
/// trait Animal: Serializer {
@@ -129,10 +128,10 @@ macro_rules! resolve_and_deserialize {
/// fn name(&self) -> &str;
/// }
///
-/// #[derive(ForyObject)]
+/// #[derive(ForyObject, Debug)]
/// struct Dog { name: String }
///
-/// #[derive(ForyObject)]
+/// #[derive(ForyObject, Debug)]
/// struct Cat { name: String }
///
/// impl Animal for Dog {
@@ -145,8 +144,18 @@ macro_rules! resolve_and_deserialize {
/// fn name(&self) -> &str { &self.name }
/// }
///
-/// // Register the trait and its implementations
/// register_trait_type!(Animal, Dog, Cat);
+///
+/// # fn main() {
+/// let mut fory = Fory::default().mode(Mode::Compatible);
+/// fory.register::<Dog>(100);
+/// fory.register::<Cat>(101);
+///
+/// let dog: Box<dyn Animal> = Box::new(Dog { name: "Rex".to_string() });
+/// let bytes = fory.serialize(&dog);
+/// let decoded: Box<dyn Animal> = fory.deserialize(&bytes).unwrap();
+/// assert_eq!(decoded.name(), "Rex");
+/// # }
/// ```
#[macro_export]
macro_rules! register_trait_type {
diff --git a/rust/fory-core/src/serializer/weak.rs
b/rust/fory-core/src/serializer/weak.rs
index a78915f8c..10b5099d4 100644
--- a/rust/fory-core/src/serializer/weak.rs
+++ b/rust/fory-core/src/serializer/weak.rs
@@ -41,18 +41,21 @@
//!
//! ```rust,ignore
//! use fory_core::RcWeak;
+//! use fory_core::Fory;
//! use std::cell::RefCell;
//! use std::rc::Rc;
//! use fory_derive::ForyObject;
//!
-//! // #[derive(ForyObject)]
+//! #[derive(ForyObject)]
//! struct Node {
//! value: i32,
//! parent: RcWeak<RefCell<Node>>,
//! children: Vec<Rc<RefCell<Node>>>,
//! }
//!
-//! // Build a parent with two children
+//! let mut fory = Fory::default();
+//! fory.register::<Node>(2000);
+//!
//! let parent = Rc::new(RefCell::new(Node {
//! value: 1,
//! parent: RcWeak::new(),
@@ -74,12 +77,8 @@
//! parent.borrow_mut().children.push(child1);
//! parent.borrow_mut().children.push(child2);
//!
-//! // Serialize & deserialize while preserving reference identity
-//! let mut fury = fory_core::fory::Fory::default();
-//! fury.register::<Node>(2000);
-//!
-//! let serialized = fury.serialize(&parent);
-//! let deserialized: Rc<RefCell<Node>> =
fury.deserialize(&serialized).unwrap();
+//! let serialized = fory.serialize(&parent);
+//! let deserialized: Rc<RefCell<Node>> =
fory.deserialize(&serialized).unwrap();
//!
//! assert_eq!(deserialized.borrow().children.len(), 2);
//! for child in &deserialized.borrow().children {
@@ -91,23 +90,25 @@
//! ## Example — Arc for Multi-Threaded Graphs
//!
//! ```rust,ignore
-//! use fory_core::serializer::weak::ArcWeak;
+//! use fory_core::ArcWeak;
+//! use fory_core::Fory;
//! use std::sync::{Arc, Mutex};
+//! use fory_derive::ForyObject;
//!
-//! #[derive(fory_derive::ForyObject)]
+//! #[derive(ForyObject)]
//! struct Node {
//! value: i32,
//! parent: ArcWeak<Mutex<Node>>,
//! }
//!
+//! let mut fory = Fory::default();
+//! fory.register::<Node>(2001);
+//!
//! let parent = Arc::new(Mutex::new(Node { value: 1, parent: ArcWeak::new()
}));
//! let child = Arc::new(Mutex::new(Node { value: 2, parent:
ArcWeak::from(&parent) }));
//!
-//! let mut fury = fory_core::fory::Fory::default();
-//! fury.register::<Node>(2001);
-//!
-//! let serialized = fury.serialize(&child);
-//! let deserialized: Arc<Mutex<Node>> =
fury.deserialize(&serialized).unwrap();
+//! let serialized = fory.serialize(&child);
+//! let deserialized: Arc<Mutex<Node>> =
fory.deserialize(&serialized).unwrap();
//! assert_eq!(deserialized.lock().unwrap().value, 2);
//! ```
//!
diff --git a/rust/fory-derive/src/object/misc.rs
b/rust/fory-derive/src/object/misc.rs
index ab519ec0f..ec05f0f4c 100644
--- a/rust/fory-derive/src/object/misc.rs
+++ b/rust/fory-derive/src/object/misc.rs
@@ -95,15 +95,26 @@ pub fn gen_type_def(fields: &[&Field]) -> TokenStream {
quote! {
fory_core::meta::FieldInfo::new(#name,
fory_core::meta::FieldType {
type_id: fory_core::types::TypeId::LIST as u32,
- generics: Vec::new()
+ generics: vec![fory_core::meta::FieldType {
+ type_id: fory_core::types::TypeId::UNKNOWN as u32,
+ generics: Vec::new()
+ }]
})
}
}
- StructField::HashMapRc(..) | StructField::HashMapArc(..) => {
+ StructField::HashMapRc(key_ty, _) |
StructField::HashMapArc(key_ty, _) => {
+ let key_generic_tree = parse_generic_tree(key_ty.as_ref());
+ let key_generic_token =
generic_tree_to_tokens(&key_generic_tree, false);
quote! {
fory_core::meta::FieldInfo::new(#name,
fory_core::meta::FieldType {
type_id: fory_core::types::TypeId::MAP as u32,
- generics: Vec::new()
+ generics: vec![
+ #key_generic_token,
+ fory_core::meta::FieldType {
+ type_id: fory_core::types::TypeId::UNKNOWN as
u32,
+ generics: Vec::new()
+ }
+ ]
})
}
}
diff --git a/rust/fory/src/lib.rs b/rust/fory/src/lib.rs
index ce9aea579..faaae0d26 100644
--- a/rust/fory/src/lib.rs
+++ b/rust/fory/src/lib.rs
@@ -15,35 +15,105 @@
// specific language governing permissions and limitations
// under the License.
-//! # Fory
+//! # Apache Fory™ Rust
//!
-//! Fory is a blazingly fast multi-language serialization framework powered by
-//! just-in-time compilation and zero-copy techniques. It provides two main
-//! serialization approaches: object serialization for complex data structures
-//! and row-based serialization for high-performance scenarios.
+//! **Apache Fory™** is a blazingly fast multi-language serialization
framework powered by
+//! **JIT compilation** and **zero-copy** techniques, providing up to
ultra-fast performance
+//! while maintaining ease of use and safety.
//!
-//! ## Key Features
+//! The Rust implementation provides versatile and high-performance
serialization with
+//! automatic memory management and compile-time type safety.
//!
-//! - **High Performance**: Optimized for speed with zero-copy deserialization
-//! - **Cross-Language**: Designed for multi-language environments
-//! - **Two Serialization Modes**: Object serialization and row-based
serialization
-//! - **Type Safety**: Compile-time type checking with derive macros
-//! - **Schema Evolution**: Support for compatible mode with field
additions/deletions
+//! **GitHub**: <https://github.com/apache/fory>
//!
-//! ## Serialization Modes
+//! ## Why Apache Fory™ Rust?
+//!
+//! Apache Fory™ Rust solves the fundamental serialization dilemma: **you
shouldn't have to
+//! choose between performance and developer experience**. Traditional
frameworks force you
+//! to pick between fast but fragile binary formats, flexible but slow
text-based protocols,
+//! or complex solutions that don't support your language's advanced features.
+//!
+//! **Key differentiators:**
+//!
+//! - **🔥 Blazingly Fast**: Zero-copy deserialization and optimized binary
protocols
+//! - **🌍 Cross-Language**: Seamlessly serialize/deserialize data across Java,
Python, C++, Go, JavaScript, and Rust
+//! - **🎯 Type-Safe**: Compile-time type checking with derive macros
+//! - **🔄 Circular References**: Automatic tracking of shared and circular
references with `Rc`/`Arc` and weak pointers
+//! - **🧬 Polymorphic**: Serialize trait objects with `Box<dyn Trait>`,
`Rc<dyn Trait>`, and `Arc<dyn Trait>`
+//! - **📦 Schema Evolution**: Compatible mode for independent schema changes
+//! - **⚡ Two Modes**: Object graph serialization and zero-copy row-based
format
+//!
+//! ## Quick Start
+//!
+//! Add Apache Fory™ to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! fory = "0.13"
+//! fory-derive = "0.13"
+//! ```
+//!
+//! ### Basic Example
+//!
+//! ```rust
+//! use fory::{Fory, Error};
+//! use fory::ForyObject;
+//!
+//! #[derive(ForyObject, Debug, PartialEq)]
+//! struct User {
+//! name: String,
+//! age: i32,
+//! email: String,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default();
+//! fory.register::<User>(1);
//!
-//! Fory provides two distinct serialization approaches:
+//! let user = User {
+//! name: "Alice".to_string(),
+//! age: 30,
+//! email: "[email protected]".to_string(),
+//! };
+//!
+//! let bytes = fory.serialize(&user);
+//! let decoded: User = fory.deserialize(&bytes)?;
+//! assert_eq!(user, decoded);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ## Core Features
+//!
+//! Apache Fory™ Rust provides seven major feature categories, each designed
to solve
+//! specific serialization challenges in modern applications.
+//!
+//! ### 1. Object Graph Serialization
+//!
+//! **What it does:** Automatically serializes complex nested data structures
while
+//! preserving relationships and hierarchies.
+//!
+//! **Why it matters:** Most real-world applications deal with complex domain
models,
+//! not just flat data structures. Apache Fory™ handles arbitrary nesting
depth,
+//! collections, and optional fields without manual mapping code.
//!
-//! ### 1. Object Serialization
+//! **Technical approach:** The `#[derive(ForyObject)]` macro generates
efficient
+//! serialization code at compile time using procedural macros. This
eliminates runtime
+//! reflection overhead while maintaining type safety.
//!
-//! Object serialization is designed for complex data structures and provides
-//! full object graph serialization with reference handling. This mode is
-//! ideal for general-purpose serialization needs.
+//! **Key capabilities:**
+//!
+//! - Nested struct serialization with arbitrary depth
+//! - Collection types (`Vec`, `HashMap`, `HashSet`, `BTreeMap`)
+//! - Optional fields with `Option<T>`
+//! - Automatic handling of primitive types and strings
+//! - Efficient binary encoding with variable-length integers
//!
//! ```rust
//! use fory::{Fory, Error};
-//! use fory_derive::ForyObject;
+//! use fory::ForyObject;
//! use std::collections::HashMap;
+//!
//! #[derive(ForyObject, Debug, PartialEq)]
//! struct Person {
//! name: String,
@@ -61,6 +131,10 @@
//! }
//!
//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default();
+//! fory.register::<Address>(100);
+//! fory.register::<Person>(200);
+//!
//! let person = Person {
//! name: "John Doe".to_string(),
//! age: 30,
@@ -71,32 +145,660 @@
//! },
//! hobbies: vec!["reading".to_string(), "coding".to_string()],
//! metadata: HashMap::from([
-//! ("department".to_string(), "engineering".to_string()),
-//! ("level".to_string(), "senior".to_string()),
+//! ("role".to_string(), "developer".to_string()),
//! ]),
//! };
//!
-//! // Create a Fory instance and register types
+//! let bytes = fory.serialize(&person);
+//! let decoded: Person = fory.deserialize(&bytes)?;
+//! assert_eq!(person, decoded);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ### 2. Shared and Circular References
+//!
+//! **What it does:** Automatically tracks and preserves reference identity
for shared
+//! objects using `Rc<T>` and `Arc<T>`, and handles circular references using
weak pointers.
+//!
+//! **Why it matters:** Graph-like data structures (trees, linked lists,
object-relational
+//! models) are common in real applications but notoriously difficult to
serialize. Most
+//! frameworks either panic on circular references or require extensive manual
handling.
+//!
+//! **Technical approach:** Apache Fory™ maintains a reference tracking map
during
+//! serialization. When the same object is encountered multiple times, it's
serialized
+//! only once and subsequent references use IDs. Weak pointers (`RcWeak<T>`,
`ArcWeak<T>`)
+//! break cycles by serializing as references without strong ownership.
+//!
+//! **Benefits:**
+//!
+//! - **Space efficiency**: No data duplication in serialized output
+//! - **Reference identity preservation**: Deserialized objects maintain the
same sharing relationships
+//! - **Circular reference support**: Use `RcWeak<T>` and `ArcWeak<T>` to
break cycles
+//! - **Forward reference resolution**: Callbacks handle weak pointers
appearing before targets
+//!
+//! #### Shared References with Rc/Arc
+//!
+//! ```rust
+//! use fory::Fory;
+//! use fory::Error;
+//! use std::rc::Rc;
+//!
+//! # fn main() -> Result<(), Error> {
+//! let fory = Fory::default();
+//!
+//! let shared = Rc::new(String::from("shared_value"));
+//! let data = vec![shared.clone(), shared.clone(), shared.clone()];
+//!
+//! let bytes = fory.serialize(&data);
+//! let decoded: Vec<Rc<String>> = fory.deserialize(&bytes)?;
+//!
+//! assert_eq!(decoded.len(), 3);
+//! assert!(Rc::ptr_eq(&decoded[0], &decoded[1]));
+//! assert!(Rc::ptr_eq(&decoded[1], &decoded[2]));
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! For thread-safe shared references, use `Arc<T>`:
+//!
+//! ```rust
+//! use fory::Fory;
+//! use fory::Error;
+//! use std::sync::Arc;
+//!
+//! # fn main() -> Result<(), Error> {
+//! let fory = Fory::default();
+//! let shared = Arc::new(String::from("shared_value"));
+//! let data = vec![shared.clone(), shared.clone()];
+//!
+//! let bytes = fory.serialize(&data);
+//! let decoded: Vec<Arc<String>> = fory.deserialize(&bytes)?;
+//!
+//! assert!(Arc::ptr_eq(&decoded[0], &decoded[1]));
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! #### Circular References with Weak Pointers
+//!
+//! **How it works:**
+//!
+//! - Weak pointers serialize as references to their target objects
+//! - If the strong pointer has been dropped, weak serializes as `Null`
+//! - Forward references (weak appearing before target) are resolved via
callbacks
+//! - All clones of a weak pointer share the same internal cell for automatic
updates
+//!
+//! ```rust
+//! use fory::{Fory, Error, RcWeak};
+//! use fory::ForyObject;
+//! use std::rc::Rc;
+//! use std::cell::RefCell;
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct Node {
+//! value: i32,
+//! parent: RcWeak<RefCell<Node>>,
+//! children: Vec<Rc<RefCell<Node>>>,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
//! let mut fory = Fory::default();
-//! fory.register::<Address>(100);
-//! fory.register::<Person>(200);
+//! fory.register::<Node>(2000);
//!
-//! // Serialize the object
-//! let serialized = fory.serialize(&person);
+//! let parent = Rc::new(RefCell::new(Node {
+//! value: 1,
+//! parent: RcWeak::new(),
+//! children: vec![],
+//! }));
//!
-//! // Deserialize back to the original type
-//! let deserialized: Person = fory.deserialize(&serialized)?;
+//! let child1 = Rc::new(RefCell::new(Node {
+//! value: 2,
+//! parent: RcWeak::from(&parent),
+//! children: vec![],
+//! }));
//!
-//! assert_eq!(person, deserialized);
+//! parent.borrow_mut().children.push(child1.clone());
+//!
+//! let bytes = fory.serialize(&parent);
+//! let decoded: Rc<RefCell<Node>> = fory.deserialize(&bytes)?;
+//!
+//! assert_eq!(decoded.borrow().children.len(), 1);
+//! let upgraded_parent =
decoded.borrow().children[0].borrow().parent.upgrade().unwrap();
+//! assert!(Rc::ptr_eq(&decoded, &upgraded_parent));
//! # Ok(())
//! # }
//! ```
//!
-//! ### 2. Row-Based Serialization
+//! **Thread-Safe Circular Graphs with Arc:**
//!
-//! Row-based serialization provides zero-copy deserialization for maximum
-//! performance. This mode is ideal for high-throughput scenarios where you
-//! need to process large amounts of data efficiently.
+//! ```rust
+//! use fory::{Fory, Error, ArcWeak};
+//! use fory::ForyObject;
+//! use std::sync::{Arc, Mutex};
+//!
+//! #[derive(ForyObject)]
+//! struct Node {
+//! val: i32,
+//! parent: ArcWeak<Mutex<Node>>,
+//! children: Vec<Arc<Mutex<Node>>>,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default();
+//! fory.register::<Node>(6000);
+//!
+//! let parent = Arc::new(Mutex::new(Node {
+//! val: 10,
+//! parent: ArcWeak::new(),
+//! children: vec![],
+//! }));
+//!
+//! let child = Arc::new(Mutex::new(Node {
+//! val: 20,
+//! parent: ArcWeak::from(&parent),
+//! children: vec![],
+//! }));
+//!
+//! parent.lock().unwrap().children.push(child.clone());
+//!
+//! let bytes = fory.serialize(&parent);
+//! let decoded: Arc<Mutex<Node>> = fory.deserialize(&bytes)?;
+//!
+//! assert_eq!(decoded.lock().unwrap().children.len(), 1);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ### 3. Trait Object Serialization
+//!
+//! **What it does:** Enables polymorphic serialization through trait objects,
supporting
+//! dynamic dispatch and type flexibility.
+//!
+//! **Why it matters:** Rust's trait system is powerful for abstraction, but
serializing
+//! `Box<dyn Trait>` is notoriously difficult. This feature is essential for
plugin systems,
+//! heterogeneous collections, and extensible architectures.
+//!
+//! **Technical approach:** The `register_trait_type!` macro generates type
registration
+//! and dispatch code for trait implementations. During serialization, type
IDs are written
+//! alongside data, enabling correct deserialization to the concrete type.
+//!
+//! **Supported trait object types:**
+//!
+//! - `Box<dyn Trait>` - Owned trait objects
+//! - `Rc<dyn Trait>` - Reference-counted trait objects
+//! - `Arc<dyn Trait>` - Thread-safe reference-counted trait objects
+//! - `Rc<dyn Any>` / `Arc<dyn Any>` - Runtime type dispatch without custom
traits
+//! - Collections: `Vec<Box<dyn Trait>>`, `HashMap<K, Box<dyn Trait>>`
+//!
+//! #### Basic Trait Object Serialization
+//!
+//! ```rust
+//! use fory::{Fory, register_trait_type, Serializer, Mode, Error};
+//! use fory::ForyObject;
+//!
+//! trait Animal: Serializer {
+//! fn speak(&self) -> String;
+//! fn name(&self) -> &str;
+//! }
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct Dog { name: String, breed: String }
+//!
+//! impl Animal for Dog {
+//! fn speak(&self) -> String { "Woof!".to_string() }
+//! fn name(&self) -> &str { &self.name }
+//! }
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct Cat { name: String, color: String }
+//!
+//! impl Animal for Cat {
+//! fn speak(&self) -> String { "Meow!".to_string() }
+//! fn name(&self) -> &str { &self.name }
+//! }
+//!
+//! register_trait_type!(Animal, Dog, Cat);
+//!
+//! #[derive(ForyObject)]
+//! struct Zoo {
+//! star_animal: Box<dyn Animal>,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default().mode(Mode::Compatible);
+//! fory.register::<Dog>(100);
+//! fory.register::<Cat>(101);
+//! fory.register::<Zoo>(102);
+//!
+//! let zoo = Zoo {
+//! star_animal: Box::new(Dog {
+//! name: "Buddy".to_string(),
+//! breed: "Labrador".to_string(),
+//! }),
+//! };
+//!
+//! let bytes = fory.serialize(&zoo);
+//! let decoded: Zoo = fory.deserialize(&bytes)?;
+//!
+//! assert_eq!(decoded.star_animal.name(), "Buddy");
+//! assert_eq!(decoded.star_animal.speak(), "Woof!");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! #### Serializing `dyn Any` Trait Objects
+//!
+//! **What it does:** Supports serializing `Rc<dyn Any>` and `Arc<dyn Any>`
for maximum
+//! runtime type flexibility without defining custom traits.
+//!
+//! **When to use:** Plugin systems, dynamic type handling, or when you need
runtime type
+//! dispatch without compile-time trait definitions.
+//!
+//! **Key points:**
+//!
+//! - Works with any type that implements `Serializer`
+//! - Requires downcasting after deserialization to access the concrete type
+//! - Type information is preserved during serialization
+//!
+//! ```rust
+//! use fory::Fory;
+//! use fory::Error;
+//! use std::rc::Rc;
+//! use std::any::Any;
+//! use fory::ForyObject;
+//!
+//! #[derive(ForyObject)]
+//! struct Dog { name: String }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default();
+//! fory.register::<Dog>(100);
+//!
+//! let dog: Rc<dyn Any> = Rc::new(Dog {
+//! name: "Rex".to_string()
+//! });
+//!
+//! let bytes = fory.serialize(&dog);
+//! let decoded: Rc<dyn Any> = fory.deserialize(&bytes)?;
+//!
+//! let unwrapped = decoded.downcast_ref::<Dog>().unwrap();
+//! assert_eq!(unwrapped.name, "Rex");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! For thread-safe scenarios, use `Arc<dyn Any>`:
+//!
+//! ```rust
+//! use fory::Fory;
+//! use fory::Error;
+//! use std::sync::Arc;
+//! use std::any::Any;
+//! use fory::ForyObject;
+//!
+//! #[derive(ForyObject)]
+//! struct Cat { name: String }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default();
+//! fory.register::<Cat>(101);
+//!
+//! let cat: Arc<dyn Any> = Arc::new(Cat {
+//! name: "Whiskers".to_string()
+//! });
+//!
+//! let bytes = fory.serialize(&cat);
+//! let decoded: Arc<dyn Any> = fory.deserialize(&bytes)?;
+//!
+//! let unwrapped = decoded.downcast_ref::<Cat>().unwrap();
+//! assert_eq!(unwrapped.name, "Whiskers");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! #### Rc/Arc-Based Trait Objects in Structs
+//!
+//! For struct fields containing `Rc<dyn Trait>` or `Arc<dyn Trait>`, Apache
Fory™
+//! automatically handles the conversion without needing wrappers:
+//!
+//! ```rust
+//! use fory::{Fory, register_trait_type, Serializer, Mode, Error};
+//! use fory::ForyObject;
+//! use std::sync::Arc;
+//! use std::rc::Rc;
+//!
+//! trait Animal: Serializer {
+//! fn name(&self) -> &str;
+//! }
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct Dog { name: String }
+//! impl Animal for Dog {
+//! fn name(&self) -> &str { &self.name }
+//! }
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct Cat { name: String }
+//! impl Animal for Cat {
+//! fn name(&self) -> &str { &self.name }
+//! }
+//!
+//! register_trait_type!(Animal, Dog, Cat);
+//!
+//! #[derive(ForyObject)]
+//! struct AnimalShelter {
+//! animals_rc: Vec<Rc<dyn Animal>>,
+//! animals_arc: Vec<Arc<dyn Animal>>,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default().mode(Mode::Compatible);
+//! fory.register::<Dog>(100);
+//! fory.register::<Cat>(101);
+//! fory.register::<AnimalShelter>(102);
+//!
+//! let shelter = AnimalShelter {
+//! animals_rc: vec![
+//! Rc::new(Dog { name: "Rex".to_string() }),
+//! Rc::new(Cat { name: "Mittens".to_string() }),
+//! ],
+//! animals_arc: vec![
+//! Arc::new(Dog { name: "Buddy".to_string() }),
+//! ],
+//! };
+//!
+//! let bytes = fory.serialize(&shelter);
+//! let decoded: AnimalShelter = fory.deserialize(&bytes)?;
+//!
+//! assert_eq!(decoded.animals_rc[0].name(), "Rex");
+//! assert_eq!(decoded.animals_arc[0].name(), "Buddy");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! #### Standalone Trait Object Serialization with Wrappers
+//!
+//! Due to Rust's orphan rule, `Rc<dyn Trait>` and `Arc<dyn Trait>` cannot
implement
+//! `Serializer` directly. For standalone serialization (not inside struct
fields),
+//! the `register_trait_type!` macro generates wrapper types.
+//!
+//! **Note:** If you don't want to use wrapper types, you can serialize as
`Rc<dyn Any>`
+//! or `Arc<dyn Any>` instead (see the `dyn Any` section above).
+//!
+//! The `register_trait_type!` macro generates `AnimalRc` and `AnimalArc`
wrapper types:
+//!
+//! ```rust
+//! use fory::{Fory, Mode, Error, register_trait_type, Serializer};
+//! use fory::ForyObject;
+//! use std::sync::Arc;
+//! use std::rc::Rc;
+//!
+//! trait Animal: Serializer {
+//! fn name(&self) -> &str;
+//! }
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct Dog { name: String }
+//! impl Animal for Dog {
+//! fn name(&self) -> &str { &self.name }
+//! }
+//!
+//! register_trait_type!(Animal, Dog);
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default().mode(Mode::Compatible);
+//! fory.register::<Dog>(100);
+//!
+//! // For Rc<dyn Trait>
+//! let dog_rc: Rc<dyn Animal> = Rc::new(Dog { name: "Rex".to_string() });
+//! let wrapper = AnimalRc::from(dog_rc);
+//!
+//! let bytes = fory.serialize(&wrapper);
+//! let decoded: AnimalRc = fory.deserialize(&bytes)?;
+//!
+//! // Unwrap back to Rc<dyn Animal>
+//! let unwrapped: Rc<dyn Animal> = decoded.unwrap();
+//! assert_eq!(unwrapped.name(), "Rex");
+//!
+//! // For Arc<dyn Trait>
+//! let dog_arc: Arc<dyn Animal> = Arc::new(Dog { name: "Buddy".to_string() });
+//! let wrapper = AnimalArc::from(dog_arc);
+//!
+//! let bytes = fory.serialize(&wrapper);
+//! let decoded: AnimalArc = fory.deserialize(&bytes)?;
+//!
+//! let unwrapped: Arc<dyn Animal> = decoded.unwrap();
+//! assert_eq!(unwrapped.name(), "Buddy");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ### 4. Schema Evolution
+//!
+//! **What it does:** Supports schema evolution in **Compatible mode**,
allowing
+//! serialization and deserialization peers to have different type definitions.
+//!
+//! **Why it matters:** In distributed systems and microservices, different
services
+//! evolve independently. Schema evolution enables zero-downtime deployments
where
+//! services can be updated gradually without breaking communication.
+//!
+//! **Technical approach:** In Compatible mode, Apache Fory™ includes field
names and
+//! type metadata in the serialized data. During deserialization, fields are
matched by
+//! name, allowing for additions, deletions, and reordering.
+//!
+//! **Features:**
+//!
+//! - Add new fields with default values
+//! - Remove obsolete fields (skipped during deserialization)
+//! - Change field nullability (`T` ↔ `Option<T>`)
+//! - Reorder fields (matched by name, not position)
+//! - Type-safe fallback to default values for missing fields
+//!
+//! **Compatibility rules:**
+//!
+//! - Field names must match (case-sensitive)
+//! - Type changes are not supported (except nullable/non-nullable)
+//! - Nested struct types must be registered on both sides
+//!
+//! ```rust
+//! use fory::{Fory, Error, Mode};
+//! use fory::ForyObject;
+//! use std::collections::HashMap;
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct PersonV1 {
+//! name: String,
+//! age: i32,
+//! address: String,
+//! }
+//!
+//! #[derive(ForyObject, Debug)]
+//! struct PersonV2 {
+//! name: String,
+//! age: i32,
+//! phone: Option<String>,
+//! metadata: HashMap<String, String>,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory1 = Fory::default().mode(Mode::Compatible);
+//! fory1.register::<PersonV1>(1);
+//!
+//! let mut fory2 = Fory::default().mode(Mode::Compatible);
+//! fory2.register::<PersonV2>(1);
+//!
+//! let person_v1 = PersonV1 {
+//! name: "Alice".to_string(),
+//! age: 30,
+//! address: "123 Main St".to_string(),
+//! };
+//!
+//! let bytes = fory1.serialize(&person_v1);
+//! let person_v2: PersonV2 = fory2.deserialize(&bytes)?;
+//!
+//! assert_eq!(person_v2.name, "Alice");
+//! assert_eq!(person_v2.age, 30);
+//! assert_eq!(person_v2.phone, None);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ### 5. Enum Support
+//!
+//! **What it does:** Supports C-style enums (enums without data payloads)
with efficient
+//! varint encoding.
+//!
+//! **Why it matters:** Enums are common for state machines, status codes, and
type
+//! discriminators. Efficient encoding and schema evolution support are
essential.
+//!
+//! **Technical approach:** Each variant is assigned an ordinal value (0, 1,
2, ...)
+//! during serialization. Ordinals are encoded using variable-length integers
for
+//! space efficiency.
+//!
+//! **Features:**
+//!
+//! - Efficient varint encoding for ordinals
+//! - Schema evolution support in Compatible mode
+//! - Type-safe variant matching
+//! - Default variant support with `#[default]`
+//!
+//! ```rust
+//! use fory::Fory;
+//! use fory::Error;
+//! use fory::ForyObject;
+//!
+//! #[derive(ForyObject, Debug, PartialEq, Default)]
+//! enum Status {
+//! #[default]
+//! Pending,
+//! Active,
+//! Inactive,
+//! Deleted,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default();
+//! fory.register::<Status>(1);
+//!
+//! let status = Status::Active;
+//! let bytes = fory.serialize(&status);
+//! let decoded: Status = fory.deserialize(&bytes)?;
+//! assert_eq!(status, decoded);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ### 6. Custom Serializers
+//!
+//! **What it does:** Allows manual implementation of the `Serializer` trait
for types
+//! that don't support `#[derive(ForyObject)]`.
+//!
+//! **When to use:**
+//!
+//! - External types from other crates that you can't modify
+//! - Types with special serialization requirements
+//! - Legacy data format compatibility
+//! - Performance-critical custom encoding
+//! - Complex types that require special handling
+//!
+//! **Technical approach:** Implement the `Serializer` trait's
`fory_write_data()` and
+//! `fory_read_data()` methods to control exactly how data is written to and
read from
+//! the binary buffer.
+//!
+//! ```rust
+//! use fory::{Fory, ReadContext, WriteContext, Serializer, ForyDefault,
Error};
+//! use std::any::Any;
+//!
+//! #[derive(Debug, PartialEq, Default)]
+//! struct CustomType {
+//! value: i32,
+//! name: String,
+//! }
+//!
+//! impl Serializer for CustomType {
+//! fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
+//! context.writer.write_i32(self.value);
+//! context.writer.write_varuint32(self.name.len() as u32);
+//! context.writer.write_utf8_string(&self.name);
+//! }
+//!
+//! fn fory_read_data(context: &mut ReadContext, is_field: bool) ->
Result<Self, Error> {
+//! let value = context.reader.read_i32();
+//! let len = context.reader.read_varuint32() as usize;
+//! let name = context.reader.read_utf8_string(len);
+//! Ok(Self { value, name })
+//! }
+//!
+//! fn fory_type_id_dyn(&self, fory: &Fory) -> u32 {
+//! Self::fory_get_type_id(fory)
+//! }
+//!
+//! fn as_any(&self) -> &dyn Any {
+//! self
+//! }
+//! }
+//!
+//! impl ForyDefault for CustomType {
+//! fn fory_default() -> Self {
+//! Self::default()
+//! }
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let mut fory = Fory::default();
+//! fory.register_serializer::<CustomType>(100);
+//!
+//! let custom = CustomType {
+//! value: 42,
+//! name: "test".to_string(),
+//! };
+//! let bytes = fory.serialize(&custom);
+//! let decoded: CustomType = fory.deserialize(&bytes)?;
+//! assert_eq!(custom, decoded);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ### 7. Row-Based Serialization
+//!
+//! **What it does:** Provides a high-performance **row format** for zero-copy
+//! deserialization, enabling random access to fields directly from binary data
+//! without full object reconstruction.
+//!
+//! **Why it matters:** Traditional serialization reconstructs entire objects
in memory.
+//! For analytics workloads or when you only need a few fields from large
objects,
+//! this is wasteful. Row format provides O(1) field access without
deserialization.
+//!
+//! **Technical approach:** Fields are encoded in a binary row with fixed
offsets for
+//! primitives. Variable-length data (strings, collections) are stored with
offset
+//! pointers. A null bitmap tracks which fields are present. The generated
code provides
+//! accessor methods that read directly from the binary buffer.
+//!
+//! **Key benefits:**
+//!
+//! - **Zero-copy access**: Read fields without allocating or copying data
+//! - **Partial deserialization**: Access only the fields you need
+//! - **Memory-mapped files**: Work with data larger than RAM
+//! - **Cache-friendly**: Sequential memory layout for better CPU cache
utilization
+//! - **Lazy evaluation**: Defer expensive operations until field access
+//!
+//! **When to use row format:**
+//!
+//! - Analytics workloads with selective field access
+//! - Large datasets where only a subset of fields is needed
+//! - Memory-constrained environments
+//! - High-throughput data pipelines
+//! - Reading from memory-mapped files or shared memory
+//!
+//! **Performance characteristics:**
+//!
+//! | Operation | Object Format | Row Format
|
+//!
|----------------------|-------------------------------|---------------------------------|
+//! | Full deserialization | Allocates all objects | Zero allocation
|
+//! | Single field access | Full deserialization required | Direct offset
read (O(1)) |
+//! | Memory usage | Full object graph in memory | Only accessed
fields in memory |
+//! | Suitable for | Small objects, full access | Large objects,
selective access |
//!
//! ```rust
//! use fory::{to_row, from_row};
@@ -113,6 +815,7 @@
//! is_active: bool,
//! }
//!
+//! # fn main() {
//! let profile = UserProfile {
//! id: 12345,
//! username: "alice".to_string(),
@@ -125,84 +828,170 @@
//! is_active: true,
//! };
//!
-//! // Serialize to row format
//! let row_data = to_row(&profile);
-//!
-//! // Deserialize with zero-copy access
//! let row = from_row::<UserProfile>(&row_data);
//!
-//! // Access fields directly from the row data
//! assert_eq!(row.id(), 12345);
//! assert_eq!(row.username(), "alice");
-//! assert_eq!(row.email(), "[email protected]");
//! assert_eq!(row.is_active(), true);
//!
-//! // Access collections efficiently
//! let scores = row.scores();
//! assert_eq!(scores.size(), 4);
//! assert_eq!(scores.get(0), 95);
-//! assert_eq!(scores.get(1), 87);
-//!
-//! let prefs = row.preferences();
-//! assert_eq!(prefs.keys().size(), 2);
-//! assert_eq!(prefs.keys().get(0), "language");
-//! assert_eq!(prefs.values().get(0), "en");
+//! # }
//! ```
//!
//! ## Supported Types
//!
-//! Fory supports a wide range of Rust types:
+//! Apache Fory™ supports a comprehensive type system for maximum flexibility.
//!
//! ### Primitive Types
-//! - `bool`, `i8`, `i16`, `i32`, `i64`, `f32`, `f64`
-//! - `String`, `&str` (in row format)
-//! - `Vec<u8>` for binary data
+//!
+//! - `bool` - Boolean values
+//! - `i8`, `i16`, `i32`, `i64` - Signed integers
+//! - `f32`, `f64` - Floating point numbers
+//! - `String` - UTF-8 encoded strings
//!
//! ### Collections
-//! - `Vec<T>` for arrays/lists
-//! - `HashMap<K, V>` and `BTreeMap<K, V>` for maps
-//! - `Option<T>` for nullable values
//!
-//! ### Date and Time
-//! - `chrono::NaiveDate` for dates
-//! - `chrono::NaiveDateTime` for timestamps
+//! - `Vec<T>` - Dynamic arrays
+//! - `HashMap<K, V>` - Hash-based maps
+//! - `BTreeMap<K, V>` - Ordered maps
+//! - `HashSet<T>` - Hash-based sets
+//! - `Option<T>` - Optional values
+//!
+//! ### Smart Pointers
+//!
+//! - `Box<T>` - Heap allocation
+//! - `Rc<T>` - Reference counting (shared references tracked automatically)
+//! - `Arc<T>` - Thread-safe reference counting (shared references tracked)
+//! - `RcWeak<T>` - Weak reference to `Rc<T>` (breaks circular references)
+//! - `ArcWeak<T>` - Weak reference to `Arc<T>` (breaks circular references)
+//! - `RefCell<T>` - Interior mutability with runtime borrow checking
+//! - `Mutex<T>` - Thread-safe interior mutability
+//!
+//! ### Date and Time (requires `chrono` feature)
+//!
+//! - `chrono::NaiveDate` - Date without timezone
+//! - `chrono::NaiveDateTime` - Timestamp without timezone
//!
//! ### Custom Types
-//! - Structs with `#[derive(ForyObject)]` or `#[derive(ForyRow)]`
-//! - Enums with `#[derive(ForyObject)]`
+//!
+//! - Structs with `#[derive(ForyObject)]` - Object graph serialization
+//! - Structs with `#[derive(ForyRow)]` - Row-based serialization
+//! - C-style enums with `#[derive(ForyObject)]` - Enum support
+//! - Manual `Serializer` implementation - Custom serialization logic
+//!
+//! ### Trait Objects
+//!
+//! - `Box<dyn Trait>` - Owned trait objects
+//! - `Rc<dyn Trait>` - Reference-counted trait objects
+//! - `Arc<dyn Trait>` - Thread-safe reference-counted trait objects
+//! - `Rc<dyn Any>` - Runtime type dispatch without custom traits
+//! - `Arc<dyn Any>` - Thread-safe runtime type dispatch
//!
//! ## Serialization Modes
//!
-//! Fory supports two serialization modes:
+//! Apache Fory™ supports two serialization modes to balance between
performance
+//! and flexibility:
+//!
+//! ### SchemaConsistent Mode (Default)
//!
-//! - **SchemaConsistent**: Type declarations must be consistent between
-//! serialization and deserialization peers (default)
-//! - **Compatible**: Type declarations can differ between peers, allowing
-//! independent field additions/deletions
+//! **When to use:** Maximum performance when schemas are guaranteed to match.
+//!
+//! **Characteristics:**
+//! - Type declarations must match exactly between serialization and
deserialization
+//! - Smaller payload size (no field names or metadata)
+//! - Faster serialization and deserialization
+//! - Suitable for monolithic applications or tightly coupled services
//!
//! ```rust
//! use fory::Fory;
-//! use fory_core::types::Mode;
-//! use fory_derive::ForyObject;
//!
-//! #[derive(ForyObject, Debug)]
-//! struct Config {
-//! name: String,
-//! value: i32,
+//! let fory = Fory::default();
+//! ```
+//!
+//! ### Compatible Mode
+//!
+//! **When to use:** Schema evolution in distributed systems or microservices.
+//!
+//! **Characteristics:**
+//! - Type declarations can differ between peers
+//! - Allows field additions, deletions, and reordering
+//! - Larger payload size (includes field names and metadata)
+//! - Slightly slower due to metadata processing
+//! - Essential for zero-downtime deployments
+//!
+//! ```rust
+//! use fory::{Fory, Mode};
+//!
+//! let fory = Fory::default().mode(Mode::Compatible);
+//! ```
+//!
+//! ## Cross-Language Serialization
+//!
+//! **What it enables:** Seamless data exchange across Java, Python, C++, Go,
+//! JavaScript, and Rust implementations.
+//!
+//! **Why it matters:** Microservices architectures often use multiple
languages.
+//! Apache Fory™ provides a common binary protocol without IDL files or code
generation.
+//!
+//! **How to enable:**
+//!
+//! ```rust
+//! use fory::{Fory, Mode};
+//! use fory::ForyObject;
+//!
+//! let mut fory = Fory::default()
+//! .mode(Mode::Compatible)
+//! .xlang(true);
+//!
+//! #[derive(ForyObject)]
+//! struct MyStruct {
+//! field1: i32,
+//! field2: String,
//! }
//!
-//! let mut fory = Fory::default().mode(Mode::Compatible);
-//! fory.register::<Config>(100);
-//! // ... use fory for serialization
+//! fory.register_by_namespace::<MyStruct>("com.example", "MyStruct");
//! ```
//!
+//! **Type registration strategies:**
+//!
+//! - **ID-based registration**: `fory.register::<T>(id)` - Fastest, requires
coordination
+//! - **Namespace-based registration**:
`fory.register_by_namespace::<T>(namespace, name)` - Automatic cross-language
mapping
+//!
+//! ## Performance Characteristics
+//!
+//! Apache Fory™ Rust is designed for maximum performance through multiple
techniques:
+//!
+//! **Compile-time code generation:**
+//! - Procedural macros generate specialized serialization code
+//! - Zero runtime overhead, no reflection
+//! - Monomorphization for type-specific optimizations
+//!
+//! **Zero-copy techniques:**
+//! - Row format enables direct memory access
+//! - No intermediate object allocation
+//! - Memory-mapped file support
+//!
+//! **Space efficiency:**
+//! - Variable-length integer encoding
+//! - Reference deduplication (shared objects serialized once)
+//! - Compact binary format
+//!
+//! **Buffer management:**
+//! - Pre-allocation based on `fory_reserved_space()` hints
+//! - Minimized reallocations
+//! - Little-endian layout for modern CPUs
+//!
//! ## Error Handling
//!
-//! Fory provides comprehensive error handling through the `Error` type:
+//! Apache Fory™ uses `Result<T, Error>` for all fallible operations, providing
+//! comprehensive error handling:
//!
//! ```rust
//! use fory::{Fory, Error};
-//! use fory_derive::ForyObject;
+//! use fory::ForyObject;
//!
//! #[derive(ForyObject)]
//! struct Data {
@@ -212,52 +1001,52 @@
//! fn process_data(bytes: &[u8]) -> Result<Data, Error> {
//! let mut fory = Fory::default();
//! fory.register::<Data>(100);
-//!
-//! // This can fail if the data is corrupted or type mismatches
+//!
//! let data: Data = fory.deserialize(bytes)?;
//! Ok(data)
//! }
//! ```
//!
-//! ## Performance Considerations
+//! ## Thread Safety
//!
-//! - **Object Serialization**: Best for complex object graphs with references
-//! - **Row Serialization**: Best for high-throughput, zero-copy scenarios
-//! - **Type Registration**: Register all types before serialization for
optimal performance
-//! - **Buffer Pre-allocation**: Fory automatically reserves space to minimize
allocations
+//! **Important:** `Fory` instances are **not thread-safe**. Use one instance
per thread:
//!
-//! ## Cross-Language Compatibility
+//! ```rust
+//! use std::thread_local;
+//! use std::cell::RefCell;
+//! use fory::Fory;
//!
-//! Fory is designed to work across multiple programming languages, making it
-//! ideal for microservices architectures and distributed systems where
different
-//! services may be implemented in different languages.
+//! thread_local! {
+//! static FORY: RefCell<Fory> = RefCell::new(Fory::default());
+//! }
//!
-//! ## Getting Started
+//! # fn serialize_data() -> Vec<u8> {
+//! FORY.with(|fory| {
+//! let data = vec![1, 2, 3];
+//! fory.borrow().serialize(&data)
+//! })
+//! # }
+//! ```
//!
-//! Add Fory to your `Cargo.toml`:
+//! ## Examples
//!
-//! ```toml
-//! [dependencies]
-//! fory = "0.1"
-//! fory-derive = "0.1"
-//! chrono = "0.4"
-//! ```
+//! See the `tests/` directory for comprehensive examples:
//!
-//! Then use the derive macros to make your types serializable:
+//! - `tests/tests/test_complex_struct.rs` - Complex nested structures
+//! - `tests/tests/test_rc_arc_trait_object.rs` - Trait object serialization
+//! - `tests/tests/test_weak.rs` - Circular reference handling
+//! - `tests/tests/test_cross_language.rs` - Cross-language compatibility
//!
-//! ```rust
-//! use fory_derive::{ForyObject, ForyRow};
+//! ## Documentation
//!
-//! #[derive(ForyObject)] // For object serialization
-//! #[derive(ForyRow)] // For row-based serialization
-//! struct MyData {
-//! field1: String,
-//! field2: i32,
-//! }
-//! ```
+//! - **[Protocol
Specification](https://fory.apache.org/docs/specification/fory_xlang_serialization_spec)**
- Binary protocol details
+//! - **[Row Format
Specification](https://fory.apache.org/docs/specification/fory_row_format_spec)**
- Row format internals
+//! - **[Type
Mapping](https://fory.apache.org/docs/guide/xlang_type_mapping)** -
Cross-language type mappings
+//! - **[API Documentation](https://docs.rs/fory)** - Complete API reference
+//! - **[GitHub Repository](https://github.com/apache/fory)** - Source code
and issue tracking
pub use fory_core::{
error::Error, fory::Fory, register_trait_type, row::from_row, row::to_row,
types::Mode,
- types::TypeId, ArcWeak, RcWeak,
+ types::TypeId, ArcWeak, ForyDefault, RcWeak, ReadContext, Serializer,
WriteContext,
};
pub use fory_derive::{ForyObject, ForyRow};
diff --git a/rust/tests/tests/test_complex_refs.rs
b/rust/tests/tests/test_complex_refs.rs
index a26e5e764..f790f4ce1 100644
--- a/rust/tests/tests/test_complex_refs.rs
+++ b/rust/tests/tests/test_complex_refs.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-//! Tests for shared reference handling in Fury Rust
+//! Tests for shared reference handling in Fory Rust
use fory_core::fory::Fory;
use std::rc::Rc;
@@ -23,7 +23,7 @@ use std::sync::Arc;
#[test]
fn test_rc_shared_in_nested_vec() {
- let fury = Fory::default();
+ let fory = Fory::default();
let shared1 = Rc::new(String::from("shared_1"));
let shared2 = Rc::new(String::from("shared_2"));
@@ -35,8 +35,8 @@ fn test_rc_shared_in_nested_vec() {
vec![shared1.clone()],
];
- let serialized = fury.serialize(&nested);
- let deserialized: Vec<Vec<Rc<String>>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&nested);
+ let deserialized: Vec<Vec<Rc<String>>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 3);
assert_eq!(deserialized[0].len(), 2);
@@ -55,7 +55,7 @@ fn test_rc_shared_in_nested_vec() {
#[test]
fn test_arc_shared_in_nested_vec() {
- let fury = Fory::default();
+ let fory = Fory::default();
let shared1 = Arc::new(String::from("shared_1"));
let shared2 = Arc::new(String::from("shared_2"));
@@ -67,8 +67,8 @@ fn test_arc_shared_in_nested_vec() {
vec![shared1.clone()],
];
- let serialized = fury.serialize(&nested);
- let deserialized: Vec<Vec<Arc<String>>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&nested);
+ let deserialized: Vec<Vec<Arc<String>>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 3);
assert_eq!(deserialized[0].len(), 2);
@@ -87,7 +87,7 @@ fn test_arc_shared_in_nested_vec() {
#[test]
fn test_mixed_rc_arc_sharing() {
- let fury = Fory::default();
+ let fory = Fory::default();
// Test both Rc and Arc sharing within the same structure
let shared_rc = Rc::new(42i32);
@@ -97,11 +97,11 @@ fn test_mixed_rc_arc_sharing() {
let rc_vec = vec![shared_rc.clone(), shared_rc.clone()];
let arc_vec = vec![shared_arc.clone(), shared_arc.clone()];
- let serialized_rc = fury.serialize(&rc_vec);
- let serialized_arc = fury.serialize(&arc_vec);
+ let serialized_rc = fory.serialize(&rc_vec);
+ let serialized_arc = fory.serialize(&arc_vec);
- let deserialized_rc: Vec<Rc<i32>> =
fury.deserialize(&serialized_rc).unwrap();
- let deserialized_arc: Vec<Arc<String>> =
fury.deserialize(&serialized_arc).unwrap();
+ let deserialized_rc: Vec<Rc<i32>> =
fory.deserialize(&serialized_rc).unwrap();
+ let deserialized_arc: Vec<Arc<String>> =
fory.deserialize(&serialized_arc).unwrap();
// Verify Rc sharing
assert!(Rc::ptr_eq(&deserialized_rc[0], &deserialized_rc[1]));
@@ -114,7 +114,7 @@ fn test_mixed_rc_arc_sharing() {
#[test]
fn test_deep_sharing_stress_test() {
- let fury = Fory::default();
+ let fory = Fory::default();
// Create a stress test with deep nesting and many shared references
let shared = Rc::new(String::from("deep_shared"));
@@ -125,8 +125,8 @@ fn test_deep_sharing_stress_test() {
vec![vec![shared.clone()]],
];
- let serialized = fury.serialize(&deep_structure);
- let deserialized: Vec<Vec<Vec<Rc<String>>>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&deep_structure);
+ let deserialized: Vec<Vec<Vec<Rc<String>>>> =
fory.deserialize(&serialized).unwrap();
// Verify structure
assert_eq!(deserialized.len(), 3);
diff --git a/rust/tests/tests/test_mutex.rs b/rust/tests/tests/test_mutex.rs
index 0b22924db..af2b75917 100644
--- a/rust/tests/tests/test_mutex.rs
+++ b/rust/tests/tests/test_mutex.rs
@@ -20,31 +20,31 @@ use std::sync::{Arc, Mutex};
#[test]
fn test_mutex_basic_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let m = Mutex::new(42i32);
- let serialized = fury.serialize(&m);
- let deserialized: Mutex<i32> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&m);
+ let deserialized: Mutex<i32> = fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.lock().unwrap().clone(), 42);
}
#[test]
fn test_arc_mutex_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let arc_mutex = Arc::new(Mutex::new(String::from("hello")));
- let serialized = fury.serialize(&arc_mutex);
- let deserialized: Arc<Mutex<String>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&arc_mutex);
+ let deserialized: Arc<Mutex<String>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.lock().unwrap().as_str(), "hello");
}
#[test]
fn test_arc_mutex_sharing_preserved() {
- let fury = Fory::default();
+ let fory = Fory::default();
let data = Arc::new(Mutex::new(123i32));
let list = vec![data.clone(), data.clone()];
- let serialized = fury.serialize(&list);
- let deserialized: Vec<Arc<Mutex<i32>>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&list);
+ let deserialized: Vec<Arc<Mutex<i32>>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 2);
assert!(Arc::ptr_eq(&deserialized[0], &deserialized[1]));
diff --git a/rust/tests/tests/test_rc_arc.rs b/rust/tests/tests/test_rc_arc.rs
index cc1046869..7b6604051 100644
--- a/rust/tests/tests/test_rc_arc.rs
+++ b/rust/tests/tests/test_rc_arc.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-//! Tests for Rc and Arc serialization support in Fury
+//! Tests for Rc and Arc serialization support in Fory
use fory_core::fory::Fory;
use std::collections::HashMap;
@@ -24,13 +24,13 @@ use std::sync::Arc;
#[test]
fn test_rc_string_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let data = String::from("Hello, Rc!");
let rc_data = Rc::new(data);
- let serialized = fury.serialize(&rc_data);
- let deserialized: Rc<String> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&rc_data);
+ let deserialized: Rc<String> = fory.deserialize(&serialized).unwrap();
assert_eq!(*rc_data, *deserialized);
assert_eq!("Hello, Rc!", *deserialized);
@@ -38,13 +38,13 @@ fn test_rc_string_serialization() {
#[test]
fn test_arc_string_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let data = String::from("Hello, Arc!");
let arc_data = Arc::new(data);
- let serialized = fury.serialize(&arc_data);
- let deserialized: Arc<String> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&arc_data);
+ let deserialized: Arc<String> = fory.deserialize(&serialized).unwrap();
assert_eq!(*arc_data, *deserialized);
assert_eq!("Hello, Arc!", *deserialized);
@@ -52,12 +52,12 @@ fn test_arc_string_serialization() {
#[test]
fn test_rc_number_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let rc_number = Rc::new(42i32);
- let serialized = fury.serialize(&rc_number);
- let deserialized: Rc<i32> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&rc_number);
+ let deserialized: Rc<i32> = fory.deserialize(&serialized).unwrap();
assert_eq!(*rc_number, *deserialized);
assert_eq!(42, *deserialized);
@@ -65,12 +65,12 @@ fn test_rc_number_serialization() {
#[test]
fn test_arc_number_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let arc_number = Arc::new(100i64);
- let serialized = fury.serialize(&arc_number);
- let deserialized: Arc<i64> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&arc_number);
+ let deserialized: Arc<i64> = fory.deserialize(&serialized).unwrap();
assert_eq!(*arc_number, *deserialized);
assert_eq!(100, *deserialized);
@@ -78,15 +78,15 @@ fn test_arc_number_serialization() {
#[test]
fn test_rc_in_collections() {
- let fury = Fory::default();
+ let fory = Fory::default();
let string1 = Rc::new(String::from("First"));
let string2 = Rc::new(String::from("Second"));
let strings = vec![string1.clone(), string2.clone(), string1.clone()];
- let serialized = fury.serialize(&strings);
- let deserialized: Vec<Rc<String>> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&strings);
+ let deserialized: Vec<Rc<String>> = fory.deserialize(&serialized).unwrap();
assert_eq!(strings.len(), deserialized.len());
assert_eq!(*strings[0], *deserialized[0]);
@@ -99,15 +99,15 @@ fn test_rc_in_collections() {
#[test]
fn test_arc_in_collections() {
- let fury = Fory::default();
+ let fory = Fory::default();
let number1 = Arc::new(123i32);
let number2 = Arc::new(456i32);
let numbers = vec![number1.clone(), number2.clone(), number1.clone()];
- let serialized = fury.serialize(&numbers);
- let deserialized: Vec<Arc<i32>> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&numbers);
+ let deserialized: Vec<Arc<i32>> = fory.deserialize(&serialized).unwrap();
assert_eq!(numbers.len(), deserialized.len());
assert_eq!(*numbers[0], *deserialized[0]);
@@ -120,13 +120,13 @@ fn test_arc_in_collections() {
#[test]
fn test_rc_vec_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let data = vec![1, 2, 3, 4, 5];
let rc_data = Rc::new(data);
- let serialized = fury.serialize(&rc_data);
- let deserialized: Rc<Vec<i32>> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&rc_data);
+ let deserialized: Rc<Vec<i32>> = fory.deserialize(&serialized).unwrap();
assert_eq!(*rc_data, *deserialized);
assert_eq!(vec![1, 2, 3, 4, 5], *deserialized);
@@ -134,13 +134,13 @@ fn test_rc_vec_serialization() {
#[test]
fn test_arc_vec_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let data = vec![String::from("a"), String::from("b"), String::from("c")];
let arc_data = Arc::new(data);
- let serialized = fury.serialize(&arc_data);
- let deserialized: Arc<Vec<String>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&arc_data);
+ let deserialized: Arc<Vec<String>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(*arc_data, *deserialized);
assert_eq!(vec!["a", "b", "c"], *deserialized);
@@ -148,17 +148,17 @@ fn test_arc_vec_serialization() {
#[test]
fn test_mixed_rc_arc_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
// Test basic types wrapped in Rc/Arc
let rc_number = Rc::new(42i32);
let arc_number = Arc::new(100i64);
- let rc_serialized = fury.serialize(&rc_number);
- let arc_serialized = fury.serialize(&arc_number);
+ let rc_serialized = fory.serialize(&rc_number);
+ let arc_serialized = fory.serialize(&arc_number);
- let rc_deserialized: Rc<i32> = fury.deserialize(&rc_serialized).unwrap();
- let arc_deserialized: Arc<i64> =
fury.deserialize(&arc_serialized).unwrap();
+ let rc_deserialized: Rc<i32> = fory.deserialize(&rc_serialized).unwrap();
+ let arc_deserialized: Arc<i64> =
fory.deserialize(&arc_serialized).unwrap();
assert_eq!(*rc_number, *rc_deserialized);
assert_eq!(*arc_number, *arc_deserialized);
@@ -166,21 +166,21 @@ fn test_mixed_rc_arc_serialization() {
#[test]
fn test_nested_rc_arc() {
- let fury = Fory::default();
+ let fory = Fory::default();
// Test Rc containing Arc
let inner_data = Arc::new(String::from("nested"));
let outer_data = Rc::new(inner_data.clone());
- let serialized = fury.serialize(&outer_data);
- let deserialized: Rc<Arc<String>> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&outer_data);
+ let deserialized: Rc<Arc<String>> = fory.deserialize(&serialized).unwrap();
assert_eq!(**outer_data, **deserialized);
}
#[test]
fn test_rc_arc_with_hashmaps() {
- let fury = Fory::default();
+ let fory = Fory::default();
let string_data = Arc::new(String::from("shared"));
@@ -188,8 +188,8 @@ fn test_rc_arc_with_hashmaps() {
map.insert("key1".to_string(), string_data.clone());
map.insert("key2".to_string(), string_data.clone());
- let serialized = fury.serialize(&map);
- let deserialized: HashMap<String, Arc<String>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&map);
+ let deserialized: HashMap<String, Arc<String>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(map.len(), deserialized.len());
assert_eq!(*map["key1"], *deserialized["key1"]);
@@ -202,35 +202,35 @@ fn test_rc_arc_with_hashmaps() {
#[test]
fn test_arc_serialization_basic() {
- let fury = Fory::default();
+ let fory = Fory::default();
let arc = Arc::new(42i32);
- let serialized = fury.serialize(&arc);
- let deserialized: Arc<i32> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&arc);
+ let deserialized: Arc<i32> = fory.deserialize(&serialized).unwrap();
assert_eq!(*deserialized, 42);
}
#[test]
fn test_arc_shared_reference() {
- let fury = Fory::default();
+ let fory = Fory::default();
let arc1 = Arc::new(String::from("shared"));
- let serialized = fury.serialize(&arc1);
- let deserialized: Arc<String> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&arc1);
+ let deserialized: Arc<String> = fory.deserialize(&serialized).unwrap();
assert_eq!(*deserialized, "shared");
}
#[test]
fn test_arc_shared_reference_in_vec() {
- let fury = Fory::default();
+ let fory = Fory::default();
let shared = Arc::new(String::from("shared_value"));
let vec = vec![shared.clone(), shared.clone(), shared.clone()];
- let serialized = fury.serialize(&vec);
- let deserialized: Vec<Arc<String>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&vec);
+ let deserialized: Vec<Arc<String>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 3);
assert_eq!(*deserialized[0], "shared_value");
@@ -244,7 +244,7 @@ fn test_arc_shared_reference_in_vec() {
#[test]
fn test_arc_multiple_shared_references() {
- let fury = Fory::default();
+ let fory = Fory::default();
let shared1 = Arc::new(42i32);
let shared2 = Arc::new(100i32);
@@ -257,8 +257,8 @@ fn test_arc_multiple_shared_references() {
shared1.clone(),
];
- let serialized = fury.serialize(&vec);
- let deserialized: Vec<Arc<i32>> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&vec);
+ let deserialized: Vec<Arc<i32>> = fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 5);
assert_eq!(*deserialized[0], 42);
@@ -277,15 +277,15 @@ fn test_arc_multiple_shared_references() {
fn test_arc_thread_safety() {
use std::thread;
- let fury = Fory::default();
+ let fory = Fory::default();
let arc = Arc::new(vec![1, 2, 3, 4, 5]);
- let serialized = fury.serialize(&arc);
+ let serialized = fory.serialize(&arc);
// Test that Arc can be sent across threads
let handle = thread::spawn(move || {
- let fury = Fory::default();
- let deserialized: Arc<Vec<i32>> =
fury.deserialize(&serialized).unwrap();
+ let fory = Fory::default();
+ let deserialized: Arc<Vec<i32>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(*deserialized, vec![1, 2, 3, 4, 5]);
});
@@ -294,35 +294,35 @@ fn test_arc_thread_safety() {
#[test]
fn test_rc_serialization_basic() {
- let fury = Fory::default();
+ let fory = Fory::default();
let rc = Rc::new(42i32);
- let serialized = fury.serialize(&rc);
- let deserialized: Rc<i32> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&rc);
+ let deserialized: Rc<i32> = fory.deserialize(&serialized).unwrap();
assert_eq!(*deserialized, 42);
}
#[test]
fn test_rc_shared_reference() {
- let fury = Fory::default();
+ let fory = Fory::default();
let rc1 = Rc::new(String::from("shared"));
- let serialized = fury.serialize(&rc1);
- let deserialized: Rc<String> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&rc1);
+ let deserialized: Rc<String> = fory.deserialize(&serialized).unwrap();
assert_eq!(*deserialized, "shared");
}
#[test]
fn test_rc_shared_reference_in_vec() {
- let fury = Fory::default();
+ let fory = Fory::default();
let shared = Rc::new(String::from("shared_value"));
let vec = vec![shared.clone(), shared.clone(), shared.clone()];
- let serialized = fury.serialize(&vec);
- let deserialized: Vec<Rc<String>> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&vec);
+ let deserialized: Vec<Rc<String>> = fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 3);
assert_eq!(*deserialized[0], "shared_value");
@@ -336,7 +336,7 @@ fn test_rc_shared_reference_in_vec() {
#[test]
fn test_rc_multiple_shared_references() {
- let fury = Fory::default();
+ let fory = Fory::default();
let shared1 = Rc::new(42i32);
let shared2 = Rc::new(100i32);
@@ -349,8 +349,8 @@ fn test_rc_multiple_shared_references() {
shared1.clone(),
];
- let serialized = fury.serialize(&vec);
- let deserialized: Vec<Rc<i32>> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&vec);
+ let deserialized: Vec<Rc<i32>> = fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 5);
assert_eq!(*deserialized[0], 42);
diff --git a/rust/tests/tests/test_rc_arc_trait_object.rs
b/rust/tests/tests/test_rc_arc_trait_object.rs
index 1dc62e828..92bfe0a66 100644
--- a/rust/tests/tests/test_rc_arc_trait_object.rs
+++ b/rust/tests/tests/test_rc_arc_trait_object.rs
@@ -315,7 +315,6 @@ struct AnimalShelter {
}
#[test]
-#[ignore]
fn test_collections_of_wrappers() {
let mut fory = fory_compatible();
fory.register::<Dog>(8001);
diff --git a/rust/tests/tests/test_refcell.rs b/rust/tests/tests/test_refcell.rs
index 61a94d45e..da7d91f1b 100644
--- a/rust/tests/tests/test_refcell.rs
+++ b/rust/tests/tests/test_refcell.rs
@@ -27,12 +27,12 @@ struct Simple {
#[test]
fn test_rc_refcell_simple() {
- let mut fury = Fory::default();
- fury.register::<Simple>(3000);
+ let mut fory = Fory::default();
+ fory.register::<Simple>(3000);
let node = Rc::new(RefCell::new(Simple { value: 42 }));
- let serialized = fury.serialize(&node);
- let deserialized: Rc<RefCell<Simple>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&node);
+ let deserialized: Rc<RefCell<Simple>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.borrow().value, 42);
}
@@ -44,17 +44,17 @@ struct Parent {
#[test]
fn test_rc_refcell_in_struct() {
- let mut fury = Fory::default();
- fury.register::<Simple>(3001);
- fury.register::<Parent>(3002);
+ let mut fory = Fory::default();
+ fory.register::<Simple>(3001);
+ fory.register::<Parent>(3002);
let child = Rc::new(RefCell::new(Simple { value: 99 }));
let parent = Parent {
value: 1,
child: Some(child),
};
- let serialized = fury.serialize(&parent);
- let deserialized: Parent = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&parent);
+ let deserialized: Parent = fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.value, 1);
assert_eq!(deserialized.child.unwrap().borrow().value, 99);
}
diff --git a/rust/tests/tests/test_weak.rs b/rust/tests/tests/test_weak.rs
index f1b52f7b9..d994030a1 100644
--- a/rust/tests/tests/test_weak.rs
+++ b/rust/tests/tests/test_weak.rs
@@ -25,31 +25,31 @@ use std::sync::Mutex;
#[test]
fn test_rc_weak_null_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let weak: RcWeak<i32> = RcWeak::new();
- let serialized = fury.serialize(&weak);
- let deserialized: RcWeak<i32> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&weak);
+ let deserialized: RcWeak<i32> = fory.deserialize(&serialized).unwrap();
assert!(deserialized.upgrade().is_none());
}
#[test]
fn test_arc_weak_null_serialization() {
- let fury = Fory::default();
+ let fory = Fory::default();
let weak: ArcWeak<i32> = ArcWeak::new();
- let serialized = fury.serialize(&weak);
- let deserialized: ArcWeak<i32> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&weak);
+ let deserialized: ArcWeak<i32> = fory.deserialize(&serialized).unwrap();
assert!(deserialized.upgrade().is_none());
}
#[test]
fn test_rc_weak_dead_pointer_serializes_as_null() {
- let fury = Fory::default();
+ let fory = Fory::default();
let weak = {
let rc = Rc::new(42i32);
@@ -61,15 +61,15 @@ fn test_rc_weak_dead_pointer_serializes_as_null() {
assert!(weak.upgrade().is_none());
// Should serialize as Null
- let serialized = fury.serialize(&weak);
- let deserialized: RcWeak<i32> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&weak);
+ let deserialized: RcWeak<i32> = fory.deserialize(&serialized).unwrap();
assert!(deserialized.upgrade().is_none());
}
#[test]
fn test_arc_weak_dead_pointer_serializes_as_null() {
- let fury = Fory::default();
+ let fory = Fory::default();
let weak = {
let arc = Arc::new(String::from("test"));
@@ -81,15 +81,15 @@ fn test_arc_weak_dead_pointer_serializes_as_null() {
assert!(weak.upgrade().is_none());
// Should serialize as Null
- let serialized = fury.serialize(&weak);
- let deserialized: ArcWeak<String> = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&weak);
+ let deserialized: ArcWeak<String> = fory.deserialize(&serialized).unwrap();
assert!(deserialized.upgrade().is_none());
}
#[test]
fn test_rc_weak_in_vec_circular_reference() {
- let fury = Fory::default();
+ let fory = Fory::default();
let data1 = Rc::new(42i32);
let data2 = Rc::new(100i32);
@@ -99,15 +99,15 @@ fn test_rc_weak_in_vec_circular_reference() {
let weak3 = weak1.clone();
let weaks = vec![weak1, weak2, weak3];
- let serialized = fury.serialize(&weaks);
- let deserialized: Vec<RcWeak<i32>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&weaks);
+ let deserialized: Vec<RcWeak<i32>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 3);
}
#[test]
fn test_arc_weak_in_vec_circular_reference() {
- let fury = Fory::default();
+ let fory = Fory::default();
let data1 = Arc::new(String::from("hello"));
let data2 = Arc::new(String::from("world"));
@@ -117,8 +117,8 @@ fn test_arc_weak_in_vec_circular_reference() {
let weak3 = weak1.clone();
let weaks = vec![weak1, weak2, weak3];
- let serialized = fury.serialize(&weaks);
- let deserialized: Vec<ArcWeak<String>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&weaks);
+ let deserialized: Vec<ArcWeak<String>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.len(), 3);
}
@@ -133,8 +133,8 @@ fn test_rc_weak_field_in_struct() {
weak_ref: RcWeak<i32>,
}
- let mut fury = Fory::default();
- fury.register::<SimpleNode>(1000);
+ let mut fory = Fory::default();
+ fory.register::<SimpleNode>(1000);
let data = Rc::new(42i32);
let node = SimpleNode {
@@ -142,8 +142,8 @@ fn test_rc_weak_field_in_struct() {
weak_ref: RcWeak::from(&data),
};
- let serialized = fury.serialize(&node);
- let deserialized: SimpleNode = fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&node);
+ let deserialized: SimpleNode = fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.value, 1);
}
@@ -160,8 +160,8 @@ struct Node {
#[test]
fn test_node_circular_reference_with_parent_children() {
// Register the Node type with Fory
- let mut fury = Fory::default();
- fury.register::<Node>(2000);
+ let mut fory = Fory::default();
+ fory.register::<Node>(2000);
// Create parent
let parent = Rc::new(RefCell::new(Node {
@@ -192,10 +192,10 @@ fn test_node_circular_reference_with_parent_children() {
child2.borrow_mut().parent = RcWeak::from(&parent);
// --- Serialize the parent node (will include children recursively) ---
- let serialized = fury.serialize(&parent);
+ let serialized = fory.serialize(&parent);
// --- Deserialize ---
- let deserialized: Rc<RefCell<Node>> =
fury.deserialize(&serialized).unwrap();
+ let deserialized: Rc<RefCell<Node>> =
fory.deserialize(&serialized).unwrap();
// --- Verify ---
let des_parent = deserialized.borrow();
@@ -218,8 +218,8 @@ fn test_arc_mutex_circular_reference() {
children: Vec<Arc<Mutex<Node>>>,
}
- let mut fury = Fory::default();
- fury.register::<Node>(6000);
+ let mut fory = Fory::default();
+ fory.register::<Node>(6000);
let parent = Arc::new(Mutex::new(Node {
val: 10,
@@ -242,8 +242,8 @@ fn test_arc_mutex_circular_reference() {
parent.lock().unwrap().children.push(child1.clone());
parent.lock().unwrap().children.push(child2.clone());
- let serialized = fury.serialize(&parent);
- let deserialized: Arc<Mutex<Node>> =
fury.deserialize(&serialized).unwrap();
+ let serialized = fory.serialize(&parent);
+ let deserialized: Arc<Mutex<Node>> =
fory.deserialize(&serialized).unwrap();
assert_eq!(deserialized.lock().unwrap().children.len(), 2);
for child in &deserialized.lock().unwrap().children {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]