liteboxfs 0.1.0

A modern POSIX filesystem in a SQLite database
Documentation
mod logical;
mod memory;
mod truncate;
mod write;

use xpct::matchers::collections::Len;

use super::{
    BlockId,
    adapter::ChunkingBlockStoreAdapter,
    store::BlockStore,
    types::{BlockLen, BlockList, BlockSignature, FileId},
};
use crate::{
    chunker::NopChunker,
    hash::{BlockHash, BlockHasher},
    settings::Settings,
    testing::{Case, MemoryBlockStore, random_buf},
};

#[derive(Debug)]
pub struct DataBlock {
    pub id: BlockId,
    pub bytes: Vec<u8>,
    pub hash: BlockHash,
    pub signature: BlockSignature,
}

pub const TEST_BLOCK_SIZE: BlockLen = 8;

pub trait BlockStoreTestExt: BlockStore {
    fn insert_data(&mut self, file_id: FileId, index: usize) -> crate::Result<DataBlock> {
        let bytes = random_buf(TEST_BLOCK_SIZE, Case::Lower);
        let hash = BlockHasher::hash(&bytes);

        let block_id = self.insert_block(file_id, index, bytes.as_slice().into())?;

        Ok(DataBlock {
            id: block_id,
            bytes,
            hash: hash.clone(),
            signature: BlockSignature::Data {
                hash,
                len: TEST_BLOCK_SIZE,
            },
        })
    }

    fn replace_data(&mut self, file_id: FileId, index: usize) -> crate::Result<DataBlock> {
        let bytes = random_buf(TEST_BLOCK_SIZE, Case::Lower);
        let hash = BlockHasher::hash(&bytes);

        let block_id = self.replace_block(file_id, index, bytes.as_slice().into())?;

        Ok(DataBlock {
            id: block_id,
            bytes,
            hash: hash.clone(),
            signature: BlockSignature::Data {
                hash,
                len: TEST_BLOCK_SIZE,
            },
        })
    }
}

impl<T: BlockStore> BlockStoreTestExt for T {}

impl ChunkingBlockStoreAdapter<MemoryBlockStore> {
    /// Get a block store adapter which does not perform chunking.
    pub fn without_chunking(inner: MemoryBlockStore) -> Self {
        let settings = Settings {
            // Disable the small write optimization for these tests.
            small_write_threshold: 0,
            ..Default::default()
        };

        ChunkingBlockStoreAdapter::new(inner, NopChunker::new(), settings)
    }

    pub fn with_small_write_threshold(
        inner: MemoryBlockStore,
        small_write_threshold: usize,
    ) -> Self {
        let settings = Settings {
            small_write_threshold,
            ..Default::default()
        };

        ChunkingBlockStoreAdapter::new(inner, NopChunker::new(), settings)
    }
}

impl Len for BlockSignature {
    fn len(&self) -> usize {
        self.len()
    }
}

impl Len for &BlockSignature {
    fn len(&self) -> usize {
        (*self).len()
    }
}

impl Len for BlockList {
    fn len(&self) -> usize {
        self.len()
    }
}

impl Len for &BlockList {
    fn len(&self) -> usize {
        (*self).len()
    }
}