opendal/services/memory/
backend.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt::Debug;
19use std::sync::Arc;
20
21use super::core::*;
22use super::delete::MemoryDeleter;
23use super::lister::MemoryLister;
24use super::writer::MemoryWriter;
25use crate::raw::oio;
26use crate::raw::*;
27use crate::services::MemoryConfig;
28use crate::*;
29
30impl Configurator for MemoryConfig {
31    type Builder = MemoryBuilder;
32    fn into_builder(self) -> Self::Builder {
33        MemoryBuilder { config: self }
34    }
35}
36
37/// In memory service support. (BTreeMap Based)
38#[doc = include_str!("docs.md")]
39#[derive(Default)]
40pub struct MemoryBuilder {
41    config: MemoryConfig,
42}
43
44impl MemoryBuilder {
45    /// Set the root for BTreeMap.
46    pub fn root(mut self, path: &str) -> Self {
47        self.config.root = Some(path.into());
48        self
49    }
50}
51
52impl Builder for MemoryBuilder {
53    const SCHEME: Scheme = Scheme::Memory;
54    type Config = MemoryConfig;
55
56    fn build(self) -> Result<impl Access> {
57        let root = normalize_root(self.config.root.as_deref().unwrap_or("/"));
58
59        let core = MemoryCore::new();
60        Ok(MemoryAccessor::new(core).with_normalized_root(root))
61    }
62}
63
64/// MemoryAccessor implements Access trait directly
65#[derive(Debug, Clone)]
66pub struct MemoryAccessor {
67    core: Arc<MemoryCore>,
68    root: String,
69    info: Arc<AccessorInfo>,
70}
71
72impl MemoryAccessor {
73    fn new(core: MemoryCore) -> Self {
74        let info = AccessorInfo::default();
75        info.set_scheme(Scheme::Memory);
76        info.set_name(&format!("{:p}", Arc::as_ptr(&core.data)));
77        info.set_root("/");
78        info.set_native_capability(Capability {
79            read: true,
80            write: true,
81            write_can_empty: true,
82            write_with_cache_control: true,
83            write_with_content_type: true,
84            write_with_content_disposition: true,
85            write_with_content_encoding: true,
86            delete: true,
87            stat: true,
88            list: true,
89            list_with_recursive: true,
90            shared: false,
91            ..Default::default()
92        });
93
94        Self {
95            core: Arc::new(core),
96            root: "/".to_string(),
97            info: Arc::new(info),
98        }
99    }
100
101    fn with_normalized_root(mut self, root: String) -> Self {
102        self.info.set_root(&root);
103        self.root = root;
104        self
105    }
106}
107
108impl Access for MemoryAccessor {
109    type Reader = Buffer;
110    type Writer = MemoryWriter;
111    type Lister = oio::HierarchyLister<MemoryLister>;
112    type Deleter = oio::OneShotDeleter<MemoryDeleter>;
113
114    fn info(&self) -> Arc<AccessorInfo> {
115        self.info.clone()
116    }
117
118    async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
119        let p = build_abs_path(&self.root, path);
120
121        if p == build_abs_path(&self.root, "") {
122            Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
123        } else {
124            match self.core.get(&p)? {
125                Some(value) => Ok(RpStat::new(value.metadata)),
126                None => Err(Error::new(
127                    ErrorKind::NotFound,
128                    "memory doesn't have this path",
129                )),
130            }
131        }
132    }
133
134    async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
135        let p = build_abs_path(&self.root, path);
136
137        let value = match self.core.get(&p)? {
138            Some(value) => value,
139            None => {
140                return Err(Error::new(
141                    ErrorKind::NotFound,
142                    "memory doesn't have this path",
143                ))
144            }
145        };
146
147        Ok((
148            RpRead::new(),
149            value.content.slice(args.range().to_range_as_usize()),
150        ))
151    }
152
153    async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
154        let p = build_abs_path(&self.root, path);
155        Ok((
156            RpWrite::new(),
157            MemoryWriter::new(self.core.clone(), p, args),
158        ))
159    }
160
161    async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
162        Ok((
163            RpDelete::default(),
164            oio::OneShotDeleter::new(MemoryDeleter::new(self.core.clone(), self.root.clone())),
165        ))
166    }
167
168    async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
169        let p = build_abs_path(&self.root, path);
170        let keys = self.core.scan(&p)?;
171        let lister = MemoryLister::new(&self.root, keys);
172        let lister = oio::HierarchyLister::new(lister, path, args.recursive());
173
174        Ok((RpList::default(), lister))
175    }
176}
177
178#[cfg(test)]
179mod tests {
180    use super::*;
181
182    #[test]
183    fn test_accessor_metadata_name() {
184        let b1 = MemoryBuilder::default().build().unwrap();
185        assert_eq!(b1.info().name(), b1.info().name());
186
187        let b2 = MemoryBuilder::default().build().unwrap();
188        assert_ne!(b1.info().name(), b2.info().name())
189    }
190}