kvs 0.0.6

Embedded Key-Value Store
Documentation
#![no_std]

use core::str::Utf8Error;

use adapters::StoreAdapter;
use modular_bitfield::prelude::*;

mod alloc;
mod grasshopper;
mod store;

pub mod adapters;

pub use alloc::*;
pub use grasshopper::*;
pub use store::*;

pub const MAX_KEY_LEN: usize = 256;
pub const MAX_VALUE_LEN: usize = 64 * 1024;

pub type Address = usize;

#[derive(Debug)]
pub struct Bucket {
    index: usize,
    raw: RawBucket,
}

impl Bucket {
    pub fn val_address(&self) -> Address {
        let addr = self.raw.address() + self.raw.key_len() as u32;
        addr as Address
    }

    pub(crate) fn index(&self) -> usize {
        self.index
    }

    pub(crate) fn address(&self) -> Address {
        self.raw.address() as Address
    }

    pub fn key_len(&self) -> usize {
        self.raw.key_len() as usize
    }

    pub fn val_len(&self) -> usize {
        self.raw.val_len() as usize
    }

    pub fn record_len(&self) -> usize {
        self.key_len() + self.val_len()
    }
}

#[derive(Debug, PartialEq)]
pub enum Error<E> {
    AdapterError(E),
    IndexOverflow,
    InvalidCapacity,
    InvalidNonce,
    InvalidPatchOffset,
    KeyNotFound,
    ReadOnlyStore,
    StoreNotFound,
    StoreOverflow,
    ValueOverflow,
    KeyOverflow,
    Utf8Error(Utf8Error),
    #[cfg(feature = "serde")]
    SerializationError(postcard::Error),
}

#[bitfield]
pub(crate) struct StoreHeader {
    magic: B32,
    nonce: B16,
    buckets: B16,
}

#[bitfield]
#[derive(Default, Debug, Clone)]
pub(crate) struct RawBucket {
    val_len: B16,
    key_len: B8,
    address: B24,
    hash: B16,
}

pub struct KeysIterator<'a, 'b, A, const BUCKETS: usize, const SLOTS: usize>
where
    A: StoreAdapter,
{
    store: &'a mut KVStore<A, BUCKETS, SLOTS>,
    prefix: Option<&'b [u8]>,
    cursor: usize,
}

impl<'a, 'b, A, const BUCKETS: usize, const SLOTS: usize> KeysIterator<'a, 'b, A, BUCKETS, SLOTS>
where
    A: StoreAdapter,
{
    pub fn new(store: &'a mut KVStore<A, BUCKETS, SLOTS>) -> Self {
        Self {
            store,
            cursor: 0,
            prefix: None,
        }
    }

    pub fn with_prefix(store: &'a mut KVStore<A, BUCKETS, SLOTS>, prefix: &'b [u8]) -> Self {
        Self {
            store,
            cursor: 0,
            prefix: Some(prefix),
        }
    }
}

impl<'a, 'b, A, const BUCKETS: usize, const SLOTS: usize> Iterator
    for KeysIterator<'a, 'b, A, BUCKETS, SLOTS>
where
    A: StoreAdapter,
{
    type Item = KeyReference;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.cursor >= BUCKETS {
                return None;
            }

            let raw = self.store.load_bucket(self.cursor).unwrap_or_default();
            let index = self.cursor;
            self.cursor += 1;

            let key_len = raw.key_len() as usize;
            let prefix_len = self.prefix.map_or(0, |prefix| prefix.len());

            if key_len > prefix_len {
                let val_len = raw.val_len() as usize;
                let bucket = Bucket { index, raw };
                let address = bucket.raw.address() as Address;
                let mut scratch = [0; MAX_KEY_LEN];

                self.store
                    .adapter()
                    .read(address, &mut scratch[..key_len])
                    .ok();

                if matches!(self.prefix, Some(prefix) if &scratch[..prefix_len] != prefix) {
                    continue;
                }

                return Some(KeyReference {
                    key_len,
                    val_len,
                    scratch,
                });
            }
        }
    }
}

pub struct KeyReference {
    key_len: usize,
    val_len: usize,
    scratch: [u8; MAX_KEY_LEN],
}

impl KeyReference {
    pub fn key(&self) -> &[u8] {
        &self.scratch[..self.key_len]
    }

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