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

Feature/improve serde #477

Merged
merged 2 commits into from
Jan 19, 2022
Merged
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
4 changes: 4 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@
"alloc,derive",
"std",
"std,derive",
"serde_no_std",
"serde_alloc",
"serde",
"serde_no_std,derive",
"serde_alloc,derive",
"serde,derive"
]
}
Expand Down
18 changes: 11 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,23 @@ atomic = []
derive = ["bincode_derive"]

# BlockedTODO: https://github.com/rust-lang/cargo/issues/8832
# We really want these features to automatically be enabled when both "serde" and either "alloc"/"std" is enabled
# But this is currently not possible
serde = ["std", "serde_incl", "serde_incl/std"]
# We want to enable these features automatically based on "alloc" or "std"
# std = ["alloc", "serde?/std"]
# alloc = ["serde?/alloc"]
# now we have to do this hack:
serde = ["serde_incl/std", "std", "serde_alloc"] # std
serde_alloc = ["serde_incl/alloc", "alloc"] # alloc
serde_no_std = ["serde_incl"] # no_std

[dependencies]
bincode_derive = { path = "derive", version = "2.0.0-beta.0", optional = true }
serde_incl = { package = "serde", version = "1.0.130", optional = true }
serde_incl = { package = "serde", version = "1.0", default-features = false, optional = true }

# Used for tests
[dev-dependencies]
serde_derive = "1.0.130"
serde_json = "1.0.68"
tempfile = "3.2.0"
serde_derive = "1.0"
serde_json = { version = "1.0", default-features = false }
tempfile = "3.2"
criterion = "0.3"
rand = "0.8"
uuid = { version = "0.8", features = ["serde"] }
Expand Down
20 changes: 4 additions & 16 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ pub enum EncodeError {
time: std::time::SystemTime,
},

/// Serde provided bincode with a sequence without a length, which is not supported in bincode
#[cfg(feature = "serde")]
SequenceMustHaveLength,
/// A serde-specific error that occured while decoding.
Serde(crate::features::serde::EncodeError),
}

impl core::fmt::Display for EncodeError {
Expand Down Expand Up @@ -157,21 +157,9 @@ pub enum DecodeError {
#[cfg(feature = "alloc")]
OtherString(alloc::string::String),

/// Bincode does not support serde's `any` decoding feature
#[cfg(feature = "serde")]
SerdeAnyNotSupported,

/// Bincode does not support serde identifiers
#[cfg(feature = "serde")]
SerdeIdentifierNotSupported,

/// Bincode does not support serde's `ignored_any`
#[cfg(feature = "serde")]
SerdeIgnoredAnyNotSupported,

/// Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead
#[cfg(feature = "serde")]
CannotBorrowOwnedData,
/// A serde-specific error that occured while decoding.
Serde(crate::features::serde::DecodeError),
}

impl core::fmt::Display for DecodeError {
Expand Down
25 changes: 22 additions & 3 deletions src/features/serde/de_borrowed.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::DecodeError as SerdeDecodeError;
use crate::{
config::Config,
de::{BorrowDecode, BorrowDecoder, Decode},
Expand Down Expand Up @@ -33,7 +34,7 @@ impl<'a, 'de, DE: BorrowDecoder<'de>> Deserializer<'de> for SerdeDecoder<'a, 'de
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::SerdeAnyNotSupported)
Err(SerdeDecodeError::AnyNotSupported.into())
}

fn deserialize_bool<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
Expand Down Expand Up @@ -128,6 +129,15 @@ impl<'a, 'de, DE: BorrowDecoder<'de>> Deserializer<'de> for SerdeDecoder<'a, 'de
visitor.visit_borrowed_str(str)
}

#[cfg(not(feature = "alloc"))]
fn deserialize_string<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}

#[cfg(feature = "alloc")]
fn deserialize_string<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
Expand All @@ -143,6 +153,15 @@ impl<'a, 'de, DE: BorrowDecoder<'de>> Deserializer<'de> for SerdeDecoder<'a, 'de
visitor.visit_borrowed_bytes(bytes)
}

#[cfg(not(feature = "alloc"))]
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}

#[cfg(feature = "alloc")]
fn deserialize_byte_buf<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
Expand Down Expand Up @@ -339,14 +358,14 @@ impl<'a, 'de, DE: BorrowDecoder<'de>> Deserializer<'de> for SerdeDecoder<'a, 'de
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::SerdeIdentifierNotSupported)
Err(SerdeDecodeError::IdentifierNotSupported.into())
}

fn deserialize_ignored_any<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::SerdeIgnoredAnyNotSupported)
Err(SerdeDecodeError::IgnoredAnyNotSupported.into())
}
}

Expand Down
30 changes: 24 additions & 6 deletions src/features/serde/de_owned.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::DecodeError as SerdeDecodeError;
use crate::{
config::Config,
de::{Decode, Decoder},
Expand Down Expand Up @@ -34,7 +35,7 @@ impl<'a, 'de, DE: Decoder> Deserializer<'de> for SerdeDecoder<'a, DE> {
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::SerdeAnyNotSupported)
Err(SerdeDecodeError::AnyNotSupported.into())
}

fn deserialize_bool<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
Expand Down Expand Up @@ -130,20 +131,29 @@ impl<'a, 'de, DE: Decoder> Deserializer<'de> for SerdeDecoder<'a, DE> {
}

#[cfg(not(feature = "alloc"))]
fn deserialize_str<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_str<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::CannotBorrowOwnedData)
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}

#[cfg(feature = "alloc")]
fn deserialize_string<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
visitor.visit_string(Decode::decode(&mut self.de)?)
}

#[cfg(not(feature = "alloc"))]
fn deserialize_string<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotAllocate.into())
}

#[cfg(feature = "alloc")]
fn deserialize_bytes<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
Expand All @@ -157,15 +167,23 @@ impl<'a, 'de, DE: Decoder> Deserializer<'de> for SerdeDecoder<'a, DE> {
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::CannotBorrowOwnedData)
Err(SerdeDecodeError::CannotBorrowOwnedData.into())
}

#[cfg(feature = "alloc")]
fn deserialize_byte_buf<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
visitor.visit_byte_buf(Decode::decode(&mut self.de)?)
}
#[cfg(not(feature = "alloc"))]
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
Err(SerdeDecodeError::CannotAllocate.into())
}

fn deserialize_option<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where
Expand Down Expand Up @@ -353,14 +371,14 @@ impl<'a, 'de, DE: Decoder> Deserializer<'de> for SerdeDecoder<'a, DE> {
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::SerdeIdentifierNotSupported)
Err(SerdeDecodeError::IdentifierNotSupported.into())
}

fn deserialize_ignored_any<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: serde_incl::de::Visitor<'de>,
{
Err(DecodeError::SerdeIgnoredAnyNotSupported)
Err(SerdeDecodeError::IgnoredAnyNotSupported.into())
}
}

Expand Down
91 changes: 91 additions & 0 deletions src/features/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@
//! # }
//! ```
//!
//! # `alloc` and `no_std`
//!
//! The `serde` feature enables both `alloc` and `std` at this point in time.
//! To use bincode and serde on no_std targets, try one of the following features:
//!
//! - `serde_alloc`: enables `serde` and `alloc`
//! - `serde_no_std`: enables `serde` without `alloc` or `std`
//!
//! # Known issues
//!
//! Currently the `serde` feature will automatically enable the `alloc` and `std` feature. If you're running in a `#[no_std]` environment consider using bincode's own derive macros.
Expand All @@ -66,6 +74,32 @@ pub use self::de_borrowed::*;
pub use self::de_owned::*;
pub use self::ser::*;

/// A serde-specific error that occured while decoding.
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum DecodeError {
VictorKoenders marked this conversation as resolved.
Show resolved Hide resolved
/// Bincode does not support serde's `any` decoding feature
AnyNotSupported,

/// Bincode does not support serde identifiers
IdentifierNotSupported,

/// Bincode does not support serde's `ignored_any`
IgnoredAnyNotSupported,

/// Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead
CannotBorrowOwnedData,

/// Could not allocate data like `String` and `Vec<u8>`
#[cfg(not(feature = "alloc"))]
CannotAllocate,

/// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
#[cfg(not(feature = "alloc"))]
CustomError,
}

#[cfg(feature = "alloc")]
impl serde_incl::de::Error for crate::error::DecodeError {
fn custom<T>(msg: T) -> Self
where
Expand All @@ -76,6 +110,50 @@ impl serde_incl::de::Error for crate::error::DecodeError {
}
}

#[cfg(not(feature = "std"))]
impl serde_incl::de::StdError for crate::error::DecodeError {}

#[cfg(not(feature = "alloc"))]
impl serde_incl::de::Error for crate::error::DecodeError {
fn custom<T>(_: T) -> Self
where
T: core::fmt::Display,
{
DecodeError::CustomError.into()
}
}

#[allow(clippy::from_over_into)]
impl Into<crate::error::DecodeError> for DecodeError {
fn into(self) -> crate::error::DecodeError {
crate::error::DecodeError::Serde(self)
}
}

/// A serde-specific error that occured while encoding.
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum EncodeError {
VictorKoenders marked this conversation as resolved.
Show resolved Hide resolved
/// Serde provided bincode with a sequence without a length, which is not supported in bincode
SequenceMustHaveLength,

/// [Serializer::collect_str] got called but bincode was unable to allocate memory.
#[cfg(not(feature = "alloc"))]
CannotCollectStr,

/// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
#[cfg(not(feature = "alloc"))]
CustomError,
}

#[allow(clippy::from_over_into)]
impl Into<crate::error::EncodeError> for EncodeError {
fn into(self) -> crate::error::EncodeError {
crate::error::EncodeError::Serde(self)
}
}

#[cfg(feature = "alloc")]
impl serde_incl::ser::Error for crate::error::EncodeError {
fn custom<T>(msg: T) -> Self
where
Expand All @@ -87,6 +165,19 @@ impl serde_incl::ser::Error for crate::error::EncodeError {
}
}

#[cfg(not(feature = "std"))]
impl serde_incl::de::StdError for crate::error::EncodeError {}
VictorKoenders marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(not(feature = "alloc"))]
impl serde_incl::ser::Error for crate::error::EncodeError {
fn custom<T>(_: T) -> Self
where
T: core::fmt::Display,
{
EncodeError::CustomError.into()
}
}

/// Wrapper struct that implements [Decode] and [Encode] on any type that implements serde's [DeserializeOwned] and [Serialize] respectively.
///
/// This works for most types, but if you're dealing with borrowed data consider using [BorrowCompat] instead.
Expand Down
13 changes: 11 additions & 2 deletions src/features/serde/ser.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::EncodeError as SerdeEncodeError;
use crate::{
config::Config,
enc::{Encode, Encoder},
Expand Down Expand Up @@ -165,7 +166,7 @@ where
}

fn serialize_seq(mut self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
let len = len.ok_or(EncodeError::SequenceMustHaveLength)?;
let len = len.ok_or_else(|| SerdeEncodeError::SequenceMustHaveLength.into())?;
len.encode(&mut self.enc)?;
Ok(Compound { enc: self.enc })
}
Expand Down Expand Up @@ -196,7 +197,7 @@ where
}

fn serialize_map(mut self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
let len = len.ok_or(EncodeError::SequenceMustHaveLength)?;
let len = len.ok_or_else(|| SerdeEncodeError::SequenceMustHaveLength.into())?;
len.encode(&mut self.enc)?;
Ok(Compound { enc: self.enc })
}
Expand All @@ -219,6 +220,14 @@ where
variant_index.encode(&mut self.enc)?;
Ok(Compound { enc: self.enc })
}

#[cfg(not(feature = "alloc"))]
fn collect_str<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
where
T: core::fmt::Display,
{
Err(SerdeEncodeError::CannotCollectStr.into())
}
}

type Compound<'a, ENC> = SerdeEncoder<'a, ENC>;
Expand Down