1use crate::object::{ObjectId, ReadObject, WriteObject};
11use std::{io, sync::Arc};
12
13mod directory;
14pub use directory::Directory;
15
16#[derive(thiserror::Error, Debug)]
17pub enum BackendError {
18 #[error("IO error: {source}")]
19 Io {
20 #[from]
21 source: io::Error,
22 },
23 #[error("No object found")]
24 NotFound { id: ObjectId },
25 #[error("Can't create object")]
26 Create,
27 #[error("Backend Error: {source}")]
28 Generic {
29 #[from]
30 source: anyhow::Error,
31 },
32}
33
34pub type Result<T> = std::result::Result<T, BackendError>;
35
36pub trait Backend: Send + Sync {
37 fn write_object(&self, object: &WriteObject) -> Result<()>;
38 fn read_object(&self, id: &ObjectId) -> Result<Arc<ReadObject>>;
39
40 fn preload(&self, _objects: &[ObjectId]) -> Result<()> {
41 Ok(())
42 }
43
44 fn delete(&self, _objects: &[ObjectId]) -> Result<()> {
45 Ok(())
46 }
47
48 fn sync(&self) -> Result<()> {
49 Ok(())
50 }
51
52 fn read_fresh(&self, id: &ObjectId) -> Result<Arc<ReadObject>> {
53 self.read_object(id)
54 }
55
56 fn keep_warm(&self, _objects: &[ObjectId]) -> Result<()> {
57 Ok(())
58 }
59}
60
61#[cfg(any(test, bench, feature = "test"))]
62pub mod test {
63 use super::*;
64 use std::{collections::HashMap, sync::Mutex};
65
66 #[derive(Clone, Default)]
67 pub struct InMemoryBackend(Arc<Mutex<HashMap<ObjectId, Arc<ReadObject>>>>);
68
69 impl InMemoryBackend {
70 pub fn new() -> Self {
71 InMemoryBackend::default()
72 }
73
74 pub fn shared() -> Arc<Self> {
75 Arc::new(InMemoryBackend::default())
76 }
77 }
78
79 impl Backend for InMemoryBackend {
80 fn write_object(&self, object: &WriteObject) -> Result<()> {
81 self.0
82 .lock()
83 .unwrap()
84 .insert(*object.id(), Arc::new(object.into()));
85 Ok(())
86 }
87
88 fn read_object(&self, id: &ObjectId) -> Result<Arc<ReadObject>> {
89 self.0
90 .lock()
91 .unwrap()
92 .get(id)
93 .ok_or(BackendError::NotFound { id: *id })
94 .map(Arc::clone)
95 }
96 }
97
98 #[derive(Clone, Default)]
99 pub struct NullBackend(Arc<Mutex<usize>>);
100
101 #[allow(clippy::len_without_is_empty)]
102 impl NullBackend {
103 pub fn len(&self) -> usize {
104 *self.0.lock().unwrap()
105 }
106 }
107
108 impl Backend for NullBackend {
109 fn write_object(&self, _object: &WriteObject) -> Result<()> {
110 *self.0.lock().unwrap() += 1;
111 Ok(())
112 }
113
114 fn read_object(&self, _id: &ObjectId) -> Result<Arc<ReadObject>> {
115 unimplemented!();
116 }
117 }
118}