liteboxfs 0.1.0

A modern POSIX filesystem in a SQLite database
Documentation
use std::ops::RangeBounds;

use super::types::BlockSignature;

pub trait EjectBuf {
    fn eject(self) -> Vec<u8>;
}

#[derive(Debug)]
pub struct FullSliceBuf {
    buf: Vec<u8>,
}

impl FullSliceBuf {
    pub fn new(buf: Vec<u8>) -> Self {
        FullSliceBuf { buf }
    }

    pub fn splice<R, I>(&mut self, range: R, replace_with: I)
    where
        R: RangeBounds<usize>,
        I: IntoIterator<Item = u8>,
    {
        self.buf.splice(range, replace_with);
    }
}

impl EjectBuf for FullSliceBuf {
    fn eject(mut self) -> Vec<u8> {
        self.buf.clear();
        self.buf
    }
}

impl AsRef<[u8]> for FullSliceBuf {
    fn as_ref(&self) -> &[u8] {
        self.buf.as_ref()
    }
}

impl AsMut<[u8]> for FullSliceBuf {
    fn as_mut(&mut self) -> &mut [u8] {
        self.buf.as_mut()
    }
}

#[derive(Debug)]
pub struct PartialSliceBuf {
    buf: Vec<u8>,
    first_block: Option<BlockSignature>,
    last_block: Option<BlockSignature>,
}

impl PartialSliceBuf {
    pub fn new(
        buf: Vec<u8>,
        first_block: Option<BlockSignature>,
        last_block: Option<BlockSignature>,
    ) -> Self {
        PartialSliceBuf {
            buf,
            first_block,
            last_block,
        }
    }

    pub fn first_block_signature(&self) -> Option<&BlockSignature> {
        self.first_block.as_ref()
    }

    pub fn last_block_signature(&self) -> Option<&BlockSignature> {
        self.last_block.as_ref()
    }

    /// The bytes of the first block in the slice, or `None` if the first block is a hole or the
    /// slice is empty. Hole blocks contribute no bytes to the buffer.
    pub fn first_block_data(&self) -> Option<&[u8]> {
        match &self.first_block {
            Some(BlockSignature::Data { len, .. }) => Some(
                self.buf
                    .get(0..*len)
                    .expect("Partial slice buffer unexpectedly missing the first block."),
            ),
            _ => None,
        }
    }

    /// The bytes of the last block in the slice, or `None` if the last block is a hole or the slice
    /// is empty.
    pub fn last_block_data(&self) -> Option<&[u8]> {
        let first_data_len = match &self.first_block {
            Some(BlockSignature::Data { len, .. }) => *len,
            _ => 0,
        };

        match &self.last_block {
            Some(BlockSignature::Data { len, .. }) => Some(
                self.buf
                    .get(first_data_len..(first_data_len + *len))
                    .expect("Partial slice buffer unexpectedly missing the last block."),
            ),
            _ => None,
        }
    }
}

impl EjectBuf for PartialSliceBuf {
    fn eject(mut self) -> Vec<u8> {
        self.buf.clear();
        self.buf
    }
}

pub enum SliceBuf {
    Full(FullSliceBuf),
    Partial(PartialSliceBuf),
}

impl EjectBuf for SliceBuf {
    fn eject(self) -> Vec<u8> {
        match self {
            SliceBuf::Full(b) => b.eject(),
            SliceBuf::Partial(b) => b.eject(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SliceReadMode {
    Full,
    Partial,
}