Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the error returned by the BytesDecode/BytesEncode trait customizable #166

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions heed-traits/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
use std::borrow::Cow;
use std::error::Error as StdError;

/// A boxed `Send + Sync + 'static` error.
pub type BoxedError = Box<dyn StdError + Send + Sync + 'static>;

/// A trait that represents an encoding structure.
pub trait BytesEncode<'a> {
type EItem: ?Sized + 'a;
type Err;

fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<'a, [u8]>, BoxedError>;
fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<'a, [u8]>, Self::Err>;
}

/// A trait that represents a decoding structure.
pub trait BytesDecode<'a> {
type DItem: 'a;
type Err;

fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError>;
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, Self::Err>;
}
12 changes: 7 additions & 5 deletions heed-types/src/cow_slice.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::borrow::Cow;

use bytemuck::{pod_collect_to_vec, try_cast_slice, AnyBitPattern, NoUninit, PodCastError};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use heed_traits::{BytesDecode, BytesEncode};

/// Describes a slice that must be [memory aligned] and
/// will be reallocated if it is not.
Expand All @@ -22,20 +22,22 @@ pub struct CowSlice<T>(std::marker::PhantomData<T>);

impl<'a, T: NoUninit> BytesEncode<'a> for CowSlice<T> {
type EItem = [T];
type Err = PodCastError;

fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
try_cast_slice(item).map(Cow::Borrowed).map_err(Into::into)
fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
try_cast_slice(item).map(Cow::Borrowed)
}
}

impl<'a, T: AnyBitPattern + NoUninit> BytesDecode<'a> for CowSlice<T> {
type DItem = Cow<'a, [T]>;
type Err = PodCastError;

fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, Self::Err> {
match try_cast_slice(bytes) {
Ok(items) => Ok(Cow::Borrowed(items)),
Err(PodCastError::AlignmentMismatch) => Ok(Cow::Owned(pod_collect_to_vec(bytes))),
Err(error) => Err(error.into()),
Err(error) => Err(error),
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions heed-types/src/cow_type.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::borrow::Cow;
use std::convert::Infallible;

use bytemuck::{bytes_of, bytes_of_mut, try_from_bytes, AnyBitPattern, NoUninit, PodCastError};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use heed_traits::{BytesDecode, BytesEncode};

/// Describes a type that must be [memory aligned] and
/// will be reallocated if it is not.
Expand All @@ -28,24 +29,26 @@ pub struct CowType<T>(std::marker::PhantomData<T>);

impl<'a, T: NoUninit> BytesEncode<'a> for CowType<T> {
type EItem = T;
type Err = Infallible;

fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
Ok(Cow::Borrowed(bytes_of(item)))
}
}

impl<'a, T: AnyBitPattern + NoUninit> BytesDecode<'a> for CowType<T> {
type DItem = Cow<'a, T>;
type Err = PodCastError;

fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, Self::Err> {
match try_from_bytes(bytes) {
Ok(item) => Ok(Cow::Borrowed(item)),
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
let mut item = T::zeroed();
bytes_of_mut(&mut item).copy_from_slice(bytes);
Ok(Cow::Owned(item))
}
Err(error) => Err(error.into()),
Err(error) => Err(error),
}
}
}
Expand Down
23 changes: 15 additions & 8 deletions heed-types/src/integer.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@
use std::borrow::Cow;
use std::convert::Infallible;
use std::marker::PhantomData;
use std::mem::size_of;

use byteorder::{ByteOrder, ReadBytesExt};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use heed_traits::{BytesDecode, BytesEncode};

pub struct U8;

impl BytesEncode<'_> for U8 {
type EItem = u8;
type Err = Infallible;

fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
Ok(Cow::from([*item].to_vec()))
}
}

impl BytesDecode<'_> for U8 {
type DItem = u8;
type Err = std::io::Error;

fn bytes_decode(mut bytes: &'_ [u8]) -> Result<Self::DItem, BoxedError> {
bytes.read_u8().map_err(Into::into)
fn bytes_decode(mut bytes: &'_ [u8]) -> Result<Self::DItem, Self::Err> {
bytes.read_u8()
}
}

pub struct I8;

impl BytesEncode<'_> for I8 {
type EItem = i8;
type Err = Infallible;

fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
Ok(Cow::from([*item as u8].to_vec()))
}
}

impl BytesDecode<'_> for I8 {
type DItem = i8;
type Err = std::io::Error;

fn bytes_decode(mut bytes: &'_ [u8]) -> Result<Self::DItem, BoxedError> {
fn bytes_decode(mut bytes: &'_ [u8]) -> Result<Self::DItem, Self::Err> {
bytes.read_i8().map_err(Into::into)
}
}
Expand All @@ -47,8 +52,9 @@ macro_rules! define_type {

impl<O: ByteOrder> BytesEncode<'_> for $name<O> {
type EItem = $native;
type Err = Infallible;

fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
let mut buf = [0; size_of::<Self::EItem>()];
O::$write_method(&mut buf, *item);
Ok(Cow::from(buf.to_vec()))
Expand All @@ -57,8 +63,9 @@ macro_rules! define_type {

impl<O: ByteOrder> BytesDecode<'_> for $name<O> {
type DItem = $native;
type Err = std::io::Error;

fn bytes_decode(mut bytes: &'_ [u8]) -> Result<Self::DItem, BoxedError> {
fn bytes_decode(mut bytes: &'_ [u8]) -> Result<Self::DItem, Self::Err> {
bytes.$read_method::<O>().map_err(Into::into)
}
}
Expand Down
5 changes: 3 additions & 2 deletions heed-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ mod serde_bincode;
#[cfg(feature = "serde-json")]
mod serde_json;

use heed_traits::BoxedError;
use std::convert::Infallible;

pub use self::cow_slice::CowSlice;
pub use self::cow_type::CowType;
Expand All @@ -63,8 +63,9 @@ pub struct DecodeIgnore;

impl heed_traits::BytesDecode<'_> for DecodeIgnore {
type DItem = ();
type Err = Infallible;

fn bytes_decode(_bytes: &[u8]) -> Result<Self::DItem, BoxedError> {
fn bytes_decode(_bytes: &[u8]) -> Result<Self::DItem, Self::Err> {
Ok(())
}
}
Expand Down
12 changes: 7 additions & 5 deletions heed-types/src/owned_slice.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::borrow::Cow;

use bytemuck::{try_cast_slice, AnyBitPattern, NoUninit};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use bytemuck::{try_cast_slice, AnyBitPattern, NoUninit, PodCastError};
use heed_traits::{BytesDecode, BytesEncode};

use crate::CowSlice;

Expand All @@ -22,16 +22,18 @@ pub struct OwnedSlice<T>(std::marker::PhantomData<T>);

impl<'a, T: NoUninit> BytesEncode<'a> for OwnedSlice<T> {
type EItem = [T];
type Err = PodCastError;

fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
try_cast_slice(item).map(Cow::Borrowed).map_err(Into::into)
fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
try_cast_slice(item).map(Cow::Borrowed)
}
}

impl<'a, T: AnyBitPattern + NoUninit> BytesDecode<'a> for OwnedSlice<T> {
type DItem = Vec<T>;
type Err = PodCastError;

fn bytes_decode(bytes: &[u8]) -> Result<Self::DItem, BoxedError> {
fn bytes_decode(bytes: &[u8]) -> Result<Self::DItem, Self::Err> {
CowSlice::<T>::bytes_decode(bytes).map(Cow::into_owned)
}
}
Expand Down
11 changes: 7 additions & 4 deletions heed-types/src/owned_type.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::borrow::Cow;
use std::convert::Infallible;

use bytemuck::{bytes_of, AnyBitPattern, NoUninit};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use bytemuck::{bytes_of, AnyBitPattern, NoUninit, PodCastError};
use heed_traits::{BytesDecode, BytesEncode};

use crate::CowType;

Expand All @@ -28,16 +29,18 @@ pub struct OwnedType<T>(std::marker::PhantomData<T>);

impl<'a, T: NoUninit> BytesEncode<'a> for OwnedType<T> {
type EItem = T;
type Err = Infallible;

fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
Ok(Cow::Borrowed(bytes_of(item)))
}
}

impl<'a, T: AnyBitPattern + NoUninit> BytesDecode<'a> for OwnedType<T> {
type DItem = T;
type Err = PodCastError;

fn bytes_decode(bytes: &[u8]) -> Result<Self::DItem, BoxedError> {
fn bytes_decode(bytes: &[u8]) -> Result<Self::DItem, Self::Err> {
CowType::<T>::bytes_decode(bytes).map(Cow::into_owned)
}
}
Expand Down
12 changes: 7 additions & 5 deletions heed-types/src/serde_bincode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use heed_traits::{BytesDecode, BytesEncode};
use serde::{Deserialize, Serialize};

/// Describes a type that is [`Serialize`]/[`Deserialize`] and uses `bincode` to do so.
Expand All @@ -13,9 +13,10 @@ where
T: Serialize,
{
type EItem = T;
type Err = bincode::Error;

fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
bincode::serialize(item).map(Cow::Owned).map_err(Into::into)
fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
bincode::serialize(item).map(Cow::Owned)
}
}

Expand All @@ -24,9 +25,10 @@ where
T: Deserialize<'a>,
{
type DItem = T;
type Err = bincode::Error;

fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
bincode::deserialize(bytes).map_err(Into::into)
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, Self::Err> {
bincode::deserialize(bytes)
}
}

Expand Down
10 changes: 6 additions & 4 deletions heed-types/src/serde_json.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use heed_traits::{BytesDecode, BytesEncode};
use serde::{Deserialize, Serialize};

/// Describes a type that is [`Serialize`]/[`Deserialize`] and uses `serde_json` to do so.
Expand All @@ -13,8 +13,9 @@ where
T: Serialize,
{
type EItem = T;
type Err = serde_json::Error;

fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
serde_json::to_vec(item).map(Cow::Owned).map_err(Into::into)
}
}
Expand All @@ -24,9 +25,10 @@ where
T: Deserialize<'a>,
{
type DItem = T;
type Err = serde_json::Error;

fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
serde_json::from_slice(bytes).map_err(Into::into)
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, Self::Err> {
serde_json::from_slice(bytes)
}
}

Expand Down
12 changes: 8 additions & 4 deletions heed-types/src/str.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
use std::borrow::Cow;
use std::convert::Infallible;
use std::str::Utf8Error;

use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use heed_traits::{BytesDecode, BytesEncode};

/// Describes an [`prim@str`].
pub struct Str;

impl BytesEncode<'_> for Str {
type EItem = str;
type Err = Infallible;

fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
Ok(Cow::Borrowed(item.as_bytes()))
}
}

impl<'a> BytesDecode<'a> for Str {
type DItem = &'a str;
type Err = Utf8Error;

fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
std::str::from_utf8(bytes).map_err(Into::into)
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, Self::Err> {
std::str::from_utf8(bytes)
}
}
14 changes: 8 additions & 6 deletions heed-types/src/unaligned_slice.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::borrow::Cow;

use bytemuck::{try_cast_slice, AnyBitPattern, NoUninit};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use bytemuck::{try_cast_slice, AnyBitPattern, NoUninit, PodCastError};
use heed_traits::{BytesDecode, BytesEncode};

/// Describes a type that is totally borrowed and doesn't
/// depends on any [memory alignment].
Expand All @@ -15,17 +15,19 @@ pub struct UnalignedSlice<T>(std::marker::PhantomData<T>);

impl<'a, T: NoUninit> BytesEncode<'a> for UnalignedSlice<T> {
type EItem = [T];
type Err = PodCastError;

fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
try_cast_slice(item).map(Cow::Borrowed).map_err(Into::into)
fn bytes_encode(item: &'a Self::EItem) -> Result<Cow<[u8]>, Self::Err> {
try_cast_slice(item).map(Cow::Borrowed)
}
}

impl<'a, T: AnyBitPattern> BytesDecode<'a> for UnalignedSlice<T> {
type DItem = &'a [T];
type Err = PodCastError;

fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
try_cast_slice(bytes).map_err(Into::into)
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, Self::Err> {
try_cast_slice(bytes)
}
}

Expand Down
Loading