matdb 0.1.0

An experimental embedded SQL-like DBMS
Documentation
use std::io::{Read, Write};

use anyhow::Result;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use crate::{Db, MAX_KEY_SIZE};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Cell {
    Full(Vec<u8>),
    Partial(Vec<u8>, u64, u64),
}

pub fn write_cell(mut buf: impl Write, cell: &Cell) {
    match cell {
        Cell::Full(vec) => {
            buf.write_u16::<BigEndian>(vec.len() as u16).unwrap();
            buf.write_all(vec).unwrap();
        }
        Cell::Partial(vec, page, len) => {
            buf.write_u16::<BigEndian>(MAX_KEY_SIZE).unwrap();
            buf.write_all(vec).unwrap();
            buf.write_u64::<BigEndian>(*page).unwrap();
            buf.write_u64::<BigEndian>(*len).unwrap();
        }
    }
}

pub fn read_cell<R: Read>(reader: &mut R) -> std::io::Result<Cell> {
    let len = reader.read_u16::<BigEndian>()?;
    if len == MAX_KEY_SIZE {
        let mut buf = vec![0; len as usize - 16];
        reader.read_exact(&mut buf)?;
        let overflow_page = reader.read_u64::<BigEndian>().unwrap();
        let overflow_length = reader.read_u64::<BigEndian>().unwrap();
        Ok(Cell::Partial(buf, overflow_page, overflow_length))
    } else {
        let mut buf = vec![0; len as usize];
        reader.read_exact(&mut buf)?;
        Ok(Cell::Full(buf))
    }
}

pub fn encode_cell(store: &mut Db, v: Vec<u8>) -> Result<Cell> {
    Ok(if v.len() >= MAX_KEY_SIZE as usize {
        let rest = v[MAX_KEY_SIZE as usize - 16..].to_vec();
        let overflow_length = rest.len();
        let overflow_page = store.append_overflow_pages(rest)?;
        Cell::Partial(
            v[0..MAX_KEY_SIZE as usize - 16].to_vec(),
            overflow_page,
            overflow_length as u64,
        )
    } else {
        Cell::Full(v)
    })
}

pub fn fetch_cell(store: &mut Db, cell: &Cell) -> Result<Vec<u8>> {
    Ok(match &cell {
        Cell::Full(vec) => vec.clone(),
        Cell::Partial(part_vec, overflow_page, overflow_length) => [
            part_vec.clone(),
            store.read_overflow_pages(*overflow_page, *overflow_length)?,
        ]
        .concat(),
    })
}

pub fn free_cell(store: &mut Db, cell: &Cell) -> Result<()> {
    match &cell {
        Cell::Full(..) => Ok(()),
        Cell::Partial(_, overflow_page, _) => store.free_overflow_pages(*overflow_page),
    }
}