1use core::future::Future;
10use core::pin::Pin;
11use std::path::Path;
12
13use super::{Entry, Name, Residency, Storage};
14use crate::lock::Claim;
15use crate::record::WallTime;
16
17type Answer<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
18
19trait Erased {
20 fn name(&self) -> Name;
21 fn names(&self, at: &Entry) -> String;
22 fn residency(&self) -> Residency;
23 fn disk_path(&self) -> Option<&Path>;
24 fn read<'a>(&'a self, at: &'a Entry) -> Answer<'a, std::io::Result<Option<Vec<u8>>>>;
25 fn exists<'a>(&'a self, at: &'a Entry) -> Answer<'a, std::io::Result<bool>>;
26 fn write<'a>(&'a self, at: &'a Entry, bytes: &'a [u8]) -> Answer<'a, std::io::Result<()>>;
27 fn append<'a>(&'a self, at: &'a Entry, bytes: &'a [u8]) -> Answer<'a, std::io::Result<()>>;
28 fn truncate<'a>(&'a self, at: &'a Entry, len: u64) -> Answer<'a, std::io::Result<()>>;
29 fn list<'a>(&'a self, dir: &'a Entry) -> Answer<'a, std::io::Result<Vec<String>>>;
30 fn remove<'a>(&'a self, at: &'a Entry) -> Answer<'a, std::io::Result<()>>;
31 fn create_dir<'a>(&'a self, dir: &'a Entry) -> Answer<'a, std::io::Result<()>>;
32 fn rename<'a>(&'a mut self, to: &'a Name) -> Answer<'a, std::io::Result<()>>;
33 fn discard(&self) -> Answer<'_, std::io::Result<()>>;
34 fn claim(&self, now: WallTime) -> Answer<'_, std::io::Result<Claim>>;
35 fn release(&self);
36}
37
38impl<S: Storage> Erased for S {
39 fn name(&self) -> Name {
40 Storage::name(self)
41 }
42 fn names(&self, at: &Entry) -> String {
43 Storage::names(self, at)
44 }
45 fn residency(&self) -> Residency {
46 Storage::residency(self)
47 }
48 fn disk_path(&self) -> Option<&Path> {
49 Storage::disk_path(self)
50 }
51 fn read<'a>(&'a self, at: &'a Entry) -> Answer<'a, std::io::Result<Option<Vec<u8>>>> {
52 Box::pin(Storage::read(self, at))
53 }
54 fn exists<'a>(&'a self, at: &'a Entry) -> Answer<'a, std::io::Result<bool>> {
55 Box::pin(Storage::exists(self, at))
56 }
57 fn write<'a>(&'a self, at: &'a Entry, bytes: &'a [u8]) -> Answer<'a, std::io::Result<()>> {
58 Box::pin(Storage::write(self, at, bytes))
59 }
60 fn append<'a>(&'a self, at: &'a Entry, bytes: &'a [u8]) -> Answer<'a, std::io::Result<()>> {
61 Box::pin(Storage::append(self, at, bytes))
62 }
63 fn truncate<'a>(&'a self, at: &'a Entry, len: u64) -> Answer<'a, std::io::Result<()>> {
64 Box::pin(Storage::truncate(self, at, len))
65 }
66 fn list<'a>(&'a self, dir: &'a Entry) -> Answer<'a, std::io::Result<Vec<String>>> {
67 Box::pin(Storage::list(self, dir))
68 }
69 fn remove<'a>(&'a self, at: &'a Entry) -> Answer<'a, std::io::Result<()>> {
70 Box::pin(Storage::remove(self, at))
71 }
72 fn create_dir<'a>(&'a self, dir: &'a Entry) -> Answer<'a, std::io::Result<()>> {
73 Box::pin(Storage::create_dir(self, dir))
74 }
75 fn rename<'a>(&'a mut self, to: &'a Name) -> Answer<'a, std::io::Result<()>> {
76 Box::pin(Storage::rename(self, to))
77 }
78 fn discard(&self) -> Answer<'_, std::io::Result<()>> {
79 Box::pin(Storage::discard(self))
80 }
81 fn claim(&self, now: WallTime) -> Answer<'_, std::io::Result<Claim>> {
82 Box::pin(Storage::claim(self, now))
83 }
84 fn release(&self) {
85 Storage::release(self);
86 }
87}
88
89pub struct Any(Box<dyn Erased>);
91
92impl Any {
93 pub fn new(storage: impl Storage + 'static) -> Self {
94 Self(Box::new(storage))
95 }
96}
97
98impl std::fmt::Debug for Any {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 write!(f, "storage for {}", self.0.name())
101 }
102}
103
104impl Storage for Any {
105 fn name(&self) -> Name {
106 self.0.name()
107 }
108 fn names(&self, at: &Entry) -> String {
109 self.0.names(at)
110 }
111 fn residency(&self) -> Residency {
112 self.0.residency()
113 }
114 fn disk_path(&self) -> Option<&Path> {
115 self.0.disk_path()
116 }
117 fn read<'a>(
118 &'a self,
119 at: &'a Entry,
120 ) -> impl Future<Output = std::io::Result<Option<Vec<u8>>>> + 'a {
121 self.0.read(at)
122 }
123 fn exists<'a>(&'a self, at: &'a Entry) -> impl Future<Output = std::io::Result<bool>> + 'a {
124 self.0.exists(at)
125 }
126 fn write<'a>(
127 &'a self,
128 at: &'a Entry,
129 bytes: &'a [u8],
130 ) -> impl Future<Output = std::io::Result<()>> + 'a {
131 self.0.write(at, bytes)
132 }
133 fn append<'a>(
134 &'a self,
135 at: &'a Entry,
136 bytes: &'a [u8],
137 ) -> impl Future<Output = std::io::Result<()>> + 'a {
138 self.0.append(at, bytes)
139 }
140 fn truncate<'a>(
141 &'a self,
142 at: &'a Entry,
143 len: u64,
144 ) -> impl Future<Output = std::io::Result<()>> + 'a {
145 self.0.truncate(at, len)
146 }
147 fn list<'a>(
148 &'a self,
149 dir: &'a Entry,
150 ) -> impl Future<Output = std::io::Result<Vec<String>>> + 'a {
151 self.0.list(dir)
152 }
153 fn remove<'a>(&'a self, at: &'a Entry) -> impl Future<Output = std::io::Result<()>> + 'a {
154 self.0.remove(at)
155 }
156 fn create_dir<'a>(&'a self, dir: &'a Entry) -> impl Future<Output = std::io::Result<()>> + 'a {
157 self.0.create_dir(dir)
158 }
159 fn rename<'a>(&'a mut self, to: &'a Name) -> impl Future<Output = std::io::Result<()>> + 'a {
160 self.0.rename(to)
161 }
162 fn discard(&self) -> impl Future<Output = std::io::Result<()>> + '_ {
163 self.0.discard()
164 }
165 fn claim(&self, now: WallTime) -> impl Future<Output = std::io::Result<Claim>> + '_ {
166 self.0.claim(now)
167 }
168 fn release(&self) {
169 self.0.release();
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use crate::container::LOCK;
177 use crate::fixture::block_on;
178 use crate::lock::Claim;
179 use crate::record::WallTime;
180 use crate::storage::{Memory, ready_now};
181
182 #[test]
185 fn a_boxed_storage_answers_as_the_one_inside_it() {
186 let held = Any::new(Memory::new("doc.bwx"));
187 let notes = Entry::fixed("notes.txt");
188 ready_now(Storage::write(&held, ¬es, b"kept")).expect("the write lands");
189
190 assert_eq!(
191 ready_now(Storage::read(&held, ¬es)).expect("it reads back"),
192 Some(b"kept".to_vec()),
193 );
194 assert_eq!(Storage::name(&held).to_string(), "doc.bwx");
195 assert_eq!(Storage::residency(&held), Residency::Lazy);
196 assert_eq!(Storage::disk_path(&held), None);
197 }
198
199 #[test]
203 fn a_boxed_storage_is_locked_the_way_the_one_inside_it_is() {
204 let held = Any::new(Memory::deferred("doc.bwx"));
205 assert!(matches!(
206 block_on(Storage::claim(&held, WallTime::EPOCH)).expect("the claim"),
207 Claim::Taken,
208 ));
209 assert_eq!(
210 block_on(Storage::read(&held, &LOCK)).expect("the read answers"),
211 None,
212 "the box wrote a lock entry the storage inside it has no use for",
213 );
214
215 assert!(matches!(
216 block_on(Storage::claim(&held, WallTime::EPOCH)).expect("the claim"),
217 Claim::Held(_),
218 ));
219 Storage::release(&held);
220 assert!(matches!(
221 block_on(Storage::claim(&held, WallTime::EPOCH)).expect("the claim"),
222 Claim::Taken,
223 ));
224 }
225}