1use std::cell::RefCell;
3use std::fmt;
4use std::mem;
5use std::sync::atomic::{self, AtomicU64};
6
7pub struct Cache<T> {
11 group: Group,
12 state: RefCell<State<T>>,
13}
14
15impl<T> Cache<T> {
16 pub fn new() -> Self {
18 Cache {
19 group: Group::singleton(),
20 state: RefCell::new(State::Empty { previous: None }),
21 }
22 }
23
24 pub fn with_group(group: Group) -> Self {
31 assert!(
32 !group.is_singleton(),
33 "The group {group:?} cannot be shared!"
34 );
35
36 Cache {
37 group,
38 state: RefCell::new(State::Empty { previous: None }),
39 }
40 }
41
42 pub fn group(&self) -> Group {
44 self.group
45 }
46
47 pub fn put(&self, value: T) {
53 *self.state.borrow_mut() = State::Filled { current: value };
54 }
55
56 pub fn state(&self) -> &RefCell<State<T>> {
58 &self.state
59 }
60
61 pub fn clear(&self) {
63 let mut state = self.state.borrow_mut();
64
65 let previous =
66 mem::replace(&mut *state, State::Empty { previous: None });
67
68 let previous = match previous {
69 State::Empty { previous } => previous,
70 State::Filled { current } => Some(current),
71 };
72
73 *state = State::Empty { previous };
74 }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
84pub struct Group {
85 id: u64,
86 is_singleton: bool,
87}
88
89impl Group {
90 pub fn unique() -> Self {
92 static NEXT: AtomicU64 = AtomicU64::new(0);
93
94 Self {
95 id: NEXT.fetch_add(1, atomic::Ordering::Relaxed),
96 is_singleton: false,
97 }
98 }
99
100 pub fn is_singleton(self) -> bool {
110 self.is_singleton
111 }
112
113 fn singleton() -> Self {
114 Self {
115 is_singleton: true,
116 ..Self::unique()
117 }
118 }
119}
120
121impl<T> fmt::Debug for Cache<T>
122where
123 T: fmt::Debug,
124{
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 use std::ops::Deref;
127
128 let state = self.state.borrow();
129
130 match state.deref() {
131 State::Empty { previous } => {
132 write!(f, "Cache::Empty {{ previous: {previous:?} }}")
133 }
134 State::Filled { current } => {
135 write!(f, "Cache::Filled {{ current: {current:?} }}")
136 }
137 }
138 }
139}
140
141impl<T> Default for Cache<T> {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149pub enum State<T> {
150 Empty {
152 previous: Option<T>,
154 },
155 Filled {
157 current: T,
159 },
160}
161
162pub trait Cached: Sized {
164 type Cache: Clone;
166
167 fn load(cache: &Self::Cache) -> Self;
171
172 fn cache(self, group: Group, previous: Option<Self::Cache>) -> Self::Cache;
176}
177
178#[cfg(debug_assertions)]
179impl Cached for () {
180 type Cache = ();
181
182 fn load(_cache: &Self::Cache) -> Self {}
183
184 fn cache(
185 self,
186 _group: Group,
187 _previous: Option<Self::Cache>,
188 ) -> Self::Cache {
189 }
190}