mycelium_core 0.1.1

Library for Mycelium DDM
Documentation
use std::collections::HashMap;
use std::error::Error;
use std::fs::{create_dir_all, DirBuilder, File};
use std::io::{prelude::*, Result};
use std::path::PathBuf;

use crate::DbId;
use rayon::prelude::*;
use serde::Serialize;

pub mod history;

#[allow(dead_code)]
pub enum SaveScope {
    All,
    One((&'static str, DbId)),
    Some(Vec<DbId>),
    Tag(&'static str),
}

//pub use self::page::write_to_disk;
pub trait Persistable {
    fn get_id_str(&self) -> &str;
    fn save(&self, path: &std::path::PathBuf) -> std::io::Result<()>;
}

pub(crate) fn prep_tag_directory(dir: &PathBuf) -> Result<()> {
    if dir.exists() {
        Ok(())
    } else {
        create_tag_directory(dir)
    }
}

fn create_tag_directory(dir: &PathBuf) -> Result<()> {
    DirBuilder::new().recursive(true).create(dir)?;
    Ok(())
}

/// Load pages
/// Validate paths are valid page files before passing.
pub(crate) fn load_from_vec(
    page_col: Vec<PathBuf>,
) -> std::result::Result<HashMap<[u8; 16], crate::ephemeral::Page>, Box<dyn std::error::Error>> {
    Ok(page_col
        .par_iter()
        .filter_map(|path_buf| match File::open(&path_buf) {
            Ok(file) => Some(file),
            Err(e) => {
                error!("Error: {:?}", e);
                None
            }
        })
        .map(|file| {
            let mut buffer = Vec::new();
            let mut file = file;
            match file.read_to_end(&mut buffer) {
                Ok(g) => g,
                Err(e) => {
                    panic!("Failed reading file: {:?}", e);
                }
            };
            let mut page: crate::ephemeral::Page = match bincode::deserialize(&buffer) {
                Ok(page) => page,
                Err(e) => panic!(format!("{:?}", e)),
            };
            buffer.clear();

            // Page could have failed to deserialize. Error recorded below this.
            // If deserialization fails skip it. It will be recorded in the error log.
            //let mut page = page.unwrap();
            let id: [u8; 16] = page.get_id();
            page.build_index();
            (id, page)
        })
        .collect())
}

pub fn persist<T: Serialize + Persistable + Clone>(
    item: &T,
    path: &std::path::PathBuf,
) -> std::io::Result<()> {
    let page_vec = match bincode::serialize(&item) {
        Ok(p) => p,
        Err(e) => panic!(
            "Failed to serialize: {}, error: {}",
            item.get_id_str(),
            e.description()
        ),
    };

    crate::persistence::write(page_vec, item.get_id_str(), path)
}

/// Attempt a write to disk. If this fails we will walk down the
/// db structure creation tree. Attempt first extra hit on first
/// record for a tag should mean less than the cost of the
/// extra checking on every record.
pub(crate) fn write(item: Vec<u8>, id: &str, path: &std::path::PathBuf) -> Result<()> {
    let mut file_path = path.to_path_buf();
    if !file_path.exists() {
        create_dir_all(path)?;
    }
    file_path.push(id);

    let mut file = match File::create(file_path) {
        Ok(f) => f,
        Err(e) => {
            error!("Error: {:?}", e);
            unimplemented!()
        }
    };

    match file.write_all(&item) {
        Ok(_) => (),
        Err(e) => {
            error!("Failed to write file to disk: {}", e);
            unimplemented!()
        }
    }

    match file.sync_all() {
        Ok(_) => Ok(()),
        Err(e) => {
            warn!(" ** Failed to write to disk: {:?}", e);
            unimplemented!()
        }
    }
}