brk_vecs 0.0.85

A KISS index/value store
Documentation
use std::sync::Arc;

use parking_lot::RwLock;
use zerocopy::{FromBytes, IntoBytes};

use crate::{
    File, Result,
    file::{Region, RegionReader},
};

use super::Page;

#[derive(Debug, Clone)]
pub struct Pages {
    _region: Arc<RwLock<Region>>,
    region_index: usize,

    vec: Vec<Page>,
    change_at: Option<usize>,
}

impl Pages {
    const SIZE_OF_PAGE: usize = size_of::<Page>();

    pub fn import(file: &File, name: &str) -> Result<Self> {
        let (region_index, _region) = file.create_region_if_needed(name)?;

        let vec = _region
            .read()
            .create_reader(file)
            .read_all()
            .chunks(Self::SIZE_OF_PAGE)
            .map(|b| Page::read_from_bytes(b).map_err(|e| e.into()))
            .collect::<Result<_>>()?;

        Ok(Self {
            _region,
            region_index,
            vec,
            change_at: None,
        })
    }

    pub fn flush(&mut self, file: &File) -> Result<()> {
        if self.change_at.is_none() {
            return Ok(());
        }

        let change_at = self.change_at.take().unwrap();
        let at = (change_at * Self::SIZE_OF_PAGE) as u64;

        file.truncate_write_all_to_region(
            self.region_index.into(),
            at,
            self.vec[change_at..].as_bytes(),
        )?;

        Ok(())
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn get(&self, page_index: usize) -> Option<&Page> {
        self.vec.get(page_index)
    }

    pub fn last(&self) -> Option<&Page> {
        self.vec.last()
    }

    pub fn pop(&mut self) -> Option<Page> {
        let popped = self.vec.pop();
        if popped.is_some() {
            self.set_changed_at(self.vec.len());
        }
        popped
    }

    pub fn checked_push(&mut self, page_index: usize, page: Page) {
        if page_index != self.vec.len() {
            panic!();
        }

        self.set_changed_at(page_index);

        self.vec.push(page);
    }

    fn set_changed_at(&mut self, page_index: usize) {
        if self.change_at.is_none_or(|pi| pi > page_index) {
            self.change_at.replace(page_index);
        }
    }

    pub fn reset(&mut self, file: &File) -> Result<()> {
        self.truncate(0);
        self.flush(file)
    }

    pub fn truncate(&mut self, page_index: usize) -> Option<Page> {
        let page = self.get(page_index).cloned();
        self.vec.truncate(page_index);
        self.set_changed_at(page_index);
        page
    }

    pub fn stored_len(&self, per_page: usize) -> usize {
        if let Some(last) = self.last() {
            (self.len() - 1) * per_page + last.values as usize
        } else {
            0
        }
    }
}