victor_db/filesystem/
memory.rs1use std::{cell::RefCell, collections::HashMap, rc::Rc};
4
5use async_trait::async_trait;
6
7use crate::filesystem;
8
9#[derive(Debug, Clone)]
11pub enum DirectoryEntry {
12 #[allow(dead_code)]
13 Directory(DirectoryHandle),
14 File(FileHandle),
15}
16
17#[derive(Debug, Clone)]
19pub struct DirectoryHandle(Rc<RefCell<HashMap<String, DirectoryEntry>>>);
20
21#[derive(Debug, Clone)]
23pub struct FileHandle(WritableFileStream);
24
25#[derive(Debug, Clone)]
27pub struct WritableFileStream {
28 cursor_pos: usize,
29 stream: Rc<RefCell<Vec<u8>>>,
30}
31
32#[async_trait(?Send)]
33impl filesystem::DirectoryHandle for DirectoryHandle {
34 type Error = String;
35 type FileHandleT = FileHandle;
36
37 async fn get_file_handle_with_options(
38 &self,
39 name: &str,
40 options: &filesystem::GetFileHandleOptions,
41 ) -> Result<Self::FileHandleT, Self::Error> {
42 let mut directory = self.0.borrow_mut();
43 let entry = match directory.entry(name.to_string()) {
44 std::collections::hash_map::Entry::Occupied(entry) => entry.get().clone(),
45 std::collections::hash_map::Entry::Vacant(entry) => {
46 if options.create {
47 let file_handle = FileHandle::new();
48 entry.insert(DirectoryEntry::File(file_handle.clone()));
49 DirectoryEntry::File(file_handle)
50 } else {
51 return Err(format!("'{name}' does not exist"));
52 }
53 }
54 };
55
56 match entry {
57 DirectoryEntry::Directory(_) => Err(format!("'{name}' is a directory")),
58 DirectoryEntry::File(file) => Ok(file),
59 }
60 }
61
62 async fn remove_entry(&mut self, name: &str) -> Result<(), Self::Error> {
63 let mut directory = self.0.borrow_mut();
64 directory.remove(name);
65 Ok(())
66 }
67}
68impl Default for DirectoryHandle {
69 fn default() -> Self {
70 Self(Rc::new(RefCell::new(HashMap::new())))
71 }
72}
73
74#[async_trait(?Send)]
75impl filesystem::FileHandle for FileHandle {
76 type Error = String;
77 type WritableFileStreamT = WritableFileStream;
78
79 async fn create_writable_with_options(
80 &mut self,
81 options: &filesystem::CreateWritableOptions,
82 ) -> Result<Self::WritableFileStreamT, Self::Error> {
83 if !options.keep_existing_data {
84 self.0.stream.borrow_mut().clear();
85 }
86 Ok(WritableFileStream {
87 cursor_pos: 0,
88 ..self.0.clone()
89 })
90 }
91
92 async fn read(&self) -> Result<Vec<u8>, Self::Error> {
93 let stream = self.0.stream.clone();
94 let data = stream.borrow().clone();
95 Ok(data)
96 }
97
98 async fn size(&self) -> Result<usize, Self::Error> {
99 Ok(self.0.len())
100 }
101}
102
103#[async_trait(?Send)]
104impl filesystem::WritableFileStream for WritableFileStream {
105 type Error = String;
106
107 async fn write_at_cursor_pos(&mut self, data: Vec<u8>) -> Result<(), Self::Error> {
108 let data_len = data.len();
109
110 let mut stream = self.stream.borrow_mut();
111 *stream = stream[0..self.cursor_pos]
112 .iter()
113 .cloned()
114 .chain(data)
115 .collect::<Vec<u8>>();
116
117 self.cursor_pos += data_len;
118
119 Ok(())
120 }
121
122 async fn close(&mut self) -> Result<(), Self::Error> {
123 Ok(())
125 }
126
127 async fn seek(&mut self, offset: usize) -> Result<(), Self::Error> {
128 if offset > self.len() {
129 return Err(format!(
130 "cannot seek to {offset} because the file is only {len} bytes long",
131 len = self.len()
132 ));
133 }
134 self.cursor_pos = offset;
135 Ok(())
136 }
137}
138
139impl FileHandle {
140 fn new() -> Self {
141 Self(WritableFileStream::new())
142 }
143}
144
145impl WritableFileStream {
146 fn new() -> Self {
147 Self {
148 cursor_pos: 0,
149 stream: Rc::new(RefCell::new(Vec::new())),
150 }
151 }
152
153 fn len(&self) -> usize {
154 self.stream.borrow().len()
155 }
156}