1#![doc = include_str!("../README.md")]
2#![no_std]
3
4extern crate alloc;
5
6use alloc::{
7 boxed::Box,
8 rc::{Rc, Weak},
9 vec,
10};
11use core::{
12 cell::{Cell, RefCell},
13 sync::atomic::AtomicUsize,
14};
15
16pub struct Store {
18 root: Node,
19 generation: usize,
20 store_id: usize,
21}
22
23impl Store {
24 #[allow(clippy::new_without_default)]
26 pub fn new() -> Self {
27 static STORE_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
28 Store {
29 root: Node(Rc::new(Cell::new(NodeData::Mem))),
30 generation: 0,
31 store_id: STORE_ID_COUNTER.fetch_add(1, core::sync::atomic::Ordering::SeqCst),
32 }
33 }
34
35 pub fn set<T: 'static + Clone>(&mut self, r: &Ref<T>, value: T) {
37 if self.generation == r.0.generation.get() {
38 r.0.value.replace(value);
39 } else {
40 let new_root = Node(Rc::new(Cell::new(NodeData::Mem)));
41 let old_root = core::mem::replace(&mut self.root, new_root.clone());
42 old_root.0.replace(NodeData::Diff(Box::new(Diff {
43 r: r.clone(),
44 value: r.0.value.replace(value),
45 generation: r.0.generation.replace(self.generation),
46 parent: new_root,
47 })));
48 }
49 }
50
51 pub fn capture(&mut self) -> Snapshot {
53 let snap = Snapshot {
54 root: self.root.clone(),
55 generation: self.generation,
56 store_id: self.store_id,
57 };
58 self.generation += 1;
59 snap
60 }
61
62 pub fn restore(&mut self, snap: Snapshot) {
68 if snap.store_id != self.store_id {
69 panic!("Cannot restore from a snapshot from a different store");
70 }
71 if let NodeData::Mem = unsafe { &*snap.root.0.as_ptr() } {
73 return;
74 }
75 reroot(&snap.root);
76 self.root = snap.root;
77 self.generation = snap.generation + 1;
78 }
79}
80
81pub struct Ref<T>(Rc<RefInner<T>>);
83
84impl<T> Ref<T> {
85 pub fn new(value: T) -> Self {
87 Ref(Rc::new(RefInner {
88 value: RefCell::new(value),
89 generation: Cell::new(0),
90 }))
91 }
92
93 pub fn get(&self) -> T
95 where
96 T: Clone,
97 {
98 self.borrow().clone()
99 }
100
101 pub fn borrow(&self) -> core::cell::Ref<'_, T> {
103 self.0.value.borrow()
104 }
105
106 pub fn set(&self, store: &mut Store, value: T)
108 where
109 T: Clone + 'static,
110 {
111 store.set(self, value);
112 }
113
114 pub fn downgrade(this: &Self) -> WeakRef<T> {
116 WeakRef(Rc::downgrade(&this.0))
117 }
118}
119
120impl<T> Clone for Ref<T> {
121 fn clone(&self) -> Self {
122 Ref(Rc::clone(&self.0))
123 }
124}
125
126struct RefInner<T> {
127 value: RefCell<T>,
128 generation: Cell<usize>,
129}
130
131pub struct WeakRef<T>(Weak<RefInner<T>>);
133
134impl<T> WeakRef<T> {
135 pub fn upgrade(&self) -> Option<Ref<T>> {
137 self.0.upgrade().map(Ref)
138 }
139}
140
141impl<T> Clone for WeakRef<T> {
142 fn clone(&self) -> Self {
143 WeakRef(self.0.clone())
144 }
145}
146
147#[derive(Clone)]
149pub struct Snapshot {
150 root: Node,
151 generation: usize,
152 store_id: usize,
153}
154
155#[derive(Clone)]
159struct Node(Rc<Cell<NodeData>>);
160
161enum NodeData {
162 Mem,
165 Diff(Box<dyn ReRoot>),
167}
168
169struct Diff<T> {
170 r: Ref<T>,
171 value: T,
173 generation: usize,
175 parent: Node,
177}
178
179trait ReRoot {
182 fn reroot(&self, this: Node, parent: &Node);
183 fn parent(&self) -> &Node;
184}
185
186impl<T: 'static + Clone> ReRoot for Diff<T> {
187 fn reroot(&self, this: Node, parent: &Node) {
190 assert!(Rc::ptr_eq(&self.parent.0, &parent.0));
191 parent.0.replace(NodeData::Diff(Box::new(Diff {
192 r: self.r.clone(),
193 value: self.r.0.value.replace(self.value.clone()),
194 generation: self.r.0.generation.replace(self.generation),
195 parent: this,
196 })));
197 }
198
199 fn parent(&self) -> &Node {
200 &self.parent
201 }
202}
203
204fn reroot(mut n: &Node) {
208 let mut stack = vec![];
209 loop {
210 match unsafe { &*n.0.as_ptr() } {
212 NodeData::Mem => break,
213 NodeData::Diff(diff) => {
214 stack.push((diff, n));
215 n = diff.parent();
216 }
217 }
218 }
219 while let Some((diff, node)) = stack.pop() {
220 diff.reroot(node.clone(), n);
221 n = node;
222 }
223 n.0.replace(NodeData::Mem);
224}