Skip to content

Commit

Permalink
Compute an error when encoding/decoding in bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
Kerollmops committed Jul 6, 2022
1 parent f3213da commit 1fd8522
Show file tree
Hide file tree
Showing 19 changed files with 190 additions and 183 deletions.
8 changes: 6 additions & 2 deletions heed-traits/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +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>;

pub trait BytesEncode<'a> {
type EItem: ?Sized + 'a;

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

pub trait BytesDecode<'a> {
type DItem: 'a;

fn bytes_decode(bytes: &'a [u8]) -> Option<Self::DItem>;
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError>;
}
2 changes: 1 addition & 1 deletion heed-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ edition = "2018"

[dependencies]
bincode = { version = "1.2.1", optional = true }
bytemuck = { version = "1.5.0", features = ["extern_crate_alloc"] }
bytemuck = { version = "1.5.0", features = ["extern_crate_alloc", "extern_crate_std"] }
byteorder = "1.4.2"
heed-traits = { version = "0.7.0", path = "../heed-traits" }
serde = { version = "1.0.117", optional = true }
Expand Down
14 changes: 7 additions & 7 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::{BytesDecode, BytesEncode};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};

/// Describes a slice that must be [memory aligned] and
/// will be reallocated if it is not.
Expand All @@ -23,19 +23,19 @@ pub struct CowSlice<T>(std::marker::PhantomData<T>);
impl<'a, T: NoUninit> BytesEncode<'a> for CowSlice<T> {
type EItem = [T];

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

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

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

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

/// Describes a type that must be [memory aligned] and
/// will be reallocated if it is not.
Expand Down Expand Up @@ -29,23 +29,23 @@ pub struct CowType<T>(std::marker::PhantomData<T>);
impl<'a, T: NoUninit> BytesEncode<'a> for CowType<T> {
type EItem = T;

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

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

fn bytes_decode(bytes: &'a [u8]) -> Option<Self::DItem> {
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
match try_from_bytes(bytes) {
Ok(item) => Some(Cow::Borrowed(item)),
Ok(item) => Ok(Cow::Borrowed(item)),
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
let mut item = T::zeroed();
bytes_of_mut(&mut item).copy_from_slice(bytes);
Some(Cow::Owned(item))
Ok(Cow::Owned(item))
}
Err(_) => None,
Err(error) => Err(error.into()),
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions heed-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ mod serde_bincode;
#[cfg(feature = "serde-json")]
mod serde_json;

use heed_traits::BoxedError;

pub use self::cow_slice::CowSlice;
pub use self::cow_type::CowType;
pub use self::integer::*;
Expand All @@ -62,8 +64,8 @@ pub struct DecodeIgnore;
impl heed_traits::BytesDecode<'_> for DecodeIgnore {
type DItem = ();

fn bytes_decode(_bytes: &[u8]) -> Option<Self::DItem> {
Some(())
fn bytes_decode(_bytes: &[u8]) -> Result<Self::DItem, BoxedError> {
Ok(())
}
}

Expand Down
8 changes: 4 additions & 4 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::{BytesDecode, BytesEncode};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};

use crate::CowSlice;

Expand All @@ -23,15 +23,15 @@ pub struct OwnedSlice<T>(std::marker::PhantomData<T>);
impl<'a, T: NoUninit> BytesEncode<'a> for OwnedSlice<T> {
type EItem = [T];

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

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

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

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

use crate::CowType;

Expand Down Expand Up @@ -29,15 +29,15 @@ pub struct OwnedType<T>(std::marker::PhantomData<T>);
impl<'a, T: NoUninit> BytesEncode<'a> for OwnedType<T> {
type EItem = T;

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

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

fn bytes_decode(bytes: &[u8]) -> Option<Self::DItem> {
fn bytes_decode(bytes: &[u8]) -> Result<Self::DItem, BoxedError> {
CowType::<T>::bytes_decode(bytes).map(Cow::into_owned)
}
}
Expand Down
10 changes: 5 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::{BytesDecode, BytesEncode};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use serde::{Deserialize, Serialize};

/// Describes a type that is [`Serialize`]/[`Deserialize`] and uses `bincode` to do so.
Expand All @@ -14,8 +14,8 @@ where
{
type EItem = T;

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

Expand All @@ -25,8 +25,8 @@ where
{
type DItem = T;

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

Expand Down
10 changes: 5 additions & 5 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::{BytesDecode, BytesEncode};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};
use serde::{Deserialize, Serialize};

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

fn bytes_encode(item: &Self::EItem) -> Option<Cow<[u8]>> {
serde_json::to_vec(item).map(Cow::Owned).ok()
fn bytes_encode(item: &Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
serde_json::to_vec(item).map(Cow::Owned).map_err(Into::into)
}
}

Expand All @@ -25,8 +25,8 @@ where
{
type DItem = T;

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

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

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

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

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

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

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

fn bytes_decode(bytes: &'a [u8]) -> Option<Self::DItem> {
std::str::from_utf8(bytes).ok()
fn bytes_decode(bytes: &'a [u8]) -> Result<Self::DItem, BoxedError> {
std::str::from_utf8(bytes).map_err(Into::into)
}
}
10 changes: 5 additions & 5 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::{BytesDecode, BytesEncode};
use heed_traits::{BoxedError, BytesDecode, BytesEncode};

/// Describes a type that is totally borrowed and doesn't
/// depends on any [memory alignment].
Expand All @@ -16,16 +16,16 @@ pub struct UnalignedSlice<T>(std::marker::PhantomData<T>);
impl<'a, T: NoUninit> BytesEncode<'a> for UnalignedSlice<T> {
type EItem = [T];

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

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

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

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

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

/// Describes a slice that is totally borrowed and doesn't
/// depends on any [memory alignment].
Expand All @@ -22,16 +22,16 @@ pub struct UnalignedType<T>(std::marker::PhantomData<T>);
impl<'a, T: NoUninit> BytesEncode<'a> for UnalignedType<T> {
type EItem = T;

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

impl<'a, T: AnyBitPattern> BytesDecode<'a> for UnalignedType<T> {
type DItem = &'a T;

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

Expand Down
13 changes: 7 additions & 6 deletions heed-types/src/unit.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
use std::borrow::Cow;

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

/// Describes the `()` type.
pub struct Unit;

impl BytesEncode<'_> for Unit {
type EItem = ();

fn bytes_encode(_item: &Self::EItem) -> Option<Cow<[u8]>> {
Some(Cow::Borrowed(&[]))
fn bytes_encode(_item: &Self::EItem) -> Result<Cow<[u8]>, BoxedError> {
Ok(Cow::Borrowed(&[]))
}
}

impl BytesDecode<'_> for Unit {
type DItem = ();

fn bytes_decode(bytes: &[u8]) -> Option<Self::DItem> {
fn bytes_decode(bytes: &[u8]) -> Result<Self::DItem, BoxedError> {
if bytes.is_empty() {
Some(())
Ok(())
} else {
None
Err(PodCastError::SizeMismatch.into())
}
}
}

0 comments on commit 1fd8522

Please sign in to comment.