Skip to main content

libmdbx/
codec.rs

1use crate::{Error, TransactionKind, error::mdbx_result};
2use derive_more::{Deref, DerefMut, Display};
3use std::{borrow::Cow, slice};
4use thiserror::Error;
5
6/// Implement this to be able to decode data values
7pub trait Decodable<'tx> {
8    fn decode(data_val: &[u8]) -> Result<Self, Error>
9    where
10        Self: Sized;
11
12    #[doc(hidden)]
13    unsafe fn decode_val<K: TransactionKind>(
14        _: *const ffi::MDBX_txn,
15        data_val: &ffi::MDBX_val,
16    ) -> Result<Self, Error>
17    where
18        Self: Sized,
19    {
20        let s = unsafe { slice::from_raw_parts(data_val.iov_base as *const u8, data_val.iov_len) };
21
22        Decodable::decode(s)
23    }
24}
25
26impl<'tx> Decodable<'tx> for Cow<'tx, [u8]> {
27    fn decode(_: &[u8]) -> Result<Self, Error> {
28        unreachable!()
29    }
30
31    #[doc(hidden)]
32    unsafe fn decode_val<K: TransactionKind>(
33        txn: *const ffi::MDBX_txn,
34        data_val: &ffi::MDBX_val,
35    ) -> Result<Self, Error> {
36        let is_dirty =
37            (!K::ONLY_CLEAN) && mdbx_result(unsafe { ffi::mdbx_is_dirty(txn, data_val.iov_base) })?;
38
39        let s = unsafe { slice::from_raw_parts(data_val.iov_base as *const u8, data_val.iov_len) };
40
41        Ok(if is_dirty {
42            Cow::Owned(s.to_vec())
43        } else {
44            Cow::Borrowed(s)
45        })
46    }
47}
48
49#[cfg(feature = "lifetimed-bytes")]
50impl<'tx> Decodable<'tx> for lifetimed_bytes::Bytes<'tx> {
51    fn decode(_: &[u8]) -> Result<Self, Error> {
52        unreachable!()
53    }
54
55    #[doc(hidden)]
56    unsafe fn decode_val<K: TransactionKind>(
57        txn: *const ffi::MDBX_txn,
58        data_val: &ffi::MDBX_val,
59    ) -> Result<Self, Error> {
60        unsafe { Cow::<'tx, [u8]>::decode_val::<K>(txn, data_val).map(From::from) }
61    }
62}
63
64impl Decodable<'_> for Vec<u8> {
65    fn decode(data_val: &[u8]) -> Result<Self, Error>
66    where
67        Self: Sized,
68    {
69        Ok(data_val.to_vec())
70    }
71}
72
73impl Decodable<'_> for () {
74    fn decode(_: &[u8]) -> Result<Self, Error> {
75        Ok(())
76    }
77
78    unsafe fn decode_val<K: TransactionKind>(
79        _: *const ffi::MDBX_txn,
80        _: &ffi::MDBX_val,
81    ) -> Result<Self, Error> {
82        Ok(())
83    }
84}
85
86/// If you don't need the data itself, just its length.
87#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Deref, DerefMut)]
88pub struct ObjectLength(pub usize);
89
90impl Decodable<'_> for ObjectLength {
91    fn decode(data_val: &[u8]) -> Result<Self, Error>
92    where
93        Self: Sized,
94    {
95        Ok(Self(data_val.len()))
96    }
97}
98
99impl<const LEN: usize> Decodable<'_> for [u8; LEN] {
100    fn decode(data_val: &[u8]) -> Result<Self, Error>
101    where
102        Self: Sized,
103    {
104        #[derive(Clone, Debug, Display, Error)]
105        struct InvalidSize<const LEN: usize> {
106            got: usize,
107        }
108
109        if data_val.len() != LEN {
110            return Err(Error::DecodeError(Box::new(InvalidSize::<LEN> {
111                got: data_val.len(),
112            })));
113        }
114        let mut a = [0; LEN];
115        a[..].copy_from_slice(data_val);
116        Ok(a)
117    }
118}