stupid-simple-kv 0.3.1

A dead-simple, pluggable, binary-sorted key-value store for Rust with FoundationDB-style keys. In-memory and SQLite backends. Zero-boilerplate and easy iteration.
Documentation
use crate::keys::key_segment::KeySegmentTag;
use crate::{KvError, KvKey};

pub struct KeyDecoder<'a> {
    rem: &'a [u8],
}

impl<'a> KeyDecoder<'a> {
    pub fn new(rem: &'a [u8]) -> Self {
        Self { rem }
    }

    pub fn next_str(&mut self) -> Option<&'a str> {
        if self.rem.len() < 9 || self.rem[0] != KeySegmentTag::String as u8 {
            return None;
        }

        let len = usize::from_be_bytes(self.rem[1..9].try_into().ok()?);
        if self.rem.len() < 9 + len {
            return None;
        }

        let out = str::from_utf8(&self.rem[9..len + 9]).ok()?;
        self.rem = &self.rem[9 + len..];
        Some(out)
    }

    pub fn next_bool(&mut self) -> Option<bool> {
        if self.rem.len() < 2 || self.rem[0] != KeySegmentTag::Bool as u8 {
            return None;
        }
        let byte = self.rem[1];
        self.rem = &self.rem[2..];
        Some(byte != 0)
    }

    pub fn next_i64(&mut self) -> Option<i64> {
        if self.rem.len() < 9 || self.rem[0] != KeySegmentTag::I64 as u8 {
            return None;
        }
        let bytes: [u8; 8] = self.rem[1..9].try_into().ok()?;
        let int = i64::from_be_bytes(bytes);
        self.rem = &self.rem[9..];
        Some(int)
    }

    pub fn next_u64(&mut self) -> Option<u64> {
        if self.rem.len() < 9 || self.rem[0] != KeySegmentTag::U64 as u8 {
            return None;
        }
        let bytes: [u8; 8] = self.rem[1..9].try_into().ok()?;
        let num = u64::from_be_bytes(bytes);
        self.rem = &self.rem[9..];
        Some(num)
    }
}

pub trait FromKvKey<'a>: Sized {
    fn from_kv_key(decoder: &mut KeyDecoder<'a>) -> Option<Self>;
}

impl<'a> FromKvKey<'a> for i64 {
    fn from_kv_key(decoder: &mut KeyDecoder<'a>) -> Option<Self> {
        decoder.next_i64()
    }
}

impl<'a> FromKvKey<'a> for u64 {
    fn from_kv_key(decoder: &mut KeyDecoder<'a>) -> Option<Self> {
        decoder.next_u64()
    }
}

impl<'a> FromKvKey<'a> for bool {
    fn from_kv_key(decoder: &mut KeyDecoder<'a>) -> Option<Self> {
        decoder.next_bool()
    }
}

impl<'a> FromKvKey<'a> for &'a str {
    fn from_kv_key(decoder: &mut KeyDecoder<'a>) -> Option<Self> {
        decoder.next_str()
    }
}

impl<'a> FromKvKey<'a> for String {
    fn from_kv_key(decoder: &mut KeyDecoder<'a>) -> Option<Self> {
        decoder.next_str().map(String::from)
    }
}

macro_rules! impl_key_decode_for_tuple {
    ($($name:ident),+) => {
        impl<'a, $($name),+> FromKvKey<'a> for ($($name,)+)
        where
            $($name: FromKvKey<'a>),+
        {
            fn from_kv_key(decoder: &mut KeyDecoder<'a>) -> Option<Self> {
                Some((
                    $(
                        <$name as FromKvKey>::from_kv_key(decoder)?,
                    )+
                ))
            }
        }
    };
}

impl_key_decode_for_tuple!(A);
impl_key_decode_for_tuple!(A, B);
impl_key_decode_for_tuple!(A, B, C);
impl_key_decode_for_tuple!(A, B, C, D);
impl_key_decode_for_tuple!(A, B, C, D, E);
impl_key_decode_for_tuple!(A, B, C, D, E, F);
impl_key_decode_for_tuple!(A, B, C, D, E, F, G);
impl_key_decode_for_tuple!(A, B, C, D, E, F, G, H);
impl_key_decode_for_tuple!(A, B, C, D, E, F, G, H, I);

macro_rules! impl_kv_key_try_from_tuple {
    ($($name:ident),+) => {
        impl<$($name: for<'a> FromKvKey<'a>),+> TryFrom<KvKey> for ($($name,)+) {
            type Error = KvError;
            fn try_from(key: KvKey) -> Result<Self, Self::Error> {
                let mut decoder = KeyDecoder::new(&key.0);
                $(
                    #[allow(non_snake_case)]
                    let $name = <$name as FromKvKey>::from_kv_key(&mut decoder)
                        .ok_or_else(|| KvError::KeyDecodeError(
                            format!("Failed to decode key segment \"{}\"", stringify!($name)))
                        )?;
                )+
                Ok(($($name,)+))
            }
        }
    }
}

impl_kv_key_try_from_tuple!(A);
impl_kv_key_try_from_tuple!(A, B);
impl_kv_key_try_from_tuple!(A, B, C);
impl_kv_key_try_from_tuple!(A, B, C, D);
impl_kv_key_try_from_tuple!(A, B, C, D, E);
impl_kv_key_try_from_tuple!(A, B, C, D, E, F);
impl_kv_key_try_from_tuple!(A, B, C, D, E, F, G);
impl_kv_key_try_from_tuple!(A, B, C, D, E, F, G, H);
impl_kv_key_try_from_tuple!(A, B, C, D, E, F, G, H, I);