dodo 0.3.1

Basic persistence library designed to be a quick and easy way to create a persistent storage.
Documentation
//! Memory storage backend (using HashMap).

use std::{collections::HashMap, io, sync::{Arc, RwLock}, vec};

use uuid::Uuid;

use super::{Result, Storage, StorageError};

/// Memory storage.
///
/// This storage is quite inefficient and **should only be used for testing purposes** or
/// prototyping.
///
/// ## Locking strategy
///
/// This storage does not have any entry locking mechanism. However, it guarantees that data
/// will not be modified while reading it.
///
/// Because there is no locking, multiple writers are allowed, causing potential data loss in
/// certain race condition scenarios.
#[derive(Debug, Clone, Default)]
pub struct Memory {
    entries: Arc<RwLock<HashMap<Uuid, Bytes>>>
}

impl Memory {
    /// Create a new memory storage.
    ///
    /// # Examples
    ///
    /// ```
    /// use dodo::prelude::*;
    /// use dodo::storage::Memory;
    ///
    /// fn main() {
    ///     let memory = Memory::new();
    /// }
    /// ```
    pub fn new() -> Self {
        Self::default()
    }
}

impl Storage for Memory {
    type Read = BytesReader;
    type Write = BytesWriter;
    type Iterator = Iter;

    fn new(&mut self) -> Result<(Uuid, Self::Write)> {
        let mut entries = self.entries.write().unwrap();

        //Loop until we find a unused id. Having a id collision is very unlikely, but we never know...
        loop {
            let entry = Uuid::new_v4();
            match entries.get(&entry) {
                None => {
                    return Ok((entry, BytesWriter::write(entries.entry(entry).or_default())));
                }
                Some(_) => {
                    continue;
                }
            }
        }
    }

    fn read(&self, entry: Uuid) -> Result<Self::Read> {
        let entries = self.entries.read().unwrap();

        match entries.get(&entry) {
            Some(bytes) => {
                let bytes = bytes.read().unwrap();
                match *bytes {
                    Some(ref bytes) => Ok(BytesReader::read(bytes)),
                    //Entry might exist, but nothing has been writen to it yet.
                    //In that case, we consider that is doesn't exist.
                    None => Err(StorageError::not_found())
                }
            }
            None => Err(StorageError::not_found())
        }
    }

    fn write(&mut self, entry: Uuid) -> Result<Self::Write> {
        let mut entries = self.entries.write().unwrap();

        Ok(BytesWriter::write(entries.entry(entry).or_default()))
    }

    fn overwrite(&mut self, entry: Uuid) -> Result<Self::Write> {
        let entries = self.entries.read().unwrap();

        match entries.get(&entry) {
            Some(bytes) => Ok(BytesWriter::write(bytes)),
            None => Err(StorageError::not_found())
        }
    }

    fn delete(&mut self, entry: Uuid) -> Result<bool> {
        let mut entries = self.entries.write().unwrap();

        Ok(entries.remove(&entry).is_some())
    }

    fn clear(&mut self) -> Result<()> {
        let mut entries = self.entries.write().unwrap();

        Ok(entries.clear())
    }

    fn iter(&self) -> Result<Self::Iterator> {
        let entries = self.entries.read().unwrap();

        Ok(entries
            .keys()
            .map(|entry| Ok(entry.clone()))
            .collect::<Vec<Result<Uuid>>>()
            .into_iter()
        )
    }
}

//When created, the bytes might not have been writen to yet. This is why there is an "Option" here.
type Bytes = Arc<RwLock<Option<Vec<u8>>>>;

/// Memory entry reader.
#[derive(Debug)]
pub struct BytesReader {
    bytes: Vec<u8>,
    index: usize,
}

impl BytesReader {
    fn read(bytes: &Vec<u8>) -> Self {
        Self {
            bytes: bytes.clone(),
            index: 0,
        }
    }
}

impl io::Read for BytesReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        use std::cmp::min;

        let len = min(self.bytes.len() - self.index, buf.len());
        let src = &self.bytes[self.index..self.index + len];
        let dest = &mut buf[..len];
        dest.copy_from_slice(&src);

        self.index += len;
        Ok(len)
    }
}

/// Memory entry writer.
#[derive(Debug)]
pub struct BytesWriter {
    bytes: Bytes,
    new_bytes: Vec<u8>,
}

impl BytesWriter {
    fn write(entry: &Bytes) -> Self {
        Self {
            bytes: entry.clone(),
            new_bytes: Vec::new(),
        }
    }
}

impl io::Write for BytesWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.new_bytes.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.new_bytes.flush()
    }
}

impl Drop for BytesWriter {
    fn drop(&mut self) {
        //Write everything at once when dropped.
        let mut entry = self.bytes.write().unwrap();
        *entry = Some(self.new_bytes.clone());
    }
}

/// Memory iterator.
pub type Iter = vec::IntoIter<Result<Uuid>>;