use crate::{MdbxError, TransactionKind, error::ReadResult, tx::ops};
use ffi::MDBX_txn;
use std::{borrow::Cow, slice};
pub trait TableObjectOwned: for<'de> TableObject<'de> {
fn decode(data_val: &[u8]) -> ReadResult<Self> {
<Self as TableObject<'_>>::decode_borrow(Cow::Borrowed(data_val))
}
}
impl<T> TableObjectOwned for T where T: for<'de> TableObject<'de> {}
pub trait TableObject<'a>: Sized {
fn decode_borrow(data: Cow<'a, [u8]>) -> ReadResult<Self>;
#[doc(hidden)]
#[inline(always)]
unsafe fn decode_val<K: TransactionKind>(
tx: *const MDBX_txn,
data_val: ffi::MDBX_val,
) -> ReadResult<Self> {
let cow = unsafe { Cow::<'a, [u8]>::decode_val::<K>(tx, data_val)? };
Self::decode_borrow(cow)
}
}
impl<'a> TableObject<'a> for Cow<'a, [u8]> {
fn decode_borrow(data: Cow<'a, [u8]>) -> ReadResult<Self> {
Ok(data)
}
#[doc(hidden)]
unsafe fn decode_val<K: TransactionKind>(
txn: *const MDBX_txn,
data_val: ffi::MDBX_val,
) -> ReadResult<Self> {
let s = unsafe { slice::from_raw_parts(data_val.iov_base as *const u8, data_val.iov_len) };
let is_dirty = (!K::IS_READ_ONLY) && unsafe { ops::is_dirty_raw(txn, data_val.iov_base) }?;
Ok(if is_dirty { Cow::Owned(s.to_vec()) } else { Cow::Borrowed(s) })
}
}
impl TableObject<'_> for Vec<u8> {
fn decode_borrow(data: Cow<'_, [u8]>) -> ReadResult<Self> {
Ok(data.into_owned())
}
unsafe fn decode_val<K: TransactionKind>(
_tx: *const MDBX_txn,
data_val: ffi::MDBX_val,
) -> ReadResult<Self> {
let s = unsafe { slice::from_raw_parts(data_val.iov_base as *const u8, data_val.iov_len) };
Ok(s.to_vec())
}
}
impl<'a> TableObject<'a> for () {
fn decode_borrow(_: Cow<'a, [u8]>) -> ReadResult<Self> {
Ok(())
}
unsafe fn decode_val<K: TransactionKind>(
_: *const MDBX_txn,
_: ffi::MDBX_val,
) -> ReadResult<Self> {
Ok(())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct ObjectLength(pub usize);
impl TableObject<'_> for ObjectLength {
fn decode_borrow(data: Cow<'_, [u8]>) -> ReadResult<Self> {
Ok(Self(data.len()))
}
unsafe fn decode_val<K: TransactionKind>(
_tx: *const MDBX_txn,
data_val: ffi::MDBX_val,
) -> ReadResult<Self> {
Ok(Self(data_val.iov_len))
}
}
impl core::ops::Deref for ObjectLength {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, const LEN: usize> TableObject<'a> for [u8; LEN] {
fn decode_borrow(data: Cow<'a, [u8]>) -> ReadResult<Self> {
if data.len() != LEN {
return Err(MdbxError::DecodeErrorLenDiff.into());
}
let mut a = [0; LEN];
a[..].copy_from_slice(&data);
Ok(a)
}
unsafe fn decode_val<K: TransactionKind>(
_tx: *const MDBX_txn,
data_val: ffi::MDBX_val,
) -> ReadResult<Self> {
if data_val.iov_len != LEN {
return Err(MdbxError::DecodeErrorLenDiff.into());
}
let s = unsafe { slice::from_raw_parts(data_val.iov_base as *const u8, data_val.iov_len) };
let mut a = [0; LEN];
a[..].copy_from_slice(s);
Ok(a)
}
}