triblespace_core/blob/
memoryblobstore.rs1use crate::blob::encodings::UnknownBlob;
2use crate::blob::Blob;
3use crate::blob::BlobEncoding;
4use crate::blob::IntoBlob;
5use crate::patch::{Entry, IdentitySchema, PATCH};
6use crate::repo::BlobStore;
7use crate::repo::BlobStoreGet;
8use crate::repo::BlobStoreKeep;
9use crate::repo::BlobStoreList;
10use crate::repo::BlobStorePut;
11use crate::inline::encodings::hash::Handle;
12use crate::inline::Inline;
13use crate::inline::INLINE_LEN;
14
15use std::convert::Infallible;
16use std::error::Error;
17use std::fmt::Debug;
18use std::fmt::{self};
19use std::iter::FromIterator;
20
21use super::TryFromBlob;
22
23pub struct MemoryBlobStore {
35 blobs: PATCH<INLINE_LEN, IdentitySchema, Blob<UnknownBlob>>,
36}
37
38impl Debug for MemoryBlobStore {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "MemoryBlobStore")
41 }
42}
43
44#[derive(Debug)]
45pub struct MemoryBlobStoreReader {
56 blobs: PATCH<INLINE_LEN, IdentitySchema, Blob<UnknownBlob>>,
57}
58
59impl Clone for MemoryBlobStoreReader {
60 fn clone(&self) -> Self {
61 MemoryBlobStoreReader {
62 blobs: self.blobs.clone(),
63 }
64 }
65}
66
67impl PartialEq for MemoryBlobStoreReader {
68 fn eq(&self, other: &Self) -> bool {
69 self.blobs == other.blobs
70 }
71}
72
73impl Eq for MemoryBlobStoreReader {}
74
75impl MemoryBlobStoreReader {
76 fn new(blobs: PATCH<INLINE_LEN, IdentitySchema, Blob<UnknownBlob>>) -> Self {
77 MemoryBlobStoreReader { blobs }
78 }
79
80 pub fn len(&self) -> usize {
82 self.blobs.len() as usize
83 }
84
85 pub fn is_empty(&self) -> bool {
87 self.len() == 0
88 }
89
90 pub fn iter(&self) -> MemoryBlobStoreIter {
93 let for_iter = self.blobs.clone();
94 let lookup = for_iter.clone();
95 MemoryBlobStoreIter {
96 keys: for_iter.into_iter(),
97 lookup,
98 }
99 }
100}
101
102impl Clone for MemoryBlobStore {
103 fn clone(&self) -> Self {
104 MemoryBlobStore {
105 blobs: self.blobs.clone(),
106 }
107 }
108}
109
110impl PartialEq for MemoryBlobStore {
111 fn eq(&self, other: &Self) -> bool {
112 self.blobs == other.blobs
113 }
114}
115
116impl Eq for MemoryBlobStore {}
117
118impl Default for MemoryBlobStore {
119 fn default() -> Self {
120 Self::new()
121 }
122}
123
124impl MemoryBlobStore {
125 pub fn new() -> MemoryBlobStore {
127 MemoryBlobStore {
128 blobs: PATCH::new(),
129 }
130 }
131
132 pub fn insert<S>(&mut self, blob: Blob<S>) -> Inline<Handle<S>>
140 where
141 S: BlobEncoding,
142 Handle<S>: crate::inline::InlineEncoding,
143 {
144 let handle: Inline<Handle<S>> = blob.get_handle();
145 let unknown_handle: Inline<Handle<UnknownBlob>> = handle.transmute();
146 let blob: Blob<UnknownBlob> = blob.transmute::<UnknownBlob>();
147 let entry = Entry::with_value(&unknown_handle.raw, blob);
148 self.blobs.insert(&entry);
149 handle
150 }
151
152 pub fn len(&self) -> usize {
154 self.blobs.len() as usize
155 }
156
157 pub fn is_empty(&self) -> bool {
159 self.len() == 0
160 }
161
162pub fn union(&mut self, other: Self) {
170 self.blobs.union(other.blobs);
171 }
172
173 pub fn keep<I>(&mut self, handles: I)
175 where
176 I: IntoIterator<Item = Inline<Handle<UnknownBlob>>>,
177 {
178 let mut surviving = PATCH::new();
179 for handle in handles {
180 if let Some(blob) = self.blobs.get(&handle.raw) {
181 let entry = Entry::with_value(&handle.raw, blob.clone());
182 surviving.insert(&entry);
183 }
184 }
185 self.blobs = surviving;
186 }
187}
188
189impl BlobStoreKeep for MemoryBlobStore {
190 fn keep<I>(&mut self, handles: I)
191 where
192 I: IntoIterator<Item = Inline<Handle<UnknownBlob>>>,
193 {
194 MemoryBlobStore::keep(self, handles);
195 }
196}
197
198impl FromIterator<(Inline<Handle<UnknownBlob>>, Blob<UnknownBlob>)> for MemoryBlobStore {
199 fn from_iter<I: IntoIterator<Item = (Inline<Handle<UnknownBlob>>, Blob<UnknownBlob>)>>(
200 iter: I,
201 ) -> Self {
202 let mut store = MemoryBlobStore::new();
203 for (handle, blob) in iter {
204 let entry = Entry::with_value(&handle.raw, blob);
205 store.blobs.insert(&entry);
206 }
207 store
208 }
209}
210
211impl IntoIterator for MemoryBlobStoreReader {
212 type Item = (Inline<Handle<UnknownBlob>>, Blob<UnknownBlob>);
213 type IntoIter = MemoryBlobStoreIter;
214 fn into_iter(self) -> Self::IntoIter {
215 self.iter()
216 }
217}
218
219#[derive(Debug)]
220pub enum MemoryStoreGetError<E: Error> {
221 NotFound(),
223 ConversionFailed(E),
225}
226
227impl<E: Error> fmt::Display for MemoryStoreGetError<E> {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 match self {
230 MemoryStoreGetError::NotFound() => write!(f, "Blob not found in memory store"),
231 MemoryStoreGetError::ConversionFailed(e) => write!(f, "Blob conversion failed: {e}"),
232 }
233 }
234}
235
236impl<E: Error> Error for MemoryStoreGetError<E> {}
237
238pub struct MemoryBlobStoreIter {
243 keys: crate::patch::PATCHIntoIterator<INLINE_LEN, IdentitySchema, Blob<UnknownBlob>>,
244 lookup: PATCH<INLINE_LEN, IdentitySchema, Blob<UnknownBlob>>,
245}
246
247impl Debug for MemoryBlobStoreIter {
248 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249 f.debug_struct("MemoryBlobStoreIter").finish()
250 }
251}
252
253impl Iterator for MemoryBlobStoreIter {
254 type Item = (Inline<Handle<UnknownBlob>>, Blob<UnknownBlob>);
255
256 fn next(&mut self) -> Option<Self::Item> {
257 let key = self.keys.next()?;
258 let handle: Inline<Handle<UnknownBlob>> = Inline::new(key);
259 let blob = self
260 .lookup
261 .get(&key)
262 .cloned()
263 .expect("key from PATCH iterator must resolve in the same snapshot");
264 Some((handle, blob))
265 }
266}
267
268pub struct MemoryBlobStoreListIter {
270 inner: MemoryBlobStoreIter,
271}
272
273impl Iterator for MemoryBlobStoreListIter {
274 type Item = Result<Inline<Handle<UnknownBlob>>, Infallible>;
275
276 fn next(&mut self) -> Option<Self::Item> {
277 let (handle, _) = self.inner.next()?;
278 Some(Ok(handle))
279 }
280}
281
282impl BlobStoreList for MemoryBlobStoreReader {
283 type Iter<'a> = MemoryBlobStoreListIter;
284 type Err = Infallible;
285
286 fn blobs(&self) -> Self::Iter<'static> {
287 MemoryBlobStoreListIter { inner: self.iter() }
288 }
289}
290
291impl BlobStoreGet for MemoryBlobStoreReader {
292 type GetError<E: Error + Send + Sync + 'static> = MemoryStoreGetError<E>;
293
294 fn get<T, S>(
295 &self,
296 handle: Inline<Handle<S>>,
297 ) -> Result<T, Self::GetError<<T as TryFromBlob<S>>::Error>>
298 where
299 S: BlobEncoding,
300 T: TryFromBlob<S>,
301 {
302 let handle: Inline<Handle<UnknownBlob>> = handle.transmute();
303 let Some(blob) = self.blobs.get(&handle.raw) else {
304 return Err(MemoryStoreGetError::NotFound());
305 };
306 let blob: Blob<S> = blob.clone().transmute();
307 match blob.try_from_blob() {
308 Ok(value) => Ok(value),
309 Err(e) => Err(MemoryStoreGetError::ConversionFailed(e)),
310 }
311 }
312}
313
314impl crate::repo::BlobChildren for MemoryBlobStoreReader {}
315
316impl BlobStorePut for MemoryBlobStore {
317 type PutError = Infallible;
318
319 fn put<S, T>(&mut self, item: T) -> Result<Inline<Handle<S>>, Self::PutError>
320 where
321 S: BlobEncoding,
322 T: IntoBlob<S>,
323 {
324 let blob = item.to_blob();
325 let handle = blob.get_handle();
326 self.insert(blob);
327 Ok(handle)
328 }
329}
330
331impl BlobStore for MemoryBlobStore {
332 type Reader = MemoryBlobStoreReader;
333 type ReaderError = Infallible;
334
335 fn reader(&mut self) -> Result<Self::Reader, Self::ReaderError> {
336 Ok(MemoryBlobStoreReader::new(self.blobs.clone()))
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use crate::prelude::*;
343
344 use super::*;
345 use anybytes::Bytes;
346 use fake::faker::name::raw::Name;
347 use fake::locales::EN;
348 use fake::Fake;
349
350 use blobencodings::LongString;
351 use inlineencodings::Handle;
352
353 attributes! {
354 "5AD0FAFB1FECBC197A385EC20166899E" as description: Handle<LongString>;
355 }
356
357 #[test]
358 fn keep() {
359 use crate::repo::potential_handles;
360 use crate::trible::TribleSet;
361
362 let mut kb = TribleSet::new();
363 let mut blobs = MemoryBlobStore::new();
364 for _i in 0..200 {
365 kb += entity! {
366 description: blobs.put(Bytes::from_source(Name(EN).fake::<String>()).view().unwrap()).unwrap()
367 };
368 }
369 blobs.keep(potential_handles(&kb));
370 }
371
372 #[test]
375 fn reader_is_send_sync() {
376 fn assert_send_sync<T: Send + Sync>() {}
377 assert_send_sync::<MemoryBlobStoreReader>();
378 }
379
380 #[test]
383 fn reader_is_a_pinned_snapshot() {
384 let mut store = MemoryBlobStore::new();
385 let blob_a: Inline<Handle<LongString>> =
386 store.put(Bytes::from_source("hello".to_string()).view().unwrap()).unwrap();
387 let snapshot = store.reader().unwrap();
388 assert_eq!(snapshot.len(), 1);
389
390 let _blob_b: Inline<Handle<LongString>> =
391 store.put(Bytes::from_source("world".to_string()).view().unwrap()).unwrap();
392 assert_eq!(snapshot.len(), 1);
394 use anybytes::View;
395 let recovered: View<str> =
396 snapshot.get::<View<str>, LongString>(blob_a).unwrap();
397 assert_eq!(&*recovered, "hello");
398
399 let fresh = store.reader().unwrap();
401 assert_eq!(fresh.len(), 2);
402 }
403
404 #[test]
406 fn union_merges_and_preserves_handles() {
407 let mut a = MemoryBlobStore::new();
408 let h_hello: Inline<Handle<LongString>> = a
409 .put(Bytes::from_source("hello".to_string()).view().unwrap())
410 .unwrap();
411 let mut b = MemoryBlobStore::new();
412 let h_world: Inline<Handle<LongString>> = b
413 .put(Bytes::from_source("world".to_string()).view().unwrap())
414 .unwrap();
415 let _h_hello_b: Inline<Handle<LongString>> = b
418 .put(Bytes::from_source("hello".to_string()).view().unwrap())
419 .unwrap();
420
421 a.union(b);
422 assert_eq!(a.reader().unwrap().len(), 2, "duplicates collapse via union");
423
424 use anybytes::View;
425 let recovered_hello: View<str> = a
426 .reader()
427 .unwrap()
428 .get::<View<str>, LongString>(h_hello)
429 .unwrap();
430 assert_eq!(&*recovered_hello, "hello");
431 let recovered_world: View<str> = a
432 .reader()
433 .unwrap()
434 .get::<View<str>, LongString>(h_world)
435 .unwrap();
436 assert_eq!(&*recovered_world, "world");
437 }
438}