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 = mem::replace(&mut *state, State::Empty { previous: None });
66
67 let previous = match previous {
68 State::Empty { previous } => previous,
69 State::Filled { current } => Some(current),
70 };
71
72 *state = State::Empty { previous };
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
83pub struct Group {
84 id: u64,
85 is_singleton: bool,
86}
87
88impl Group {
89 pub fn unique() -> Self {
91 static NEXT: AtomicU64 = AtomicU64::new(0);
92
93 Self {
94 id: NEXT.fetch_add(1, atomic::Ordering::Relaxed),
95 is_singleton: false,
96 }
97 }
98
99 pub fn is_singleton(self) -> bool {
109 self.is_singleton
110 }
111
112 fn singleton() -> Self {
113 Self {
114 is_singleton: true,
115 ..Self::unique()
116 }
117 }
118}
119
120impl<T> fmt::Debug for Cache<T>
121where
122 T: fmt::Debug,
123{
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 use std::ops::Deref;
126
127 let state = self.state.borrow();
128
129 match state.deref() {
130 State::Empty { previous } => {
131 write!(f, "Cache::Empty {{ previous: {previous:?} }}")
132 }
133 State::Filled { current } => {
134 write!(f, "Cache::Filled {{ current: {current:?} }}")
135 }
136 }
137 }
138}
139
140impl<T> Default for Cache<T> {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148pub enum State<T> {
149 Empty {
151 previous: Option<T>,
153 },
154 Filled {
156 current: T,
158 },
159}
160
161pub trait Cached: Sized {
163 type Cache: Clone;
165
166 fn load(cache: &Self::Cache) -> Self;
170
171 fn cache(self, group: Group, previous: Option<Self::Cache>) -> Self::Cache;
175}
176
177#[cfg(debug_assertions)]
178impl Cached for () {
179 type Cache = ();
180
181 fn load(_cache: &Self::Cache) -> Self {}
182
183 fn cache(self, _group: Group, _previous: Option<Self::Cache>) -> Self::Cache {}
184}