title: Shared & Circular References sidebar_position: 5 id: references license: | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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:
RcWeak<T> and ArcWeak<T> to break cyclesuse fory::Fory; use std::rc::Rc; let fory = Fory::default(); // Create a shared value let shared = Rc::new(String::from("shared_value")); // Reference it multiple times let data = vec![shared.clone(), shared.clone(), shared.clone()]; // The shared value is serialized only once let bytes = fory.serialize(&data); let decoded: Vec<Rc<String>> = fory.deserialize(&bytes)?; // Verify reference identity is preserved assert_eq!(decoded.len(), 3); assert_eq!(*decoded[0], "shared_value"); // All three Rc pointers point to the same object assert!(Rc::ptr_eq(&decoded[0], &decoded[1])); assert!(Rc::ptr_eq(&decoded[1], &decoded[2]));
For thread-safe shared references, use Arc<T>:
use fory::Fory; use std::sync::Arc; 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]));
To serialize circular references like parent-child relationships or doubly-linked structures, use RcWeak<T> or ArcWeak<T> to break the cycle.
How it works:
Nulluse fory::{Fory, Error}; use fory::ForyObject; use fory::RcWeak; use std::rc::Rc; use std::cell::RefCell; #[derive(ForyObject, Debug)] struct Node { value: i32, parent: RcWeak<RefCell<Node>>, children: Vec<Rc<RefCell<Node>>>, } let mut fory = Fory::default(); fory.register::<Node>(2000); // Build a parent-child tree let parent = Rc::new(RefCell::new(Node { value: 1, parent: RcWeak::new(), children: vec![], })); let child1 = Rc::new(RefCell::new(Node { value: 2, parent: RcWeak::from(&parent), children: vec![], })); let child2 = Rc::new(RefCell::new(Node { value: 3, parent: RcWeak::from(&parent), children: vec![], })); parent.borrow_mut().children.push(child1.clone()); parent.borrow_mut().children.push(child2.clone()); // Serialize and deserialize the circular structure let bytes = fory.serialize(&parent); let decoded: Rc<RefCell<Node>> = fory.deserialize(&bytes)?; // Verify the circular relationship assert_eq!(decoded.borrow().children.len(), 2); for child in &decoded.borrow().children { let upgraded_parent = child.borrow().parent.upgrade().unwrap(); assert!(Rc::ptr_eq(&decoded, &upgraded_parent)); }
use fory::{Fory, Error}; use fory::ForyObject; use fory::ArcWeak; use std::sync::{Arc, Mutex}; #[derive(ForyObject)] struct Node { val: i32, parent: ArcWeak<Mutex<Node>>, children: Vec<Arc<Mutex<Node>>>, } let mut fory = Fory::default(); fory.register::<Node>(6000); let parent = Arc::new(Mutex::new(Node { val: 10, parent: ArcWeak::new(), children: vec![], })); let child1 = Arc::new(Mutex::new(Node { val: 20, parent: ArcWeak::from(&parent), children: vec![], })); let child2 = Arc::new(Mutex::new(Node { val: 30, parent: ArcWeak::from(&parent), children: vec![], })); parent.lock().unwrap().children.push(child1.clone()); parent.lock().unwrap().children.push(child2.clone()); 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 { let upgraded_parent = child.lock().unwrap().parent.upgrade().unwrap(); assert!(Arc::ptr_eq(&decoded, &upgraded_parent)); }
| Type | Description |
|---|---|
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 with runtime borrow checking |
Mutex<T> | Thread-safe interior mutability |