1use core::future::Future;
11use core::pin::Pin;
12use core::task::{Context, Poll};
13use std::cell::{Cell, RefCell};
14use std::collections::{BTreeMap, BTreeSet};
15use std::rc::Rc;
16
17use super::{Entry, Name, Residency, Storage};
18use crate::lock::{Claim, Holding};
19use crate::record::WallTime;
20
21#[derive(Clone, Debug)]
27pub struct Memory(Rc<Held>);
28
29#[derive(Debug)]
30struct Held {
31 name: RefCell<Name>,
32 residency: Residency,
33 pace: Pace,
34 files: RefCell<BTreeMap<String, Vec<u8>>>,
35 dirs: RefCell<BTreeSet<String>>,
36 refused: RefCell<Option<Entry>>,
37 own_lock: Cell<Option<bool>>,
40 reads: Cell<usize>,
41 wrote: RefCell<Vec<Entry>>,
42}
43
44#[derive(Clone, Copy, PartialEq, Eq, Debug)]
46enum Pace {
47 Ready,
48 Deferred,
49}
50
51impl Memory {
52 pub fn new(name: &str) -> Self {
54 Self::with(name, Residency::Lazy, Pace::Ready)
55 }
56
57 pub fn resident(name: &str) -> Self {
60 Self::with(name, Residency::Resident, Pace::Ready)
61 }
62
63 pub fn deferred(name: &str) -> Self {
69 let deferred = Self::with(name, Residency::Resident, Pace::Deferred);
70 deferred.0.own_lock.set(Some(false));
71 deferred
72 }
73
74 #[must_use]
77 pub fn refusing(self, at: Entry) -> Self {
78 *self.0.refused.borrow_mut() = Some(at);
79 self
80 }
81
82 fn with(name: &str, residency: Residency, pace: Pace) -> Self {
83 Self(Rc::new(Held {
84 name: RefCell::new(Name::new(name).unwrap_or_else(|| Name(name.to_owned()))),
85 residency,
86 pace,
87 files: RefCell::default(),
88 dirs: RefCell::default(),
89 refused: RefCell::default(),
90 own_lock: Cell::new(None),
91 reads: Cell::new(0),
92 wrote: RefCell::default(),
93 }))
94 }
95
96 pub fn reads(&self) -> usize {
99 self.0.reads.get()
100 }
101
102 pub fn wrote(&self) -> Vec<Entry> {
104 self.0.wrote.borrow().clone()
105 }
106
107 async fn paced(&self) {
110 if let Pace::Deferred = self.0.pace {
111 Wait(false).await;
112 }
113 }
114
115 fn read_one(&self) {
116 self.0.reads.set(self.0.reads.get() + 1);
117 }
118
119 fn wrote_one(&self, at: &Entry) -> std::io::Result<()> {
120 if self.0.refused.borrow().as_ref() == Some(at) {
121 return Err(std::io::Error::new(
122 std::io::ErrorKind::PermissionDenied,
123 format!("{at} is an entry this map refuses to write"),
124 ));
125 }
126 self.0.wrote.borrow_mut().push(at.clone());
127 Ok(())
128 }
129}
130
131struct Wait(bool);
133
134impl Future for Wait {
135 type Output = ();
136
137 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
138 if self.0 {
139 return Poll::Ready(());
140 }
141 self.0 = true;
142 cx.waker().wake_by_ref();
143 Poll::Pending
144 }
145}
146
147impl Default for Memory {
148 fn default() -> Self {
149 Self::new("session.bwx")
150 }
151}
152
153fn within<'a>(dir: &str, key: &'a str) -> Option<&'a str> {
156 let rest = if dir.is_empty() {
157 key
158 } else {
159 key.strip_prefix(dir)?.strip_prefix('/')?
160 };
161 (!rest.contains('/')).then_some(rest)
162}
163
164impl Storage for Memory {
165 fn name(&self) -> Name {
166 self.0.name.borrow().clone()
167 }
168
169 fn names(&self, at: &Entry) -> String {
170 format!("{at} of {}", self.0.name.borrow())
171 }
172
173 fn residency(&self) -> Residency {
174 self.0.residency
175 }
176
177 async fn read<'a>(&'a self, at: &'a Entry) -> std::io::Result<Option<Vec<u8>>> {
178 self.paced().await;
179 self.read_one();
180 Ok(self.0.files.borrow().get(at.as_str()).cloned())
181 }
182
183 async fn exists<'a>(&'a self, at: &'a Entry) -> std::io::Result<bool> {
184 self.paced().await;
185 self.read_one();
186 Ok(self.0.files.borrow().contains_key(at.as_str()))
187 }
188
189 async fn write<'a>(&'a self, at: &'a Entry, bytes: &'a [u8]) -> std::io::Result<()> {
190 self.paced().await;
191 self.wrote_one(at)?;
192 self.0
193 .files
194 .borrow_mut()
195 .insert(at.as_str().to_owned(), bytes.to_vec());
196 Ok(())
197 }
198
199 async fn append<'a>(&'a self, at: &'a Entry, bytes: &'a [u8]) -> std::io::Result<()> {
200 self.paced().await;
201 self.wrote_one(at)?;
202 self.0
203 .files
204 .borrow_mut()
205 .entry(at.as_str().to_owned())
206 .or_default()
207 .extend_from_slice(bytes);
208 Ok(())
209 }
210
211 async fn truncate<'a>(&'a self, at: &'a Entry, len: u64) -> std::io::Result<()> {
212 self.paced().await;
213 self.wrote_one(at)?;
214 if let Some(bytes) = self.0.files.borrow_mut().get_mut(at.as_str()) {
215 bytes.truncate(len as usize);
216 }
217 Ok(())
218 }
219
220 async fn list<'a>(&'a self, dir: &'a Entry) -> std::io::Result<Vec<String>> {
221 self.paced().await;
222 self.read_one();
223 let mut names: Vec<String> = self
224 .0
225 .dirs
226 .borrow()
227 .iter()
228 .filter_map(|key| within(dir.as_str(), key))
229 .map(ToOwned::to_owned)
230 .collect();
231 names.extend(
232 self.0
233 .files
234 .borrow()
235 .keys()
236 .filter_map(|key| within(dir.as_str(), key))
237 .map(ToOwned::to_owned),
238 );
239 Ok(names)
240 }
241
242 async fn remove<'a>(&'a self, at: &'a Entry) -> std::io::Result<()> {
243 self.paced().await;
244 let gone = self.0.files.borrow_mut().remove(at.as_str()).is_some()
245 || self.0.dirs.borrow_mut().remove(at.as_str());
246 if gone {
247 return Ok(());
248 }
249 Err(std::io::Error::from(std::io::ErrorKind::NotFound))
250 }
251
252 async fn create_dir<'a>(&'a self, dir: &'a Entry) -> std::io::Result<()> {
253 self.paced().await;
254 if !dir.as_str().is_empty() {
255 self.0.dirs.borrow_mut().insert(dir.as_str().to_owned());
256 }
257 Ok(())
258 }
259
260 async fn rename<'a>(&'a mut self, to: &'a Name) -> std::io::Result<()> {
261 self.paced().await;
262 *self.0.name.borrow_mut() = to.clone();
263 Ok(())
264 }
265
266 async fn discard(&self) -> std::io::Result<()> {
267 self.paced().await;
268 self.0.files.borrow_mut().clear();
269 self.0.dirs.borrow_mut().clear();
270 Ok(())
271 }
272
273 async fn claim(&self, now: WallTime) -> std::io::Result<Claim> {
274 self.paced().await;
275 match self.0.own_lock.get() {
276 None => crate::lock::claim(self, now).await,
277 Some(true) => Ok(Claim::Held(Holding::Elsewhere)),
278 Some(false) => {
279 self.0.own_lock.set(Some(true));
280 Ok(Claim::Taken)
281 }
282 }
283 }
284
285 fn release(&self) {
286 match self.0.own_lock.get() {
287 None => crate::lock::release(self),
288 Some(_) => self.0.own_lock.set(Some(false)),
289 }
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296 use crate::storage::ready_now;
297
298 const MANIFEST: Entry = Entry::fixed("manifest.jsonl");
299
300 #[test]
301 fn entries_round_trip_and_list_under_the_directory_that_holds_them() {
302 let memory = Memory::new("doc.bwx");
303 ready_now(memory.create_dir(&Entry::fixed("revs"))).expect("the directory");
304 ready_now(memory.append(&MANIFEST, b"one\n")).expect("a row");
305 ready_now(memory.append(&MANIFEST, b"two\n")).expect("another row");
306 let rev = Entry::under("revs", "000001.json");
307 ready_now(memory.write(&rev, b"a document")).expect("a rev");
308
309 assert_eq!(
310 ready_now(memory.read(&MANIFEST)).expect("it reads back"),
311 Some(b"one\ntwo\n".to_vec()),
312 );
313 let mut root = ready_now(memory.list(&Entry::ROOT)).expect("it lists");
314 root.sort();
315 assert_eq!(root, ["manifest.jsonl", "revs"]);
316 assert_eq!(
317 ready_now(memory.list(&Entry::fixed("revs"))).expect("it lists"),
318 ["000001.json"],
319 "a nested entry was listed at the root, or not under its directory",
320 );
321
322 ready_now(memory.truncate(&MANIFEST, 4)).expect("the truncate");
323 assert_eq!(
324 ready_now(memory.read(&MANIFEST)).expect("it reads back"),
325 Some(b"one\n".to_vec()),
326 );
327 ready_now(memory.remove(&rev)).expect("the rev goes");
328 assert_eq!(
329 ready_now(memory.read(&rev)).expect("the read answers"),
330 None
331 );
332 }
333
334 #[test]
335 fn a_map_is_read_as_it_is_asked_and_can_be_asked_to_be_read_whole() {
336 assert_eq!(Memory::new("a").residency(), Residency::Lazy);
337 assert_eq!(Memory::resident("a").residency(), Residency::Resident);
338 assert_eq!(Memory::deferred("a").residency(), Residency::Resident);
339 }
340
341 #[test]
344 fn a_clone_is_the_same_map_and_not_a_copy_of_it() {
345 let first = Memory::new("doc.bwx");
346 let second = first.clone();
347 ready_now(first.write(&MANIFEST, b"a row\n")).expect("the write lands");
348
349 assert_eq!(
350 ready_now(second.read(&MANIFEST)).expect("it reads back"),
351 Some(b"a row\n".to_vec()),
352 );
353 }
354
355 #[test]
358 fn a_deferred_map_refuses_to_be_read_as_if_it_were_ready() {
359 let deferred = Memory::deferred("doc.bwx");
360 assert_eq!(
361 ready_now(deferred.read(&MANIFEST))
362 .expect_err("a deferred future must not resolve in one poll")
363 .kind(),
364 std::io::ErrorKind::WouldBlock,
365 );
366 assert_eq!(
367 crate::fixture::block_on(deferred.read(&MANIFEST)).expect("driven, it answers"),
368 None,
369 );
370 }
371
372 #[test]
373 fn a_refused_entry_is_the_only_one_that_does_not_write() {
374 let memory = Memory::new("doc.bwx").refusing(MANIFEST);
375 assert_eq!(
376 ready_now(memory.append(&MANIFEST, b"a row\n"))
377 .expect_err("the refusal")
378 .kind(),
379 std::io::ErrorKind::PermissionDenied,
380 );
381 ready_now(memory.write(&Entry::fixed("document.json"), b"{}")).expect("another entry");
382 assert_eq!(memory.wrote(), [Entry::fixed("document.json")]);
383 }
384}