Skip to main content
Version: 1.0

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 TypeDescription
boolBoolean
i8, i16, i32, i64Signed integers
f32, f64Floating point
BFloat1616-bit brain floating point
StringUTF-8 string

Collections​

Rust TypeDescription
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 TypeDescription
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 TypeDescription
DateDate without timezone, stored as epoch days
TimestampPoint in time, stored as epoch seconds and nanos
DurationSigned 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​

MacroDescription
#[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