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 version: RefCell<u64>,
14}
15
16static VERSION: AtomicU64 = AtomicU64::new(0);
17
18impl<T> Cache<T> {
19 pub fn new() -> Self {
21 Cache {
22 group: Group::singleton(),
23 state: RefCell::new(State::Empty { previous: None }),
24 version: RefCell::new(VERSION.load(atomic::Ordering::Relaxed)),
25 }
26 }
27
28 pub fn with_group(group: Group) -> Self {
35 assert!(
36 !group.is_singleton(),
37 "The group {group:?} cannot be shared!"
38 );
39
40 Cache {
41 group,
42 state: RefCell::new(State::Empty { previous: None }),
43 version: RefCell::new(VERSION.load(atomic::Ordering::Relaxed)),
44 }
45 }
46
47 pub fn group(&self) -> Group {
49 self.group
50 }
51
52 pub fn put(&self, value: T) {
58 *self.state.borrow_mut() = State::Filled { current: value };
59 }
60
61 pub fn state(&self) -> &RefCell<State<T>> {
63 let version = VERSION.load(atomic::Ordering::Relaxed);
64
65 if *self.version.borrow() != version {
66 *self.state.borrow_mut() = State::Empty { previous: None };
67 let _ = self.version.replace(version);
68 }
69
70 &self.state
71 }
72
73 pub fn clear(&self) {
75 let mut state = self.state.borrow_mut();
76
77 let previous = mem::replace(&mut *state, State::Empty { previous: None });
78
79 let previous = match previous {
80 State::Empty { previous } => previous,
81 State::Filled { current } => Some(current),
82 };
83
84 *state = State::Empty { previous };
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
95pub struct Group {
96 id: u64,
97 is_singleton: bool,
98}
99
100impl Group {
101 pub fn unique() -> Self {
103 static NEXT: AtomicU64 = AtomicU64::new(0);
104
105 Self {
106 id: NEXT.fetch_add(1, atomic::Ordering::Relaxed),
107 is_singleton: false,
108 }
109 }
110
111 pub fn is_singleton(self) -> bool {
121 self.is_singleton
122 }
123
124 fn singleton() -> Self {
125 Self {
126 is_singleton: true,
127 ..Self::unique()
128 }
129 }
130}
131
132impl<T> fmt::Debug for Cache<T>
133where
134 T: fmt::Debug,
135{
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 use std::ops::Deref;
138
139 let state = self.state.borrow();
140
141 match state.deref() {
142 State::Empty { previous } => {
143 write!(f, "Cache::Empty {{ previous: {previous:?} }}")
144 }
145 State::Filled { current } => {
146 write!(f, "Cache::Filled {{ current: {current:?} }}")
147 }
148 }
149 }
150}
151
152impl<T> Default for Cache<T> {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub enum State<T> {
161 Empty {
163 previous: Option<T>,
165 },
166 Filled {
168 current: T,
170 },
171}
172
173pub trait Cached: Sized {
175 type Cache: Clone;
177
178 fn load(cache: &Self::Cache) -> Self;
182
183 fn cache(self, group: Group, previous: Option<Self::Cache>) -> Self::Cache;
187}
188
189#[cfg(debug_assertions)]
190impl Cached for () {
191 type Cache = ();
192
193 fn load(_cache: &Self::Cache) -> Self {}
194
195 fn cache(self, _group: Group, _previous: Option<Self::Cache>) -> Self::Cache {}
196}
197
198pub fn invalidate_all() {
200 let _ = VERSION.fetch_add(1, atomic::Ordering::Relaxed);
201}