opendal/services/memory/
backend.rs1use std::collections::HashMap;
19use std::fmt::Debug;
20use std::sync::Arc;
21
22use http::Uri;
23use percent_encoding::percent_decode_str;
24
25use super::core::*;
26use super::delete::MemoryDeleter;
27use super::lister::MemoryLister;
28use super::writer::MemoryWriter;
29use super::MEMORY_SCHEME;
30use crate::raw::oio;
31use crate::raw::*;
32use crate::services::MemoryConfig;
33use crate::*;
34impl Configurator for MemoryConfig {
35 type Builder = MemoryBuilder;
36
37 fn from_uri(uri: &Uri, options: &HashMap<String, String>) -> Result<Self> {
38 let mut map = options.clone();
39
40 if !map.contains_key("root") {
41 let path = percent_decode_str(uri.path()).decode_utf8_lossy();
42 if !path.is_empty() && path != "/" {
43 map.insert("root".to_string(), path.trim_start_matches('/').to_string());
44 }
45 }
46
47 Self::from_iter(map)
48 }
49
50 fn into_builder(self) -> Self::Builder {
51 MemoryBuilder { config: self }
52 }
53}
54
55#[doc = include_str!("docs.md")]
57#[derive(Default)]
58pub struct MemoryBuilder {
59 config: MemoryConfig,
60}
61
62impl MemoryBuilder {
63 pub fn root(mut self, path: &str) -> Self {
65 self.config.root = Some(path.into());
66 self
67 }
68}
69
70impl Builder for MemoryBuilder {
71 type Config = MemoryConfig;
72
73 fn build(self) -> Result<impl Access> {
74 let root = normalize_root(self.config.root.as_deref().unwrap_or("/"));
75
76 let core = MemoryCore::new();
77 Ok(MemoryAccessor::new(core).with_normalized_root(root))
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct MemoryAccessor {
84 core: Arc<MemoryCore>,
85 root: String,
86 info: Arc<AccessorInfo>,
87}
88
89impl MemoryAccessor {
90 fn new(core: MemoryCore) -> Self {
91 let info = AccessorInfo::default();
92 info.set_scheme(MEMORY_SCHEME);
93 info.set_name(&format!("{:p}", Arc::as_ptr(&core.data)));
94 info.set_root("/");
95 info.set_native_capability(Capability {
96 read: true,
97 write: true,
98 write_can_empty: true,
99 write_with_cache_control: true,
100 write_with_content_type: true,
101 write_with_content_disposition: true,
102 write_with_content_encoding: true,
103 delete: true,
104 stat: true,
105 list: true,
106 list_with_recursive: true,
107 shared: false,
108 ..Default::default()
109 });
110
111 Self {
112 core: Arc::new(core),
113 root: "/".to_string(),
114 info: Arc::new(info),
115 }
116 }
117
118 fn with_normalized_root(mut self, root: String) -> Self {
119 self.info.set_root(&root);
120 self.root = root;
121 self
122 }
123}
124
125impl Access for MemoryAccessor {
126 type Reader = Buffer;
127 type Writer = MemoryWriter;
128 type Lister = oio::HierarchyLister<MemoryLister>;
129 type Deleter = oio::OneShotDeleter<MemoryDeleter>;
130
131 fn info(&self) -> Arc<AccessorInfo> {
132 self.info.clone()
133 }
134
135 async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
136 let p = build_abs_path(&self.root, path);
137
138 if p == build_abs_path(&self.root, "") {
139 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
140 } else {
141 match self.core.get(&p)? {
142 Some(value) => Ok(RpStat::new(value.metadata)),
143 None => Err(Error::new(
144 ErrorKind::NotFound,
145 "memory doesn't have this path",
146 )),
147 }
148 }
149 }
150
151 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
152 let p = build_abs_path(&self.root, path);
153
154 let value = match self.core.get(&p)? {
155 Some(value) => value,
156 None => {
157 return Err(Error::new(
158 ErrorKind::NotFound,
159 "memory doesn't have this path",
160 ))
161 }
162 };
163
164 Ok((
165 RpRead::new(),
166 value.content.slice(args.range().to_range_as_usize()),
167 ))
168 }
169
170 async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
171 let p = build_abs_path(&self.root, path);
172 Ok((
173 RpWrite::new(),
174 MemoryWriter::new(self.core.clone(), p, args),
175 ))
176 }
177
178 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
179 Ok((
180 RpDelete::default(),
181 oio::OneShotDeleter::new(MemoryDeleter::new(self.core.clone(), self.root.clone())),
182 ))
183 }
184
185 async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
186 let p = build_abs_path(&self.root, path);
187 let keys = self.core.scan(&p)?;
188 let lister = MemoryLister::new(&self.root, keys);
189 let lister = oio::HierarchyLister::new(lister, path, args.recursive());
190
191 Ok((RpList::default(), lister))
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_accessor_metadata_name() {
201 let b1 = MemoryBuilder::default().build().unwrap();
202 assert_eq!(b1.info().name(), b1.info().name());
203
204 let b2 = MemoryBuilder::default().build().unwrap();
205 assert_ne!(b1.info().name(), b2.info().name())
206 }
207}