Basic Serialization
This page covers basic object graph serialization and supported types.
Object Graph Serialization
Apache Fory™ provides automatic serialization of complex object graphs, preserving the structure and relationships between objects. The #[derive(ForyStruct)] macro generates efficient serialization code at compile time, eliminating runtime overhead.
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
use fory::{Fory, Error};
use fory::ForyStruct;
use std::collections::HashMap;
#[derive(ForyStruct, Debug, PartialEq)]
struct Person {
name: String,
age: i32,
address: Address,
hobbies: Vec<String>,
metadata: HashMap<String, String>,
}
#[derive(ForyStruct, Debug, PartialEq)]
struct Address {
street: String,
city: String,
country: String,
}
let mut fory = Fory::builder().xlang(true).build();
fory.register_by_name::<Address>("example", "Address").unwrap();
fory.register_by_name::<Person>("example", "Person").unwrap();
let person = Person {
name: "John Doe".to_string(),
age: 30,
address: Address {
street: "123 Main St".to_string(),
city: "New York".to_string(),
country: "USA".to_string(),
},
hobbies: vec!["reading".to_string(), "coding".to_string()],
metadata: HashMap::from([
("role".to_string(), "developer".to_string()),
]),
};
let bytes = fory.serialize(&person).unwrap();
let decoded: Person = fory.deserialize(&bytes)?;
assert_eq!(person, decoded);
Supported Types
Primitive Types
| Rust Type | Description |
|---|---|
bool | Boolean |
i8, i16, i32, i64 | Signed integers |
f32, f64 | Floating point |
BFloat16 | 16-bit brain floating point |
String | UTF-8 string |
Collections
| Rust Type | Description |
|---|---|
Vec<T> | Dynamic array |
VecDeque<T> | Double-ended queue |
LinkedList<T> | Doubly-linked list |
HashMap<K, V> | Hash map |
BTreeMap<K, V> | Ordered map |
HashSet<T> | Hash set |
BTreeSet<T> | Ordered set |
BinaryHeap<T> | Binary heap |
Option<T> | Optional value |
Vec<BFloat16> is the dense carrier when the schema is array<bfloat16>.
Smart Pointers
| Rust Type | Description |
|---|---|
Box<T> | Heap allocation |
Rc<T> | Reference counting (shared refs tracked) |
Arc<T> | Thread-safe reference counting (shared refs tracked) |
RcWeak<T> | Weak reference to Rc<T> (breaks circular refs) |
ArcWeak<T> | Weak reference to Arc<T> (breaks circular refs) |
RefCell<T> | Interior mutability (runtime borrow checking) |
Mutex<T> | Thread-safe interior mutability |
Date and Time
| Rust Type | Description |
|---|---|
Date | Date without timezone, stored as epoch days |
Timestamp | Point in time, stored as epoch seconds and nanos |
Duration | Signed duration, stored as seconds and normalized nanos |
The built-in carriers expose dependency-free constructors, accessors, conversions, and checked arithmetic:
use fory::{Date, Duration, Timestamp};
let date = Date::from_epoch_days(19_782);
assert_eq!(date.checked_add_days(1)?.epoch_days(), 19_783);
let timestamp = Timestamp::from_epoch_millis(-1);
assert_eq!(timestamp.to_epoch_millis()?, -1);
let duration = Duration::from_parts(1, 1_500_000_000)?;
assert_eq!(duration.to_millis()?, 2_500);
let later = timestamp.checked_add_duration(duration)?;
chrono::NaiveDate, chrono::NaiveDateTime, and chrono::Duration are supported when the Rust
chrono feature is enabled:
[dependencies]
fory = { version = "1.0.0", features = ["chrono"] }
Custom Types
| Macro | Description |
|---|---|
#[derive(ForyStruct)] | Object graph serialization |
#[derive(ForyRow)] | Row-based serialization |
Serialization APIs
use fory::{Fory, Reader};
let mut fory = Fory::builder().xlang(true).build();
fory.register::<MyStruct>(1)?;
let obj = MyStruct { /* ... */ };
// Basic serialize/deserialize
let bytes = fory.serialize(&obj)?;
let decoded: MyStruct = fory.deserialize(&bytes)?;
// Serialize to existing buffer
let mut buf: Vec<u8> = vec![];
fory.serialize_to(&mut buf, &obj)?;
// Deserialize from reader
let mut reader = Reader::new(&buf);
let decoded: MyStruct = fory.deserialize_from(&mut reader)?;
Performance Tips
- Zero-Copy Deserialization: Row format enables direct memory access without copying
- Buffer Pre-allocation: Minimizes memory allocations during serialization
- Compact Encoding: Variable-length encoding for space efficiency
- Little-Endian: Optimized for modern CPU architectures
- Reference Deduplication: Shared objects serialized only once
Related Topics
- Type Registration - Registering types
- References - Shared and circular references
- Custom Serializers - Manual serialization