vfs/engine/mem/
object_backend.rs1use crate::engine::block::ObjectBackend;
2use crate::engine::error::{VfsError, VfsResult};
3use crate::engine::types::{ObjectEntry, ObjectMeta};
4use async_trait::async_trait;
5use std::collections::{BTreeMap, BTreeSet};
6use std::sync::{Arc, Mutex};
7
8#[derive(Debug, Clone)]
9struct StoredObject {
10 data: Vec<u8>,
11 meta: ObjectMeta,
12}
13
14#[derive(Debug, Clone, Default)]
15pub struct MemoryObjectBackend {
16 objects: Arc<Mutex<BTreeMap<String, StoredObject>>>,
17}
18
19impl MemoryObjectBackend {
20 pub fn new() -> Self {
21 Self::default()
22 }
23}
24
25#[async_trait]
26impl ObjectBackend for MemoryObjectBackend {
27 async fn list(&self, prefix: &str) -> VfsResult<Vec<ObjectEntry>> {
28 let objects = self.objects.lock().expect("object mutex poisoned");
29 let mut entries = Vec::new();
30 let mut prefixes = BTreeSet::new();
31 for (key, object) in objects.range(prefix.to_string()..) {
32 if !key.starts_with(prefix) {
33 break;
34 }
35 let rest = &key[prefix.len()..];
36 if rest.is_empty() {
37 entries.push(ObjectEntry {
38 name: key.clone(),
39 size: object.meta.size,
40 mtime: object.meta.mtime,
41 is_prefix: false,
42 });
43 continue;
44 }
45 if let Some((head, _)) = rest.split_once('/') {
46 prefixes.insert(format!("{prefix}{head}/"));
47 } else {
48 entries.push(ObjectEntry {
49 name: key.clone(),
50 size: object.meta.size,
51 mtime: object.meta.mtime,
52 is_prefix: false,
53 });
54 }
55 }
56 entries.extend(prefixes.into_iter().map(|name| ObjectEntry {
57 name,
58 size: 0,
59 mtime: crate::engine::types::Timespec::now(),
60 is_prefix: true,
61 }));
62 Ok(entries)
63 }
64
65 async fn head(&self, key: &str) -> VfsResult<Option<ObjectMeta>> {
66 Ok(self
67 .objects
68 .lock()
69 .expect("object mutex poisoned")
70 .get(key)
71 .map(|object| object.meta.clone()))
72 }
73
74 async fn get_range(&self, key: &str, off: u64, len: u64) -> VfsResult<Vec<u8>> {
75 let objects = self.objects.lock().expect("object mutex poisoned");
76 let object = objects.get(key).ok_or_else(|| VfsError::enoent(key))?;
77 let start = usize::try_from(off)
78 .map_err(|_| VfsError::einval(format!("range offset is too large: {off}")))?;
79 let len = usize::try_from(len)
80 .map_err(|_| VfsError::einval(format!("range length is too large: {len}")))?;
81 if start >= object.data.len() {
82 return Ok(Vec::new());
83 }
84 let end = start.saturating_add(len).min(object.data.len());
85 Ok(object.data[start..end].to_vec())
86 }
87
88 async fn put(&self, key: &str, data: &[u8], mut meta: ObjectMeta) -> VfsResult<()> {
89 meta.size = data.len() as u64;
90 self.objects.lock().expect("object mutex poisoned").insert(
91 key.to_string(),
92 StoredObject {
93 data: data.to_vec(),
94 meta,
95 },
96 );
97 Ok(())
98 }
99
100 async fn copy(&self, src: &str, dst: &str) -> VfsResult<()> {
101 let mut objects = self.objects.lock().expect("object mutex poisoned");
102 let object = objects
103 .get(src)
104 .cloned()
105 .ok_or_else(|| VfsError::enoent(src))?;
106 objects.insert(dst.to_string(), object);
107 Ok(())
108 }
109
110 async fn delete(&self, key: &str) -> VfsResult<()> {
111 self.objects
112 .lock()
113 .expect("object mutex poisoned")
114 .remove(key);
115 Ok(())
116 }
117}