haematite 0.6.1

Content-addressed, branchable, actor-native storage engine
Documentation
use std::collections::BTreeMap;
use std::fmt;
use std::sync::Arc;

use crate::store::NodeStore;
use crate::tree::{Hash, Node};

use super::BrowserSourceError;

#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct BrowserNodeError(pub(super) BrowserSourceError);

impl fmt::Display for BrowserNodeError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(formatter)
    }
}

impl std::error::Error for BrowserNodeError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        Some(&self.0)
    }
}

#[derive(Debug, Default)]
pub(super) struct BrowserNodeStore {
    nodes: BTreeMap<Hash, Vec<u8>>,
}

impl BrowserNodeStore {
    pub(super) fn from_serialized(
        nodes: BTreeMap<Hash, Vec<u8>>,
    ) -> Result<Self, BrowserNodeError> {
        for (hash, bytes) in &nodes {
            let node = Node::deserialise(bytes)
                .map_err(|error| BrowserNodeError(BrowserSourceError::Node { error }))?;
            if node.hash() != *hash {
                return Err(BrowserNodeError(BrowserSourceError::NodeHashMismatch {
                    expected: *hash,
                    actual: node.hash(),
                }));
            }
        }
        Ok(Self { nodes })
    }

    pub(super) const fn serialized(&self) -> &BTreeMap<Hash, Vec<u8>> {
        &self.nodes
    }
}

impl NodeStore for BrowserNodeStore {
    type Error = BrowserNodeError;

    fn get(&self, hash: &Hash) -> Result<Option<Arc<Node>>, Self::Error> {
        self.nodes
            .get(hash)
            .map(|bytes| Node::deserialise(bytes).map(Arc::new))
            .transpose()
            .map_err(|error| BrowserNodeError(BrowserSourceError::Node { error }))
    }

    fn put(&mut self, node: &Node) -> Result<Hash, Self::Error> {
        let hash = node.hash();
        self.nodes.insert(hash, node.serialise());
        Ok(hash)
    }
}