nuts_memory/
lib.rs

1// MIT License
2//
3// Copyright (c) 2022-2024 Robin Doer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to
7// deal in the Software without restriction, including without limitation the
8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9// sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21// IN THE SOFTWARE.
22
23//! A sample [`nuts_backend::Backend`] implementation which stores the data in
24//! memory.
25//!
26//! **This implementation is mainly used for demonstration, testing and
27//! documentation.**
28//!
29//! It stores the content of the data blocks in a [hash](HashMap) indexed by
30//! the [`Id`](nuts_backend::Backend::Id) of this backend, where the
31//! [id](nuts_backend::Backend::Id) is a simple `u32` value.
32
33use nuts_backend::{Backend, Binary, Create, IdSize, Open, ReceiveHeader, HEADER_MAX_SIZE};
34use nuts_bytes::{FromBytes, ToBytes};
35use serde::{Deserialize, Deserializer, Serialize, Serializer};
36use std::borrow::Cow;
37use std::collections::HashMap;
38use std::convert::TryInto;
39use std::num::ParseIntError;
40use std::str::FromStr;
41use std::{cmp, fmt, mem};
42use thiserror::Error;
43
44pub fn deserialize_header<'de, D: Deserializer<'de>>(
45    deserializer: D,
46) -> Result<Option<[u8; HEADER_MAX_SIZE]>, D::Error> {
47    let value: Option<Vec<u8>> = Deserialize::deserialize(deserializer)?;
48
49    match value {
50        Some(vec) => match vec.try_into() {
51            Ok(buf) => Ok(Some(buf)),
52            Err(_) => Err(serde::de::Error::custom("header has an invalid size")),
53        },
54        None => Ok(None),
55    }
56}
57
58pub fn serialize_header<S: Serializer>(
59    value: &Option<[u8; HEADER_MAX_SIZE]>,
60    serializer: S,
61) -> Result<S::Ok, S::Error> {
62    Serialize::serialize(&value.map(|buf| buf.to_vec()), serializer)
63}
64
65/// Error used by the memory backend.
66#[derive(Debug, Error)]
67pub enum Error {
68    /// Tried to read or write from/to an id, which does not exist.
69    #[error("no such id: {0}")]
70    NoSuchId(Id),
71
72    /// Failed to aquire the given id.
73    #[error("already aquired: {0}")]
74    AlreadAquired(Id),
75
76    /// Tried to open the backend without header data
77    #[error("no header data available")]
78    NoHeader,
79
80    /// Failed to serialize binary data.
81    #[error(transparent)]
82    Bytes(#[from] nuts_bytes::Error),
83}
84
85/// The [id](nuts_backend::Backend::Id) of the memory backend.
86#[derive(Clone, Copy, Debug, FromBytes, PartialEq, ToBytes)]
87pub struct Id(u32);
88
89impl Binary for Id {
90    fn from_bytes(bytes: &[u8]) -> Option<Self> {
91        match bytes.try_into() {
92            Ok(buf) => Some(Id(u32::from_be_bytes(buf))),
93            Err(_) => None,
94        }
95    }
96
97    fn as_bytes(&self) -> Vec<u8> {
98        self.0.to_be_bytes().to_vec()
99    }
100}
101
102impl IdSize for Id {
103    fn size() -> usize {
104        mem::size_of::<u32>()
105    }
106}
107
108impl fmt::Display for Id {
109    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
110        fmt::Display::fmt(&self.0, fmt)
111    }
112}
113
114impl FromStr for Id {
115    type Err = ParseIntError;
116
117    fn from_str(s: &str) -> Result<Self, ParseIntError> {
118        FromStr::from_str(s).map(Id)
119    }
120}
121
122#[derive(Clone, Debug, PartialEq)]
123pub struct Settings;
124
125impl Binary for Settings {
126    fn from_bytes(bytes: &[u8]) -> Option<Settings> {
127        if bytes.is_empty() {
128            Some(Settings)
129        } else {
130            None
131        }
132    }
133
134    fn as_bytes(&self) -> Vec<u8> {
135        vec![]
136    }
137}
138
139/// The [`Backend`] implementation itself.
140///
141/// See the [module](crate) documentation for details.
142#[derive(Debug, Deserialize, PartialEq, Serialize)]
143pub struct MemoryBackend {
144    bsize: u32,
145    blocks: HashMap<u32, Vec<u8>>,
146    #[serde(
147        deserialize_with = "deserialize_header",
148        serialize_with = "serialize_header"
149    )]
150    header: Option<[u8; HEADER_MAX_SIZE]>,
151}
152
153impl MemoryBackend {
154    /// Creates a new instance of the `MemoryBackend` type.
155    ///
156    /// The block-size is set to 512 bytes.
157    pub fn new() -> MemoryBackend {
158        Self::new_with_bsize(512)
159    }
160
161    /// Creates a new instance of the `MemoryBackend` type with the given
162    /// block-size.
163    pub fn new_with_bsize(bsize: u32) -> MemoryBackend {
164        MemoryBackend {
165            bsize,
166            blocks: HashMap::new(),
167            header: None,
168        }
169    }
170
171    /// Returns the block size specified for this backend instance.
172    pub fn block_size(&self) -> u32 {
173        self.bsize
174    }
175
176    /// Receives the content of the block with the given `id`.
177    ///
178    /// Returns [`None`] if the block does not exist.
179    pub fn get(&self, id: &Id) -> Option<&[u8]> {
180        self.blocks.get(&id.0).map(|buf| buf.as_slice())
181    }
182
183    /// Inserts a new block.
184    ///
185    /// The block contains only zeros.
186    ///
187    /// Returns the id of the new block.
188    pub fn insert(&mut self) -> Result<Id, Error> {
189        self.insert_data(&[])
190    }
191
192    /// Inserts a new block with some initial data.
193    ///
194    /// Assigns the first [`block-size`](Self::block_size) bytes from `data` to
195    /// the new block. If `data` does not have [`block-size`](Self::block_size)
196    /// bytes, the new block is padded with zero bytes.
197    ///
198    /// Returns the id of the new block.
199    pub fn insert_data(&mut self, data: &[u8]) -> Result<Id, Error> {
200        let id = Id(self.max_id() + 1);
201        let mut block = vec![0; self.bsize as usize];
202
203        let n = cmp::min(block.len(), data.len());
204        block[..n].copy_from_slice(&data[..n]);
205
206        match self.blocks.insert(id.0, block) {
207            Some(_) => Err(Error::AlreadAquired(id)),
208            None => Ok(id),
209        }
210    }
211
212    fn max_id(&self) -> u32 {
213        *self.blocks.keys().max().unwrap_or(&0)
214    }
215}
216
217impl Default for MemoryBackend {
218    fn default() -> Self {
219        Self::new()
220    }
221}
222
223impl ReceiveHeader<Self> for MemoryBackend {
224    fn get_header_bytes(&mut self, bytes: &mut [u8; HEADER_MAX_SIZE]) -> Result<(), Error> {
225        match self.header.as_ref() {
226            Some(source) => {
227                bytes.copy_from_slice(source);
228                Ok(())
229            }
230            None => Err(Error::NoHeader),
231        }
232    }
233}
234
235impl Create<Self> for MemoryBackend {
236    fn settings(&self) -> Settings {
237        Settings
238    }
239
240    fn build(
241        mut self,
242        header: [u8; HEADER_MAX_SIZE],
243        _overwrite: bool,
244    ) -> Result<MemoryBackend, Error> {
245        <Self as Backend>::write_header(&mut self, &header)?;
246        Ok(self)
247    }
248}
249
250impl Open<Self> for MemoryBackend {
251    fn build(self, _settings: Settings) -> Result<MemoryBackend, Error> {
252        Ok(self)
253    }
254}
255
256impl Backend for MemoryBackend {
257    type Settings = Settings;
258    type Err = Error;
259    type Id = Id;
260    type Info = ();
261
262    fn info(&self) -> Result<(), Error> {
263        Ok(())
264    }
265
266    fn block_size(&self) -> u32 {
267        self.bsize
268    }
269
270    fn aquire(&mut self, buf: &[u8]) -> Result<Id, Error> {
271        self.insert_data(buf)
272    }
273
274    fn release(&mut self, id: Id) -> Result<(), Error> {
275        self.blocks.remove(&id.0);
276        Ok(())
277    }
278
279    fn read(&mut self, id: &Id, buf: &mut [u8]) -> Result<usize, Error> {
280        match self.blocks.get(&id.0) {
281            Some(src) => {
282                let len = cmp::min(src.len(), buf.len());
283
284                let source = &src[..len];
285                let target = &mut buf[..len];
286
287                target.copy_from_slice(source);
288
289                Ok(len)
290            }
291            None => Err(Error::NoSuchId(*id)),
292        }
293    }
294
295    fn write(&mut self, id: &Id, buf: &[u8]) -> Result<usize, Error> {
296        match self.blocks.get_mut(&id.0) {
297            Some(target) => {
298                let mut source = Cow::from(buf);
299                let mut len = source.len();
300
301                if len != self.bsize as usize {
302                    len = cmp::min(source.len(), self.bsize as usize);
303                    source.to_mut().resize(self.bsize as usize, 0);
304                }
305
306                target.copy_from_slice(&source);
307
308                Ok(len)
309            }
310            None => Err(Error::NoSuchId(*id)),
311        }
312    }
313
314    fn write_header(&mut self, buf: &[u8; HEADER_MAX_SIZE]) -> Result<(), Error> {
315        self.header = Some(*buf);
316        Ok(())
317    }
318
319    fn delete(self) {
320        // noop
321    }
322}