mycelium_core 0.1.1

Library for Mycelium DDM
Documentation
use crate::persistence::Persistable;
use crate::PageId;
use mycelium_command::node::Node;

use std::collections::HashMap;
use uuid::Uuid;

#[derive(Debug, Serialize, Deserialize)]
pub(crate) enum IndexType {
    History,
    Blob,
}

#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct IndexPage {
    i: Vec<PageId>,
    t: IndexType,
}

///
///  # Page
///
/// Id | Offset Start | Offset End | Type
///  This is a record kept in memory
///  Each page maps to a file. Each file will
///  be of a size related to the number of blocks
///  set in config. Blocks sould be selected based
///  on processor hosting the Stew application.
///  Most processors should default to 32 blocks.
///  Intermediate layer with logic. Each page should
///  size itself correctly with it's disk size not memory
///  size. When we go to save a tag block it should
///  simply be a call to save that serializes all pages
///  within the tag and writes them to disk. Save should
///  be ready and fast.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Page {
    #[serde(skip)]
    dirty: bool,
    id_b: [u8; 16],
    id_str: String,
    #[serde(skip)]
    pub index: HashMap<[u8; 16], usize>,
    pub nodes: Vec<Node>,
    #[serde(skip)]
    max_size: usize,
    size: usize,
    tag: String,
}

impl Page {
    #[allow(dead_code)]
    pub fn new(max_size: usize) -> Self {
        let id = Uuid::new_v4();
        let mut page = Page {
            id_b: *id.as_bytes(),
            id_str: id.to_string(),
            index: HashMap::new(),
            nodes: Vec::new(),
            size: 0,
            tag: String::from("Default"),
            max_size,
            dirty: false,
        };
        page.size = std::mem::size_of_val(&page);
        page
    }

    pub fn add(&mut self, node: Node) -> PageId {
        let node_id = node.get_id();
        self.nodes.push(node);
        self.index.insert(node_id, self.nodes.len() - 1);
        self.get_id()
    }

    pub fn build_index(&mut self) {
        for (i, n) in self.nodes.iter().enumerate() {
            self.index.insert(n.get_id(), i);
        }
    }

    pub fn get_id(&self) -> PageId {
        self.id_b
    }

    pub fn get_nodes(&self) -> &Vec<Node> {
        &self.nodes
    }

    pub fn get_all_nodes(&self) -> &Vec<Node> {
        &self.nodes
    }

    pub fn get_size(&self) -> usize {
        let mut total = 0;
        for x in &self.nodes {
            total += x.get_size();
        }
        total
    }

    pub fn get_max_size(&self) -> usize {
        self.max_size
    }

    #[allow(dead_code)]
    pub fn get_node_count(&self) -> usize {
        self.nodes.len()
    }
}

#[test]
fn add_test() {
    let mut test_page = Page::new(12);
    let node = Node::new([0; 16], vec![0, 0, 0, 0].as_slice());
    test_page.add(node);
    let node = Node::new([1; 16], vec![1, 1, 1, 1].as_slice());
    test_page.add(node);

    // Nodes added to page should be a part of both the collection of nodes and index
    assert!(test_page.index.len() == 2 && test_page.nodes.len() == 2);
}

impl Persistable for Page {
    fn get_id_str(&self) -> &str {
        self.id_str.as_str()
    }

    fn save(&self, path: &std::path::PathBuf) -> std::io::Result<()> {
        crate::persistence::persist(self, path)
    }
}

pub fn create_page(tag: &str, max_size: usize) -> Page {
    let mut page = Page::new(max_size);
    page.tag = tag.to_string();
    page
}

#[test]
fn test_create_page() {
    let page = create_page("test", 100);
    assert!(page.tag == "test" && page.max_size == 100);
}