github apache/fory v0.13.0

one day ago

Highlights

  • Dynamic Trait Object Serialization for Rust
  • Shared/Circular ownership serialization for Rust
  • Schema Forward/Backward compatibilify for Rust
  • Drop-in Replacement for Python pickle: support local function/classes/__reduce__/__getstate__ serialization
  • Schema Forward/Backward compatibilify for Python dataclass
  • Support codegen for xlang mode in java
  • Primitive array compression using SIMD
  • Compact Row Codec for Row Format
  • Schema Forward/Backward compatibilify for Go
  • Ahead-of-time codegen for golang struct serialization

Rust: First Release Highlights

This is the first Apache Fory Rust release, delivering a complete, high‑performance serialization stack. If you build Rust services or libraries, you can now use Fory natively with strong typing, performance, and schema evolution.

  • Derive-based object graph serialization via #[derive(ForyObject)]
  • Polymorphism for trait objects: Box<dyn Trait>, Rc<dyn Trait>, Arc<dyn Trait>, plus dyn Any
  • Shared and circular reference tracking: Rc/Arc and RcWeak/ArcWeak
  • Forward/backward compatible schema evolution (Compatible mode)
  • Zero-copy Row format via #[derive(ForyRow)] with selective field access
  • Thread-safe and multi-thread capable serialization (context pool)
  • Broad collection support (e.g., VecDeque, LinkedList, BTreeMap, BTreeSet, BinaryHeap)

Quick start (minimal example):

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)?;

	let user = User { name: "Alice".into(), age: 30, email: "alice@example.com".into() };
	let bytes = fory.serialize(&user)?;
	let decoded: User = fory.deserialize(&bytes)?;
	assert_eq!(user, decoded);
	Ok(())
}

Rust Benchmarks

ecommerce_data system_data

Below are serialize throughput results (TPS; higher is better) comparing Fory with JSON and Protobuf across multiple datasets and sizes.

Datatype Size Operation Fory TPS JSON TPS Protobuf TPS Fastest
company small serialize 10,063,906 761,673 896,620 fory
company medium serialize 412,507 33,835 37,590 fory
company large serialize 9,183 793 880 fory
ecommerce_data small serialize 2,350,729 206,262 256,970 fory
ecommerce_data medium serialize 59,977 4,699 5,242 fory
ecommerce_data large serialize 3,727 266 295 fory
person small serialize 13,632,522 1,345,189 1,475,035 fory
person medium serialize 3,839,656 337,610 369,031 fory
person large serialize 907,853 79,631 91,408 fory
simple_list small serialize 27,726,945 4,874,957 4,643,172 fory
simple_list medium serialize 4,770,765 401,558 397,551 fory
simple_list large serialize 606,061 41,061 44,565 fory
simple_map small serialize 22,862,369 3,888,025 2,695,999 fory
simple_map medium serialize 2,128,973 204,319 193,132 fory
simple_map large serialize 177,847 18,419 18,668 fory
simple_struct small serialize 35,729,598 10,167,045 8,633,342 fory
simple_struct medium serialize 34,988,279 9,737,098 6,433,350 fory
simple_struct large serialize 31,801,558 4,545,041 7,420,049 fory
system_data small serialize 5,382,131 468,033 569,930 fory
system_data medium serialize 174,240 11,896 14,753 fory
system_data large serialize 10,671 876 1,040 fory

Note: Results depend on hardware, dataset, and implementation versions. See the Rust guide for how to run benchmarks yourself: https://github.com/apache/fory/blob/main/rust/benches/README.md

Python: Drop‑in Replacement for pickle

pyfory now acts as a high‑performance drop‑in replacement for pickle/cloudpickle, while keeping the same simple API and adding security and performance features.

  • Serialize any Python object in Python‑native mode (xlang=False): global/local functions, lambdas, global/local classes, instance/class/static methods
  • Honors Python hooks: __getstate__, __setstate__, __reduce__, __reduce_ex__
  • Reference tracking for shared/circular graphs with ref=True
  • Pickle protocol 5 out‑of‑band buffers for zero‑copy via pickle.PickleBuffer (NumPy, Pandas, etc.)
  • Security: strict=True for registration‑based safety and DeserializationPolicy for fine‑grained control
  • Threading: ThreadSafeFory for safe multi‑thread use
  • Familiar API: dumps/loads are aliases of serialize/deserialize

Quick start:

import pyfory

# Drop-in replacement for pickle/cloudpickle
fory = pyfory.Fory(xlang=False, ref=True, strict=False)

def make_multiplier(k):
	def mul(x):
		return k * x
	return mul

binary = fory.dumps(make_multiplier(10))
assert fory.loads(binary)(3) == 30

Read more: Python Guide – https://fory.apache.org/docs/latest/python_serialization/

Features

  • feat(java): support object stream serialization for graalvm by @chaokunyang in #2464
  • refactor(java): rename abstract collection/map serializers to Map/ListLikeSerializer by @chaokunyang in #2466
  • feat(memory): add customizable MemoryAllocator interface by @adriacabeza in #2467
  • feat: Chain wheel test/build and release workflows by @esafak in #2483
  • feat(python): set default languge to python for pyfory by @chaokunyang in #2490
  • feat(python): add register api to python by @chaokunyang in #2491
  • feat(python): meta compression for python by @chaokunyang in #2504
  • feat(python): type meta encoding for python by @chaokunyang in #2509
  • feat(CI): Cache npm, add node 24, lock file by @esafak in #2523
  • feat(Rust): Implementing Type Compatible by @urlyy in #2492
  • feat(Rust): support Option in MetaFieldType se/de by @urlyy in #2528
  • feat(rust): support skipping fields bytes when deserializing in compatible mode by @urlyy in #2545
  • feat(go): add type meta encoding for meta share by @junjiexh in #2554
  • feat(Rust): Support automatic conversion between T and Option<T> when deserialize by @urlyy in #2563
  • feat(java): bean encoder implemented interfaces honor @Ignore by @stevenschlansker in #2576
  • refactor(java): refactor fory java exception hierarchical structure by @chaokunyang in #2577
  • feat(Go): Implement ahead of time codegen for fory-go serialization by @ThisingL in #2553
  • feat(java): support limit deserialization depth by @chaokunyang in #2578
  • feat(rust): add fory rust benchmark by @chaokunyang in #2583
  • perf(rust): optimize rust deserialize perf by @chaokunyang in #2584
  • feat(rust): add rust profiler for serialization by @chaokunyang in #2588
  • refactor(go): rename FieldInfo to FieldDef to avoide name collision by @junjiexh in #2594
  • feat(python): meta share mode for pyfory compatible serialization by @chaokunyang in #2593
  • feat(java/python): align java and python compatible mode serialization by @chaokunyang in #2602
  • feat(java/python): support enum xlang serialization by @chaokunyang in #2603
  • feat(Rust): support basic type se/de aligned with java by @urlyy in #2585
  • perf(python/java): Fix & optimize cross-language meta-share mode by @pandalee99 in #2601
  • feat(go): align cross-language type serialization for primitive arrays by @pandalee99 in #2610
  • feat(java): support codegen for xlang mode in java by @chaokunyang in #2613
  • feat(java): primitive array compression using SIMD by @adriacabeza in #2485
  • refactor(go): Replace globalTypeResolver with factory-based serializer registration by @ThisingL in #2615
  • feat(go): Implement compatible mode with metashare mode by @junjiexh in #2607
  • feat(java): support concurent map serialization when being updated by @chaokunyang in #2617
  • feat(java): support concurrent updates when serializing collections by @chaokunyang in #2623
  • feat(python): support limit pyfory depth by @chaokunyang in #2625
  • feat(Rust): sort fields && feat Enum && fix read/write type_info && fix type_meta en/decode by @urlyy in #2630
  • feat(python): drop-in replacement for pickle serialization by @chaokunyang in #2629
  • refactor(java): refactor type resolver by @chaokunyang in #2640
  • feat(java): support type converters for comaptible mode by @chaokunyang in #2641
  • refactor(java/python): refine collection header bitmap by @chaokunyang in #2642
  • feat(go): metashare mode support collection and map and nested object by @junjiexh in #2643
  • feat(go): Add slice and map support to fory-go codegen serialization by @ThisingL in #2638
  • refactor(go): Change codegen annotation from //fory:gen to //fory:generate by @ThisingL in #2648
  • feat(rust): support Map and register_by_name by @urlyy in #2649
  • feat(java): support graalvm 25 by @chaokunyang in #2652
  • feat(java): support deserialize not registered/exsited class/fields for xlang compatible mode by @chaokunyang in #2655
  • refactor(Rust): Refactor compile-time code & fix named_enum & fix skip enum by @urlyy in #2657
  • feat(python): support local py class serialization by @chaokunyang in #2665
  • refactor(go): refine collection header bitmap by @junjiexh in #2656
  • feat(python): support class methods serialization by @chaokunyang in #2670
  • refactor(go): refine collection header bitmap in codegen by @ThisingL in #2676
  • feat(rust): support box serde for rust by @chaokunyang in #2677
  • feat(rust): support reference tracking for rust Rc/Arc by @chaokunyang in #2678
  • feat(python): refine python serialization api by @chaokunyang in #2673
  • refactor(Rust): Refine api name by @urlyy in #2671
  • feat(rust): support rust dyn trait object serialization by @chaokunyang in #2691
  • feat(rust): support dyn any trait object serialization for box/arc/rc by @chaokunyang in #2704
  • feat(rust): support shared reference tracking for arc/rc<dyn T> by @chaokunyang in #2707
  • feat(rust): avoid downcast method of multiple trait objects in same module conflict by @chaokunyang in #2708
  • feat(rust): add deref to arc/rc wrapper by @chaokunyang in #2709
  • refactor(rust): unify rc/arc wrapper macro arms into one function by @chaokunyang in #2711
  • perf(Rust): Use SIMD to se/de string by @urlyy in #2716
  • feat(Rust): named_xx se/de && ext se/de && add unittest by @urlyy in #2712
  • feat(rust): support RcWeak/ArcWeak for circular reference tracking by @chaokunyang in #2714
  • feat(rust): support limit max dyn depth by @chaokunyang in #2730
  • feat(Rust): Unroll fields loop & Add a feature for this by @urlyy in #2724
  • feat(python): make fory out-of-band serialization compatible with pickle5 by @chaokunyang in #2732
  • refactor(go): Replace legacy RegisterTagType api call by @junjiexh in #2696
  • feat(python): add thread safe fory by @chaokunyang in #2735
  • feat(rust): support VecDeque/LinkedList serialization by @chaokunyang in #2741
  • feat(rust): support btreemap serialization by @chaokunyang in #2743
  • feat(rust): support btree set and binary heap serialization by @chaokunyang in #2744
  • feat(Rust): support context_pool to reduce context allocation && support se/de in multi-thread by @urlyy in #2737
  • feat(ci): cache Bazel binary in Python CI workflow by @SanyamSuyal in #2745
  • feat(rust): rewrite fory derive macro for smaller and faster generated code using compile-time fields sort algorithm by @chaokunyang in #2749
  • feat(ci): add maven cache to ci for faster build by @chaokunyang in #2751
  • feat(rust): fast fory_read_compatible macro to use match by assigned field id by @chaokunyang in #2758
  • refactor(rust): use compatible bool instead of enum to simplify API by @chaokunyang in #2763
  • feat(rust): query type meta from parsed cache to speed up deserialization by @chaokunyang in #2764
  • feat(java): introduce Compact Row Codec by @stevenschlansker in #2414
  • feat(go): Add pointer field test for meta share mode by @junjiexh in #2674
  • feat(rust): make Serializer api to return Result && replace panic/expect/assert/unwrap with Result by @urlyy in #2765
  • feat(rust): refactor rust serialization system by @chaokunyang in #2774
  • feat(python): support optional typehint for dataclass fields by @chaokunyang in #2766
  • feat(rust): dynamic rust serializer system by @chaokunyang in #2778
  • feat(rust): use rc instead of arc for type meta for faster performance by @chaokunyang in #2782
  • feat(python): support dataclass compatible mode for python native mode by @chaokunyang in #2784
  • feat(java): support deserialize non exist enum variant to default by @chaokunyang in #2787
  • feat(go): update codegen field sorting to generate smaller and faster code by @ThisingL in #2779
  • feat(rust): make type meta resolve return type info directly by @chaokunyang in #2789
  • perf(Rust): remove clone()/to_owned() on MetaString/MetaStringBytes in MetaStringResolver to improve performance && fix xlang test by @urlyy in #2791
  • feat(rust): support static struct version hash check for rust by @chaokunyang in #2793
  • feat(rust): support profile all data types in rust benchmark by @chaokunyang in #2801
  • perf(rust): optimize rust small string/struct read/write performance by @chaokunyang in #2803
  • perf(rust): optimize rust performance by remove copy simd and add more inline hints by @chaokunyang in #2807
  • perf(rust): always use utf8 when writing string by @chaokunyang in #2809
  • feat(python): add deserialization policy for more fine-grained control and audit deserialization behaviour by @chaokunyang in #2811
  • perf(Rust): Enchance performance by @theweipeng in #2810
  • feat(Rust): Support serialize_to by @theweipeng in #2822
  • feat(rust): lazy build typeinfo for rust to avoid nested struct register deps by @chaokunyang in #2824
  • perf(Rust): Refactor reader by @theweipeng in #2826
  • perf(python): optimize pyfory perf by @chaokunyang in #2829

Bug Fix

Other Improvements

New Contributors

Full Changelog: v0.12.3...v0.13.0-rc2

Don't miss a new fory release

NewReleases is sending notifications on new releases.