start 0.1.9

Start – Your embedded database.
Documentation
use std::{cell::{RefCell, RefMut}, rc::Rc};

use super::{catalog::collection::RawDocument, collection::{_SYSTEM_MASTER, _SYSTEM_TRASH}, operation_context::{ensure_capacity, OperationContext}, ops::{self, insert::insert_one_by_offset}, storage::start_storage::StartStorage};

pub fn get_header(op_ctx: &mut OperationContext) -> Header {
    let storage = op_ctx.storage();
    
    if storage.borrow().len() == 0 {
        insert_one_by_offset(op_ctx, _SYSTEM_MASTER.offset, RawDocument {
            next_document: 0,
            content_length: 40,
            content: _SYSTEM_MASTER.to_bytes(),
        });

        insert_one_by_offset(op_ctx, _SYSTEM_TRASH.offset, RawDocument {
            next_document: 0,
            content_length: 40,
            content: _SYSTEM_TRASH.to_bytes(),
        });

        match Header::create(storage) {
            Ok(header) => {
                header
            },
            Err(HeaderError::DatabaseError(err)) => panic!("DBerr: {}", err),
            Err(err) => panic!("Header parsing error: {:?}", err)
        }
    } else {
        match Header::parse(storage) {
            Ok(header) => {
                header
            },
            Err(HeaderError::DatabaseError(err)) => panic!("DBerr: {}", err),
            Err(err) => panic!("Header parsing error: {:?}", err)
        }
    }
}

#[derive(Debug)]
pub struct Header {
    pub magic_number: MagicNumber,
    pub version: Version,
}

#[derive(Debug)]
pub struct MagicNumber(pub u32);

#[derive(Debug)]
pub struct Version(pub String);

// To check that it's database file
const MAGIC_NUMBER: u32 = 0x14841488;
const MAGIC_NUMBER_OFFSET: usize = 0;

const VERSION_OFFSET: usize = 4;
const CURRENT_VERSION: &str = "0.0.1";

impl Header {
    pub fn parse(storage: Rc<RefCell<StartStorage>>) -> Result<Self, HeaderError> {
        let ss_clone = storage.clone();
        let mut ss = ss_clone.borrow_mut();
        let magic_number = if ss.len() > 4 {
            MagicNumber::get(storage.clone())
        } else {
            Err(HeaderError::MagicNumberParsingError(
                "File is too short".to_string()
            ))
        }?;
        Self::ensure_capacity(&mut ss)?;
        
        Ok(Header {
            magic_number,
            version: Version::get(storage)?,
        })
    }

    #[deprecated]
    pub fn create(ss: Rc<RefCell<StartStorage>>) -> Result<Self, HeaderError> {
        Self::ensure_capacity(&mut ss.borrow_mut())?;

        Ok(Header {
            magic_number: MagicNumber::create(ss.clone())?,
            version: Version::create(ss)?,
        })
    }

    fn ensure_capacity(ss: &mut RefMut<'_, StartStorage>) -> Result<(), HeaderError> {
        match ensure_capacity(ss, 100) {
            Ok(_) => Ok(()),
            Err(err) => Err(HeaderError::DatabaseError(
                format!("Ensure capatiry error: {:?}", err).into()
            )),
        }
    }
}

impl MagicNumber {
    #[deprecated]
    fn get(ss: Rc<RefCell<StartStorage>>) -> Result<Self, HeaderError> {
        let ss = ss.borrow();

        let mut bytes = [0u8; 4];
        bytes.copy_from_slice(&ss[0..4]);
        let magic_number = u32::from_le_bytes(bytes);
        if magic_number!=MAGIC_NUMBER {
            return Err(HeaderError::MagicNumberParsingError(
                format!("This's not database file! ({})", magic_number).into()
            ));
        }
        Ok(MagicNumber(magic_number))
    }

    #[deprecated]
    fn create(ss: Rc<RefCell<StartStorage>>) -> Result<Self, HeaderError> {
        let mut ss = ss.borrow_mut();

        ss[MAGIC_NUMBER_OFFSET..MAGIC_NUMBER_OFFSET+4]
            .copy_from_slice(&MAGIC_NUMBER.to_le_bytes());
        Ok(MagicNumber(MAGIC_NUMBER))
    }
}

impl Default for MagicNumber {
    fn default() -> Self {
        Self(Default::default())
    }
}

impl Version {
    #[deprecated]
    fn get(ss: Rc<RefCell<StartStorage>>) -> Result<Self, HeaderError> {
        let ss = ss.borrow();

        let mut bytes = [0u8; 8];
        bytes.copy_from_slice(&ss[VERSION_OFFSET..VERSION_OFFSET+8]);
        match String::from_utf8(bytes.to_vec()) {
            Ok(value) => Ok(Version(
                value.trim_matches(char::from(0))
                .to_string()
            )),
            Err(_) => Err(HeaderError::VersionParsingError(
                "Cannot parse string version".into()
            )),
        }
    }

    #[deprecated]
    fn create(ss: Rc<RefCell<StartStorage>>) -> Result<Self, HeaderError> {
        let mut ss = ss.borrow_mut();

        let mut bytes = [0u8; 8];
        bytes[..CURRENT_VERSION.len()].copy_from_slice(CURRENT_VERSION.as_bytes());
        ss[VERSION_OFFSET..VERSION_OFFSET+8].copy_from_slice(&bytes);
        Ok(Version(CURRENT_VERSION.to_string()))
    }
}

impl Default for Version {
    fn default() -> Self {
        Self(Default::default())
    }
}

#[derive(Debug)]
pub enum HeaderError {
    MagicNumberParsingError(String),
    VersionParsingError(String),
    CollectionsParsingError(String),
    DatabaseError(String)
}