libmdbx 0.6.6

Idiomatic and safe MDBX wrapper.
Documentation
use super::traits::*;
use crate::{RW, TransactionKind, WriteFlags};
use std::marker::PhantomData;

#[derive(Clone, Debug)]
pub(crate) struct DecodableWrapper<T>(pub T);

impl<T> crate::Decodable<'_> for DecodableWrapper<T>
where
    T: Decodable,
{
    fn decode(data_val: &[u8]) -> Result<Self, crate::Error>
    where
        Self: Sized,
    {
        T::decode(data_val)
            .map_err(|e| crate::Error::DecodeError(e.into()))
            .map(Self)
    }
}

#[derive(Debug)]
pub struct Cursor<'tx, K, T>
where
    K: TransactionKind,
    T: Table,
{
    pub(crate) inner: crate::Cursor<'tx, K>,
    pub(crate) _marker: PhantomData<T>,
}

#[allow(clippy::type_complexity)]
fn map_res_inner<T, E>(
    v: Result<Option<(DecodableWrapper<T::Key>, DecodableWrapper<T::Value>)>, E>,
) -> anyhow::Result<Option<(T::Key, T::Value)>>
where
    T: Table<Key: Decodable>,
    E: std::error::Error + Send + Sync + 'static,
{
    if let Some((k, v)) = v? {
        return Ok(Some((k.0, v.0)));
    }

    Ok(None)
}

impl<K, T> Cursor<'_, K, T>
where
    K: TransactionKind,
    T: Table,
{
    pub fn first(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.first())
    }

    pub fn seek_closest(&mut self, key: T::SeekKey) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.set_range(key.encode().as_ref()))
    }

    pub fn seek_exact(&mut self, key: T::Key) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.set_key(key.encode().as_ref()))
    }

    #[allow(clippy::should_implement_trait)]
    pub fn next(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.next())
    }

    pub fn prev(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.prev())
    }

    pub fn last(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.last())
    }

    pub fn current(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.get_current())
    }

    pub fn walk(
        self,
        start: Option<T::SeekKey>,
    ) -> impl Iterator<Item = anyhow::Result<(T::Key, T::Value)>>
    where
        T: Table<Key: Decodable>,
    {
        struct I<'tx, K, T>
        where
            K: TransactionKind,
            T: Table<Key: Decodable>,
        {
            cursor: Cursor<'tx, K, T>,
            start: Option<T::SeekKey>,

            first: bool,
        }

        impl<K, T> Iterator for I<'_, K, T>
        where
            K: TransactionKind,
            T: Table<Key: Decodable>,
        {
            type Item = anyhow::Result<(T::Key, T::Value)>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.first {
                    self.first = false;
                    if let Some(start) = self.start.take() {
                        self.cursor.seek_closest(start)
                    } else {
                        self.cursor.first()
                    }
                } else {
                    self.cursor.next()
                }
                .transpose()
            }
        }

        I {
            cursor: self,
            start,
            first: true,
        }
    }

    pub fn walk_back(
        self,
        start: Option<T::SeekKey>,
    ) -> impl Iterator<Item = anyhow::Result<(T::Key, T::Value)>>
    where
        T: Table<Key: Decodable>,
    {
        struct I<'tx, K, T>
        where
            K: TransactionKind,
            T: Table<Key: Decodable>,
        {
            cursor: Cursor<'tx, K, T>,
            start: Option<T::SeekKey>,

            first: bool,
        }

        impl<K, T> Iterator for I<'_, K, T>
        where
            K: TransactionKind,
            T: Table<Key: Decodable>,
        {
            type Item = anyhow::Result<(T::Key, T::Value)>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.first {
                    self.first = false;
                    if let Some(start_key) = self.start.take() {
                        self.cursor.seek_closest(start_key)
                    } else {
                        self.cursor.last()
                    }
                } else {
                    self.cursor.prev()
                }
                .transpose()
            }
        }

        I {
            cursor: self,
            start,
            first: true,
        }
    }
}

impl<K, T> Cursor<'_, K, T>
where
    K: TransactionKind,
    T: DupSort,
{
    pub fn seek_value(
        &mut self,
        key: T::Key,
        seek_value: T::SeekValue,
    ) -> anyhow::Result<Option<T::Value>>
    where
        T::Key: Clone,
    {
        let res = self.inner.get_both_range::<DecodableWrapper<T::Value>>(
            key.encode().as_ref(),
            seek_value.encode().as_ref(),
        )?;

        if let Some(v) = res {
            return Ok(Some(v.0));
        }

        Ok(None)
    }

    pub fn last_value(&mut self) -> anyhow::Result<Option<T::Value>>
    where
        T::Key: Decodable,
    {
        Ok(self
            .inner
            .last_dup::<DecodableWrapper<T::Value>>()?
            .map(|v| v.0))
    }

    pub fn next_key(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.next_nodup())
    }

    pub fn next_value(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.next_dup())
    }

    pub fn prev_key(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.prev_nodup())
    }

    pub fn prev_value(&mut self) -> anyhow::Result<Option<(T::Key, T::Value)>>
    where
        T::Key: Decodable,
    {
        map_res_inner::<T, _>(self.inner.prev_dup())
    }

    pub fn walk_key(
        self,
        start: T::Key,
        seek_value: Option<T::SeekValue>,
    ) -> impl Iterator<Item = anyhow::Result<T::Value>>
    where
        T::Key: Clone + Decodable,
    {
        struct I<'tx, K, T>
        where
            K: TransactionKind,
            T: DupSort<Key: Clone + Decodable>,
        {
            cursor: Cursor<'tx, K, T>,
            start: Option<T::Key>,
            seek_value: Option<T::SeekValue>,

            first: bool,
        }

        impl<K, T> Iterator for I<'_, K, T>
        where
            K: TransactionKind,
            T: DupSort<Key: Clone + Decodable>,
        {
            type Item = anyhow::Result<T::Value>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.first {
                    self.first = false;
                    let start_key = self.start.take().unwrap();
                    if let Some(seek_both_key) = self.seek_value.take() {
                        self.cursor.seek_value(start_key, seek_both_key)
                    } else {
                        self.cursor.seek_exact(start_key).map(|v| v.map(|(_, v)| v))
                    }
                } else {
                    self.cursor.next_value().map(|v| v.map(|(_, v)| v))
                }
                .transpose()
            }
        }

        I {
            cursor: self,
            start: Some(start),
            seek_value,
            first: true,
        }
    }
}

impl<T> Cursor<'_, RW, T>
where
    T: Table,
{
    pub fn upsert(&mut self, key: T::Key, value: T::Value) -> anyhow::Result<()> {
        Ok(self.inner.put(
            key.encode().as_ref(),
            value.encode().as_ref(),
            WriteFlags::UPSERT,
        )?)
    }

    pub fn append(&mut self, key: T::Key, value: T::Value) -> anyhow::Result<()> {
        Ok(self.inner.put(
            key.encode().as_ref(),
            value.encode().as_ref(),
            WriteFlags::APPEND,
        )?)
    }

    pub fn delete_current(&mut self) -> anyhow::Result<()> {
        self.inner.del(WriteFlags::CURRENT)?;

        Ok(())
    }
}

impl<T> Cursor<'_, RW, T>
where
    T: DupSort,
{
    pub fn delete_current_key(&mut self) -> anyhow::Result<()> {
        Ok(self.inner.del(WriteFlags::NO_DUP_DATA)?)
    }
    pub fn append_value(&mut self, key: T::Key, value: T::Value) -> anyhow::Result<()> {
        Ok(self.inner.put(
            key.encode().as_ref(),
            value.encode().as_ref(),
            WriteFlags::APPEND_DUP,
        )?)
    }
}