various_data_file 0.14.0

Store a dainary datas in a file. Use mmap, optimize fragments on delete, and reference identical strings.
Documentation
use std::{mem::size_of, num::NonZeroU64, path::Path};

use file_mmap::FileMmap;

use crate::DataAddress;

pub(super) struct FragmentGetResult {
    pub(super) fragment_id: NonZeroU64,
    pub(super) addr: u64,
}

pub(super) struct Fragment {
    filemmap: FileMmap,
}

const DATAADDRESS_SIZE: u64 = size_of::<DataAddress>() as u64;
const COUNTER_SIZE: u64 = size_of::<u64>() as u64;
const INIT_SIZE: u64 = COUNTER_SIZE + DATAADDRESS_SIZE;

impl Fragment {
    pub fn new<P: AsRef<Path>>(path: P) -> Self {
        let mut filemmap = FileMmap::new(path).unwrap();
        if filemmap.len() == 0 {
            filemmap.set_len(INIT_SIZE).unwrap();
        }
        Self { filemmap }
    }

    unsafe fn list(&self) -> *const DataAddress {
        self.filemmap.as_ptr().offset(COUNTER_SIZE as isize) as *const DataAddress
    }

    unsafe fn list_mut(&mut self) -> *mut DataAddress {
        self.filemmap.as_ptr().offset(COUNTER_SIZE as isize) as *mut DataAddress
    }

    pub(crate) fn insert(&mut self, addr: &DataAddress) {
        let record_count = self.filemmap.as_ptr() as *mut u64;
        let record_count = unsafe {
            *record_count += 1;
            *record_count
        };
        let size = INIT_SIZE + DATAADDRESS_SIZE * record_count;
        if self.filemmap.len() < size {
            self.filemmap.set_len(size).unwrap();
        }
        unsafe {
            *self.list_mut().offset(record_count as isize) = addr.clone();
        }
    }

    pub(crate) unsafe fn release(&mut self, row: NonZeroU64, len: usize) {
        let row = row.get() as u64;
        let s = &mut *self.list_mut().offset(row as isize);
        s.offset += len as i64;
        s.len -= len as u64;

        let record_count = self.filemmap.as_ptr() as *mut u64;
        if s.len == 0 && row == *record_count {
            *record_count -= 1;
        }
    }

    pub(crate) fn search_blank(&self, len: usize) -> Option<FragmentGetResult> {
        let record_count = unsafe { *(self.filemmap.as_ptr() as *const u64) };
        if record_count != 0 {
            for index in (-(record_count as isize)..0).map(|i| -i) {
                let s = unsafe { &*self.list().offset(index) };
                if s.len as usize >= len {
                    return Some(FragmentGetResult {
                        fragment_id: unsafe { NonZeroU64::new_unchecked(index as u64) },
                        addr: s.offset as u64,
                    });
                }
            }
        }
        None
    }
}