mirror of https://git.sr.ht/~stygianentity/bincode
Allow serde types to be Decode/Encoded (#434)
* Added support for #[bincode(serde)] attribute on fields, added SerdeToBincode helper struct * Switch to using Compat/BorrowCompat * Moved all the serde features and functions to its own module * Fix broken link * Added support for the bincode(with_serde) attribute in enum variants * Updated the main documentation on serde, fixed an example not compiling under certain feature flag combinations * Added #[serde(flatten)] to the list of problematic attributes * Added better error reporting on invalid attributes
This commit is contained in:
parent
8c1279feab
commit
ad7ddebff3
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::generate::{FnSelfArg, Generator, StreamBuilder};
|
use crate::generate::{FnSelfArg, Generator, StreamBuilder};
|
||||||
use crate::parse::{EnumVariant, Fields};
|
use crate::parse::{EnumVariant, FieldAttribute, Fields};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
|
|
@ -80,12 +80,20 @@ impl DeriveEnum {
|
||||||
body.punct(';');
|
body.punct(';');
|
||||||
// If we have any fields, encode them all one by one
|
// If we have any fields, encode them all one by one
|
||||||
for field_name in variant.fields.names() {
|
for field_name in variant.fields.names() {
|
||||||
|
if field_name.has_field_attribute(FieldAttribute::WithSerde) {
|
||||||
|
body.push_parsed(format!(
|
||||||
|
"bincode::enc::Encode::encode(&bincode::serde::Compat({}), &mut encoder)?;",
|
||||||
|
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
body.push_parsed(format!(
|
body.push_parsed(format!(
|
||||||
"bincode::enc::Encode::encode({}, &mut encoder)?;",
|
"bincode::enc::Encode::encode({}, &mut encoder)?;",
|
||||||
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
|
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
match_body.punct(',');
|
match_body.punct(',');
|
||||||
}
|
}
|
||||||
|
|
@ -209,10 +217,16 @@ impl DeriveEnum {
|
||||||
variant_body.ident(field.unwrap_ident().clone());
|
variant_body.ident(field.unwrap_ident().clone());
|
||||||
}
|
}
|
||||||
variant_body.punct(':');
|
variant_body.punct(':');
|
||||||
|
if field.has_field_attribute(FieldAttribute::WithSerde) {
|
||||||
|
variant_body
|
||||||
|
.push_parsed("<bincode::serde::Compat<_> as bincode::Decode>::decode(&mut decoder)?.0,")
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
variant_body
|
variant_body
|
||||||
.push_parsed("bincode::Decode::decode(&mut decoder)?,")
|
.push_parsed("bincode::Decode::decode(&mut decoder)?,")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
variant_case.punct(',');
|
variant_case.punct(',');
|
||||||
|
|
@ -269,8 +283,14 @@ impl DeriveEnum {
|
||||||
variant_body.ident(field.unwrap_ident().clone());
|
variant_body.ident(field.unwrap_ident().clone());
|
||||||
}
|
}
|
||||||
variant_body.punct(':');
|
variant_body.punct(':');
|
||||||
|
if field.has_field_attribute(FieldAttribute::WithSerde) {
|
||||||
|
variant_body
|
||||||
|
.push_parsed("<bincode::serde::BorrowCompat<_> as bincode::BorrowDecode>::borrow_decode(&mut decoder)?.0,")
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
variant_body.push_parsed("bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,").unwrap();
|
variant_body.push_parsed("bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,").unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
variant_case.punct(',');
|
variant_case.punct(',');
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::generate::Generator;
|
use crate::generate::Generator;
|
||||||
use crate::parse::Fields;
|
use crate::parse::{FieldAttribute, Fields};
|
||||||
use crate::prelude::Delimiter;
|
use crate::prelude::Delimiter;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
|
|
@ -21,6 +21,14 @@ impl DeriveStruct {
|
||||||
.with_return_type("core::result::Result<(), bincode::error::EncodeError>")
|
.with_return_type("core::result::Result<(), bincode::error::EncodeError>")
|
||||||
.body(|fn_body| {
|
.body(|fn_body| {
|
||||||
for field in fields.names() {
|
for field in fields.names() {
|
||||||
|
if field.has_field_attribute(FieldAttribute::WithSerde) {
|
||||||
|
fn_body
|
||||||
|
.push_parsed(format!(
|
||||||
|
"bincode::Encode::encode(&bincode::serde::Compat(&self.{}), &mut encoder)?;",
|
||||||
|
field.to_string()
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
fn_body
|
fn_body
|
||||||
.push_parsed(format!(
|
.push_parsed(format!(
|
||||||
"bincode::enc::Encode::encode(&self.{}, &mut encoder)?;",
|
"bincode::enc::Encode::encode(&self.{}, &mut encoder)?;",
|
||||||
|
|
@ -28,6 +36,7 @@ impl DeriveStruct {
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn_body.push_parsed("Ok(())").unwrap();
|
fn_body.push_parsed("Ok(())").unwrap();
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -59,6 +68,14 @@ impl DeriveStruct {
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
for field in fields.names() {
|
for field in fields.names() {
|
||||||
|
if field.has_field_attribute(FieldAttribute::WithSerde) {
|
||||||
|
struct_body
|
||||||
|
.push_parsed(format!(
|
||||||
|
"{}: (<bincode::serde::Compat<_> as bincode::Decode>::decode(&mut decoder)?).0,",
|
||||||
|
field.to_string()
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
struct_body
|
struct_body
|
||||||
.push_parsed(format!(
|
.push_parsed(format!(
|
||||||
"{}: bincode::Decode::decode(&mut decoder)?,",
|
"{}: bincode::Decode::decode(&mut decoder)?,",
|
||||||
|
|
@ -66,6 +83,7 @@ impl DeriveStruct {
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -92,6 +110,14 @@ impl DeriveStruct {
|
||||||
ok_group.ident_str("Self");
|
ok_group.ident_str("Self");
|
||||||
ok_group.group(Delimiter::Brace, |struct_body| {
|
ok_group.group(Delimiter::Brace, |struct_body| {
|
||||||
for field in fields.names() {
|
for field in fields.names() {
|
||||||
|
if field.has_field_attribute(FieldAttribute::WithSerde) {
|
||||||
|
struct_body
|
||||||
|
.push_parsed(format!(
|
||||||
|
"{}: (<bincode::serde::BorrowCompat<_> as bincode::de::BorrowDecode>::borrow_decode(&mut decoder)?).0,",
|
||||||
|
field.to_string()
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
struct_body
|
struct_body
|
||||||
.push_parsed(format!(
|
.push_parsed(format!(
|
||||||
"{}: bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,",
|
"{}: bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,",
|
||||||
|
|
@ -99,6 +125,7 @@ impl DeriveStruct {
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
pub fn wrong_token<T>(token: Option<&TokenTree>, expected: &'static str) -> Result<T, Self> {
|
pub fn wrong_token<T>(token: Option<&TokenTree>, expected: &str) -> Result<T, Self> {
|
||||||
Err(Self::InvalidRustSyntax {
|
Err(Self::InvalidRustSyntax {
|
||||||
span: token.map(|t| t.span()).unwrap_or_else(Span::call_site),
|
span: token.map(|t| t.span()).unwrap_or_else(Span::call_site),
|
||||||
expected: format!("{}, got {:?}", expected, token),
|
expected: format!("{}, got {:?}", expected, token),
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,12 @@ pub(crate) mod prelude {
|
||||||
}
|
}
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
use parse::AttributeLocation;
|
||||||
use prelude::TokenStream;
|
use prelude::TokenStream;
|
||||||
|
|
||||||
type Result<T = ()> = std::result::Result<T, Error>;
|
type Result<T = ()> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[proc_macro_derive(Encode)]
|
#[proc_macro_derive(Encode, attributes(bincode))]
|
||||||
pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
#[allow(clippy::useless_conversion)]
|
#[allow(clippy::useless_conversion)]
|
||||||
derive_encode_inner(input.into())
|
derive_encode_inner(input.into())
|
||||||
|
|
@ -31,7 +32,7 @@ pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream
|
||||||
fn derive_encode_inner(input: TokenStream) -> Result<TokenStream> {
|
fn derive_encode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
let source = &mut input.into_iter().peekable();
|
let source = &mut input.into_iter().peekable();
|
||||||
|
|
||||||
let _attributes = parse::Attribute::try_take(source)?;
|
let _attributes = parse::Attribute::try_take(AttributeLocation::Container, source)?;
|
||||||
let _visibility = parse::Visibility::try_take(source)?;
|
let _visibility = parse::Visibility::try_take(source)?;
|
||||||
let (datatype, name) = parse::DataType::take(source)?;
|
let (datatype, name) = parse::DataType::take(source)?;
|
||||||
let generics = parse::Generics::try_take(source)?;
|
let generics = parse::Generics::try_take(source)?;
|
||||||
|
|
@ -61,7 +62,7 @@ fn derive_encode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Decode)]
|
#[proc_macro_derive(Decode, attributes(bincode))]
|
||||||
pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
#[allow(clippy::useless_conversion)]
|
#[allow(clippy::useless_conversion)]
|
||||||
derive_decode_inner(input.into())
|
derive_decode_inner(input.into())
|
||||||
|
|
@ -72,7 +73,7 @@ pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream
|
||||||
fn derive_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
fn derive_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
let source = &mut input.into_iter().peekable();
|
let source = &mut input.into_iter().peekable();
|
||||||
|
|
||||||
let _attributes = parse::Attribute::try_take(source)?;
|
let _attributes = parse::Attribute::try_take(AttributeLocation::Container, source)?;
|
||||||
let _visibility = parse::Visibility::try_take(source)?;
|
let _visibility = parse::Visibility::try_take(source)?;
|
||||||
let (datatype, name) = parse::DataType::take(source)?;
|
let (datatype, name) = parse::DataType::take(source)?;
|
||||||
let generics = parse::Generics::try_take(source)?;
|
let generics = parse::Generics::try_take(source)?;
|
||||||
|
|
@ -102,7 +103,7 @@ fn derive_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(BorrowDecode)]
|
#[proc_macro_derive(BorrowDecode, attributes(bincode))]
|
||||||
pub fn derive_brrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_brrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
#[allow(clippy::useless_conversion)]
|
#[allow(clippy::useless_conversion)]
|
||||||
derive_borrow_decode_inner(input.into())
|
derive_borrow_decode_inner(input.into())
|
||||||
|
|
@ -113,7 +114,7 @@ pub fn derive_brrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenS
|
||||||
fn derive_borrow_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
fn derive_borrow_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
let source = &mut input.into_iter().peekable();
|
let source = &mut input.into_iter().peekable();
|
||||||
|
|
||||||
let _attributes = parse::Attribute::try_take(source)?;
|
let _attributes = parse::Attribute::try_take(AttributeLocation::Container, source)?;
|
||||||
let _visibility = parse::Visibility::try_take(source)?;
|
let _visibility = parse::Visibility::try_take(source)?;
|
||||||
let (datatype, name) = parse::DataType::take(source)?;
|
let (datatype, name) = parse::DataType::take(source)?;
|
||||||
let generics = parse::Generics::try_take(source)?;
|
let generics = parse::Generics::try_take(source)?;
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,62 @@
|
||||||
use super::{assume_group, assume_punct};
|
use super::{assume_group, assume_ident, assume_punct};
|
||||||
use crate::parse::consume_punct_if;
|
use crate::parse::{consume_punct_if, ident_eq};
|
||||||
use crate::prelude::{Delimiter, Group, Punct, TokenTree};
|
use crate::prelude::{Delimiter, Group, Punct, TokenTree};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Attribute {
|
pub enum Attribute {
|
||||||
// we don't use these fields yet
|
Field(FieldAttribute),
|
||||||
#[allow(dead_code)]
|
Unknown { punct: Punct, tokens: Option<Group> },
|
||||||
punct: Punct,
|
}
|
||||||
#[allow(dead_code)]
|
#[derive(Debug, PartialEq)]
|
||||||
tokens: Option<Group>,
|
pub enum FieldAttribute {
|
||||||
|
/// The field is a serde type and should implement Encode/Decode through a wrapper
|
||||||
|
WithSerde,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Hash, Copy, Clone)]
|
||||||
|
pub enum AttributeLocation {
|
||||||
|
Container,
|
||||||
|
Variant,
|
||||||
|
Field,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attribute {
|
impl Attribute {
|
||||||
pub fn try_take(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Result<Vec<Self>> {
|
pub fn try_take(
|
||||||
|
loc: AttributeLocation,
|
||||||
|
input: &mut Peekable<impl Iterator<Item = TokenTree>>,
|
||||||
|
) -> Result<Vec<Self>> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
||||||
while let Some(punct) = consume_punct_if(input, '#') {
|
while let Some(punct) = consume_punct_if(input, '#') {
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => {
|
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => {
|
||||||
result.push(Attribute {
|
let group = assume_group(input.next());
|
||||||
|
let stream = &mut group.stream().into_iter().peekable();
|
||||||
|
if let Some(TokenTree::Ident(attribute_ident)) = stream.peek() {
|
||||||
|
if super::ident_eq(attribute_ident, "bincode") {
|
||||||
|
assume_ident(stream.next());
|
||||||
|
match stream.next() {
|
||||||
|
Some(TokenTree::Group(group)) => {
|
||||||
|
result.push(Self::parse_bincode_attribute(
|
||||||
|
loc,
|
||||||
|
&mut group.stream().into_iter().peekable(),
|
||||||
|
)?);
|
||||||
|
}
|
||||||
|
token => {
|
||||||
|
return Error::wrong_token(
|
||||||
|
token.as_ref(),
|
||||||
|
"Bracketed group of attributes",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(Attribute::Unknown {
|
||||||
punct,
|
punct,
|
||||||
tokens: Some(assume_group(input.next())),
|
tokens: Some(group),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(TokenTree::Group(g)) => {
|
Some(TokenTree::Group(g)) => {
|
||||||
|
|
@ -34,7 +68,7 @@ impl Attribute {
|
||||||
Some(TokenTree::Punct(p)) if p.as_char() == '#' => {
|
Some(TokenTree::Punct(p)) if p.as_char() == '#' => {
|
||||||
// sometimes with empty lines of doc comments, we get two #'s in a row
|
// sometimes with empty lines of doc comments, we get two #'s in a row
|
||||||
// add an empty attributes and continue to the next loop
|
// add an empty attributes and continue to the next loop
|
||||||
result.push(Attribute {
|
result.push(Attribute::Unknown {
|
||||||
punct: assume_punct(input.next(), '#'),
|
punct: assume_punct(input.next(), '#'),
|
||||||
tokens: None,
|
tokens: None,
|
||||||
})
|
})
|
||||||
|
|
@ -44,6 +78,27 @@ impl Attribute {
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_bincode_attribute(
|
||||||
|
loc: AttributeLocation,
|
||||||
|
stream: &mut Peekable<impl Iterator<Item = TokenTree>>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
match (stream.next(), loc) {
|
||||||
|
(Some(TokenTree::Ident(ident)), AttributeLocation::Field)
|
||||||
|
if ident_eq(&ident, "with_serde") =>
|
||||||
|
{
|
||||||
|
Ok(Self::Field(FieldAttribute::WithSerde))
|
||||||
|
}
|
||||||
|
(token @ Some(TokenTree::Ident(_)), AttributeLocation::Field) => {
|
||||||
|
Error::wrong_token(token.as_ref(), "one of: `with_serde`")
|
||||||
|
}
|
||||||
|
(token @ Some(TokenTree::Ident(_)), loc) => Error::wrong_token(
|
||||||
|
token.as_ref(),
|
||||||
|
&format!("{:?} attributes not supported", loc),
|
||||||
|
),
|
||||||
|
(token, _) => Error::wrong_token(token.as_ref(), "ident"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -51,14 +106,18 @@ fn test_attributes_try_take() {
|
||||||
use crate::token_stream;
|
use crate::token_stream;
|
||||||
|
|
||||||
let stream = &mut token_stream("struct Foo;");
|
let stream = &mut token_stream("struct Foo;");
|
||||||
assert!(Attribute::try_take(stream).unwrap().is_empty());
|
assert!(Attribute::try_take(AttributeLocation::Container, stream)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
match stream.next().unwrap() {
|
match stream.next().unwrap() {
|
||||||
TokenTree::Ident(i) => assert_eq!(i, "struct"),
|
TokenTree::Ident(i) => assert_eq!(i, "struct"),
|
||||||
x => panic!("Expected ident, found {:?}", x),
|
x => panic!("Expected ident, found {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream = &mut token_stream("#[cfg(test)] struct Foo;");
|
let stream = &mut token_stream("#[cfg(test)] struct Foo;");
|
||||||
assert!(!Attribute::try_take(stream).unwrap().is_empty());
|
assert!(!Attribute::try_take(AttributeLocation::Container, stream)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
match stream.next().unwrap() {
|
match stream.next().unwrap() {
|
||||||
TokenTree::Ident(i) => assert_eq!(i, "struct"),
|
TokenTree::Ident(i) => assert_eq!(i, "struct"),
|
||||||
x => panic!("Expected ident, found {:?}", x),
|
x => panic!("Expected ident, found {:?}", x),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
use super::attributes::AttributeLocation;
|
||||||
use super::{
|
use super::{
|
||||||
assume_group, assume_ident, assume_punct, read_tokens_until_punct, Attribute, Visibility,
|
assume_group, assume_ident, assume_punct, read_tokens_until_punct, Attribute, FieldAttribute,
|
||||||
|
Visibility,
|
||||||
};
|
};
|
||||||
use crate::parse::consume_punct_if;
|
use crate::parse::consume_punct_if;
|
||||||
use crate::prelude::{Delimiter, Ident, Literal, Span, TokenTree};
|
use crate::prelude::{Delimiter, Ident, Literal, Span, TokenTree};
|
||||||
|
|
@ -132,7 +134,7 @@ impl EnumBody {
|
||||||
let mut variants = Vec::new();
|
let mut variants = Vec::new();
|
||||||
let stream = &mut group.stream().into_iter().peekable();
|
let stream = &mut group.stream().into_iter().peekable();
|
||||||
while stream.peek().is_some() {
|
while stream.peek().is_some() {
|
||||||
let attributes = Attribute::try_take(stream)?;
|
let attributes = Attribute::try_take(AttributeLocation::Variant, stream)?;
|
||||||
let ident = match stream.peek() {
|
let ident = match stream.peek() {
|
||||||
Some(TokenTree::Ident(_)) => assume_ident(stream.next()),
|
Some(TokenTree::Ident(_)) => assume_ident(stream.next()),
|
||||||
token => return Error::wrong_token(token, "ident"),
|
token => return Error::wrong_token(token, "ident"),
|
||||||
|
|
@ -288,11 +290,18 @@ impl Fields {
|
||||||
Self::Tuple(fields) => fields
|
Self::Tuple(fields) => fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, field)| IdentOrIndex::Index(idx, field.span()))
|
.map(|(index, field)| IdentOrIndex::Index {
|
||||||
|
index,
|
||||||
|
span: field.span(),
|
||||||
|
attributes: &field.attributes,
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
Self::Struct(fields) => fields
|
Self::Struct(fields) => fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ident, _)| IdentOrIndex::Ident(ident))
|
.map(|(ident, field)| IdentOrIndex::Ident {
|
||||||
|
ident,
|
||||||
|
attributes: &field.attributes,
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
Self::Unit | Self::Integer(_) => Vec::new(),
|
Self::Unit | Self::Integer(_) => Vec::new(),
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +354,7 @@ impl UnnamedField {
|
||||||
) -> Result<Vec<(Ident, Self)>> {
|
) -> Result<Vec<(Ident, Self)>> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let attributes = Attribute::try_take(input)?;
|
let attributes = Attribute::try_take(AttributeLocation::Field, input)?;
|
||||||
let vis = Visibility::try_take(input)?;
|
let vis = Visibility::try_take(input)?;
|
||||||
|
|
||||||
let ident = match input.peek() {
|
let ident = match input.peek() {
|
||||||
|
|
@ -381,7 +390,7 @@ impl UnnamedField {
|
||||||
pub fn parse(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Result<Vec<Self>> {
|
pub fn parse(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Result<Vec<Self>> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
while input.peek().is_some() {
|
while input.peek().is_some() {
|
||||||
let attributes = Attribute::try_take(input)?;
|
let attributes = Attribute::try_take(AttributeLocation::Field, input)?;
|
||||||
let vis = Visibility::try_take(input)?;
|
let vis = Visibility::try_take(input)?;
|
||||||
|
|
||||||
let r#type = read_tokens_until_punct(input, &[','])?;
|
let r#type = read_tokens_until_punct(input, &[','])?;
|
||||||
|
|
@ -422,42 +431,63 @@ impl UnnamedField {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum IdentOrIndex<'a> {
|
pub enum IdentOrIndex<'a> {
|
||||||
Ident(&'a Ident),
|
Ident {
|
||||||
Index(usize, Span),
|
ident: &'a Ident,
|
||||||
|
attributes: &'a Vec<Attribute>,
|
||||||
|
},
|
||||||
|
Index {
|
||||||
|
index: usize,
|
||||||
|
span: Span,
|
||||||
|
attributes: &'a Vec<Attribute>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IdentOrIndex<'a> {
|
impl<'a> IdentOrIndex<'a> {
|
||||||
pub fn unwrap_ident(&self) -> &'a Ident {
|
pub fn unwrap_ident(&self) -> &'a Ident {
|
||||||
match self {
|
match self {
|
||||||
Self::Ident(i) => i,
|
Self::Ident { ident, .. } => ident,
|
||||||
x => panic!("Expected ident, found {:?}", x),
|
x => panic!("Expected ident, found {:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_token_tree_with_prefix(&self, prefix: &str) -> TokenTree {
|
pub fn to_token_tree_with_prefix(&self, prefix: &str) -> TokenTree {
|
||||||
TokenTree::Ident(match self {
|
TokenTree::Ident(match self {
|
||||||
IdentOrIndex::Ident(i) => (*i).clone(),
|
IdentOrIndex::Ident { ident, .. } => (*ident).clone(),
|
||||||
IdentOrIndex::Index(idx, span) => {
|
IdentOrIndex::Index { index, span, .. } => {
|
||||||
let name = format!("{}{}", prefix, idx);
|
let name = format!("{}{}", prefix, index);
|
||||||
Ident::new(&name, *span)
|
Ident::new(&name, *span)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn to_string_with_prefix(&self, prefix: &str) -> String {
|
pub fn to_string_with_prefix(&self, prefix: &str) -> String {
|
||||||
match self {
|
match self {
|
||||||
IdentOrIndex::Ident(i) => i.to_string(),
|
IdentOrIndex::Ident { ident, .. } => ident.to_string(),
|
||||||
IdentOrIndex::Index(idx, _) => {
|
IdentOrIndex::Index { index, .. } => {
|
||||||
format!("{}{}", prefix, idx)
|
format!("{}{}", prefix, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_field_attribute(&self, attribute: FieldAttribute) -> bool {
|
||||||
|
let attributes = match self {
|
||||||
|
IdentOrIndex::Ident { attributes, .. } => attributes,
|
||||||
|
IdentOrIndex::Index { attributes, .. } => attributes,
|
||||||
|
};
|
||||||
|
attributes.iter().any(|a| {
|
||||||
|
if let Attribute::Field(field_attribute) = a {
|
||||||
|
field_attribute == &attribute
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for IdentOrIndex<'_> {
|
impl std::fmt::Display for IdentOrIndex<'_> {
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
IdentOrIndex::Ident(i) => write!(fmt, "{}", i),
|
IdentOrIndex::Ident { ident, .. } => write!(fmt, "{}", ident),
|
||||||
IdentOrIndex::Index(idx, _) => write!(fmt, "{}", idx),
|
IdentOrIndex::Index { index, .. } => write!(fmt, "{}", index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ mod data_type;
|
||||||
mod generics;
|
mod generics;
|
||||||
mod visibility;
|
mod visibility;
|
||||||
|
|
||||||
pub use self::attributes::Attribute;
|
pub use self::attributes::{Attribute, AttributeLocation, FieldAttribute};
|
||||||
pub use self::body::{EnumBody, EnumVariant, Fields, StructBody, UnnamedField};
|
pub use self::body::{EnumBody, EnumVariant, Fields, StructBody, UnnamedField};
|
||||||
pub use self::data_type::DataType;
|
pub use self::data_type::DataType;
|
||||||
pub use self::generics::{GenericConstraints, Generics, Lifetime, SimpleGeneric};
|
pub use self::generics::{GenericConstraints, Generics, Lifetime, SimpleGeneric};
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ By default `bincode` will serialize values in little endian encoding. This can b
|
||||||
|
|
||||||
Boolean types are encoded with 1 byte for each boolean type, with `0` being `false`, `1` being true. Whilst deserializing every other value will throw an error.
|
Boolean types are encoded with 1 byte for each boolean type, with `0` being `false`, `1` being true. Whilst deserializing every other value will throw an error.
|
||||||
|
|
||||||
All basic numeric types will be encoded based on the configured [IntEncoding](#IntEncoding).
|
All basic numeric types will be encoded based on the configured [IntEncoding](#intencoding).
|
||||||
|
|
||||||
All floating point types will take up exactly 4 (for `f32`) or 8 (for `f64`) bytes.
|
All floating point types will take up exactly 4 (for `f32`) or 8 (for `f64`) bytes.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,5 @@ mod derive;
|
||||||
pub use self::derive::*;
|
pub use self::derive::*;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
mod serde;
|
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
||||||
#[cfg(feature = "serde")]
|
pub mod serde;
|
||||||
pub use self::serde::*;
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,7 @@ use core::marker::PhantomData;
|
||||||
use serde_incl::de::*;
|
use serde_incl::de::*;
|
||||||
|
|
||||||
/// Decode a borrowed type from the given slice. Some parts of the decoded type are expected to be referring to the given slice
|
/// Decode a borrowed type from the given slice. Some parts of the decoded type are expected to be referring to the given slice
|
||||||
pub fn serde_decode_borrowed_from_slice<'de, T, C>(
|
pub fn decode_borrowed_from_slice<'de, T, C>(slice: &'de [u8], config: C) -> Result<T, DecodeError>
|
||||||
slice: &'de [u8],
|
|
||||||
config: C,
|
|
||||||
) -> Result<T, DecodeError>
|
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>,
|
T: Deserialize<'de>,
|
||||||
C: Config,
|
C: Config,
|
||||||
|
|
@ -24,9 +21,9 @@ where
|
||||||
T::deserialize(serde_decoder)
|
T::deserialize(serde_decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerdeDecoder<'a, 'de, DE: BorrowDecoder<'de>> {
|
pub(super) struct SerdeDecoder<'a, 'de, DE: BorrowDecoder<'de>> {
|
||||||
de: &'a mut DE,
|
pub(super) de: &'a mut DE,
|
||||||
pd: PhantomData<&'de ()>,
|
pub(super) pd: PhantomData<&'de ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'de, DE: BorrowDecoder<'de>> Deserializer<'de> for SerdeDecoder<'a, 'de, DE> {
|
impl<'a, 'de, DE: BorrowDecoder<'de>> Deserializer<'de> for SerdeDecoder<'a, 'de, DE> {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ use serde_incl::de::*;
|
||||||
|
|
||||||
/// Decode an owned type from the given slice.
|
/// Decode an owned type from the given slice.
|
||||||
///
|
///
|
||||||
/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [serde_decode_borrowed_from_slice].
|
/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [decode_borrowed_from_slice].
|
||||||
pub fn serde_decode_from_slice<T, C>(slice: &[u8], config: C) -> Result<T, DecodeError>
|
///
|
||||||
|
/// [decode_borrowed_from_slice]: fn.decode_borrowed_from_slice.html
|
||||||
|
pub fn decode_from_slice<T, C>(slice: &[u8], config: C) -> Result<T, DecodeError>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
C: Config,
|
C: Config,
|
||||||
|
|
@ -19,8 +21,8 @@ where
|
||||||
T::deserialize(serde_decoder)
|
T::deserialize(serde_decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerdeDecoder<'a, DE: Decoder> {
|
pub(crate) struct SerdeDecoder<'a, DE: Decoder> {
|
||||||
de: &'a mut DE,
|
pub(crate) de: &'a mut DE,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'de, DE: Decoder> Deserializer<'de> for SerdeDecoder<'a, DE> {
|
impl<'a, 'de, DE: Decoder> Deserializer<'de> for SerdeDecoder<'a, DE> {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,63 @@
|
||||||
|
//! Support for serde integration. Enable this with the `serde` feature.
|
||||||
|
//!
|
||||||
|
//! To encode/decode type that implement serde's trait, you can use:
|
||||||
|
//! - [decode_borrowed_from_slice]
|
||||||
|
//! - [decode_from_slice]
|
||||||
|
//! - [encode_to_slice]
|
||||||
|
//! - [encode_to_vec]
|
||||||
|
//!
|
||||||
|
//! For interop with bincode's [Decode]/[Encode], you can use:
|
||||||
|
//! - [Compat]
|
||||||
|
//! - [BorrowCompat]
|
||||||
|
//!
|
||||||
|
//! For interop with bincode's `derive` feature, you can use the `#[bincode(with_serde)]` attribute on each field that implements serde's traits.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # #[cfg(feature = "derive")]
|
||||||
|
//! # mod foo {
|
||||||
|
//! # use bincode::{Decode, Encode};
|
||||||
|
//! # use serde_derive::{Deserialize, Serialize};
|
||||||
|
//! #[derive(Serialize, Deserialize)]
|
||||||
|
//! # #[serde(crate = "serde_incl")]
|
||||||
|
//! pub struct SerdeType {
|
||||||
|
//! // ...
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Decode, Encode)]
|
||||||
|
//! pub struct StructWithSerde {
|
||||||
|
//! #[bincode(with_serde)]
|
||||||
|
//! pub serde: SerdeType,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Decode, Encode)]
|
||||||
|
//! pub enum EnumWithSerde {
|
||||||
|
//! Unit(#[bincode(with_serde)] SerdeType),
|
||||||
|
//! Struct {
|
||||||
|
//! #[bincode(with_serde)]
|
||||||
|
//! serde: SerdeType,
|
||||||
|
//! },
|
||||||
|
//! }
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # 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.
|
||||||
|
//!
|
||||||
|
//! Because bincode is a format without meta data, there are several known issues with serde's `skip` attributes. Please do not use `skip` attributes if you plan on using bincode, or use bincode's own `derive` macros.
|
||||||
|
//!
|
||||||
|
//! This includes:
|
||||||
|
//! - `#[serde(skip)]`
|
||||||
|
//! - `#[serde(skip_serializing)]`
|
||||||
|
//! - `#[serde(skip_deserializing)]`
|
||||||
|
//! - `#[serde(skip_serializing_if = "path")]`
|
||||||
|
//! - `#[serde(flatten)]`
|
||||||
|
//!
|
||||||
|
//! **Using any of the above attributes can and will cause issues with bincode and will result in lost data**. Consider using bincode's own derive macro instead.
|
||||||
|
//!
|
||||||
|
//! [Decode]: ../de/trait.Decode.html
|
||||||
|
//! [Encode]: ../enc/trait.Encode.html
|
||||||
|
|
||||||
mod de_borrowed;
|
mod de_borrowed;
|
||||||
mod de_owned;
|
mod de_owned;
|
||||||
mod ser;
|
mod ser;
|
||||||
|
|
@ -26,3 +86,74 @@ impl serde_incl::ser::Error for crate::error::EncodeError {
|
||||||
Self::OtherString(msg.to_string())
|
Self::OtherString(msg.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// [Decode]: ../de/trait.Decode.html
|
||||||
|
/// [Encode]: ../enc/trait.Encode.html
|
||||||
|
/// [DeserializeOwned]: https://docs.rs/serde/1/serde/de/trait.DeserializeOwned.html
|
||||||
|
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
|
||||||
|
pub struct Compat<T>(pub T);
|
||||||
|
|
||||||
|
impl<T> crate::Decode for Compat<T>
|
||||||
|
where
|
||||||
|
T: serde_incl::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
fn decode<D: crate::de::Decoder>(mut decoder: D) -> Result<Self, crate::error::DecodeError> {
|
||||||
|
let serde_decoder = de_owned::SerdeDecoder { de: &mut decoder };
|
||||||
|
T::deserialize(serde_decoder).map(Compat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> crate::Encode for Compat<T>
|
||||||
|
where
|
||||||
|
T: serde_incl::Serialize,
|
||||||
|
{
|
||||||
|
fn encode<E: crate::enc::Encoder>(
|
||||||
|
&self,
|
||||||
|
mut encoder: E,
|
||||||
|
) -> Result<(), crate::error::EncodeError> {
|
||||||
|
let serializer = ser::SerdeEncoder { enc: &mut encoder };
|
||||||
|
self.0.serialize(serializer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper struct that implements [BorrowDecode] and [Encode] on any type that implements serde's [Deserialize] and [Serialize] respectively. This is mostly used on `&[u8]` and `&str`, for other types consider using [Compat] instead.
|
||||||
|
///
|
||||||
|
/// [BorrowDecode]: ../de/trait.BorrowDecode.html
|
||||||
|
/// [Encode]: ../enc/trait.Encode.html
|
||||||
|
/// [Deserialize]: https://docs.rs/serde/1/serde/de/trait.Deserialize.html
|
||||||
|
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
|
||||||
|
pub struct BorrowCompat<T>(pub T);
|
||||||
|
|
||||||
|
impl<'de, T> crate::de::BorrowDecode<'de> for BorrowCompat<T>
|
||||||
|
where
|
||||||
|
T: serde_incl::de::Deserialize<'de>,
|
||||||
|
{
|
||||||
|
fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
|
||||||
|
mut decoder: D,
|
||||||
|
) -> Result<Self, crate::error::DecodeError> {
|
||||||
|
let serde_decoder = de_borrowed::SerdeDecoder {
|
||||||
|
de: &mut decoder,
|
||||||
|
pd: core::marker::PhantomData,
|
||||||
|
};
|
||||||
|
T::deserialize(serde_decoder).map(BorrowCompat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> crate::Encode for BorrowCompat<T>
|
||||||
|
where
|
||||||
|
T: serde_incl::Serialize,
|
||||||
|
{
|
||||||
|
fn encode<E: crate::enc::Encoder>(
|
||||||
|
&self,
|
||||||
|
mut encoder: E,
|
||||||
|
) -> Result<(), crate::error::EncodeError> {
|
||||||
|
let serializer = ser::SerdeEncoder { enc: &mut encoder };
|
||||||
|
self.0.serialize(serializer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ use serde_incl::ser::*;
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
/// Encode a `serde` `Serialize` type into a `Vec<u8>` with the bincode algorithm
|
/// Encode a `serde` `Serialize` type into a `Vec<u8>` with the bincode algorithm
|
||||||
pub fn serde_encode_to_vec<T, C>(t: T, config: C) -> Result<Vec<u8>, EncodeError>
|
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||||
|
pub fn encode_to_vec<T, C>(t: T, config: C) -> Result<Vec<u8>, EncodeError>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
C: Config,
|
C: Config,
|
||||||
|
|
@ -21,7 +22,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode a `serde` `Serialize` type into a given byte slice with the bincode algorithm
|
/// Encode a `serde` `Serialize` type into a given byte slice with the bincode algorithm
|
||||||
pub fn serde_encode_to_slice<T, C>(t: T, slice: &mut [u8], config: C) -> Result<usize, EncodeError>
|
pub fn encode_to_slice<T, C>(t: T, slice: &mut [u8], config: C) -> Result<usize, EncodeError>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
C: Config,
|
C: Config,
|
||||||
|
|
@ -33,8 +34,8 @@ where
|
||||||
Ok(encoder.into_writer().bytes_written())
|
Ok(encoder.into_writer().bytes_written())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerdeEncoder<'a, ENC: Encoder> {
|
pub(super) struct SerdeEncoder<'a, ENC: Encoder> {
|
||||||
enc: &'a mut ENC,
|
pub(super) enc: &'a mut ENC,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, ENC> Serializer for SerdeEncoder<'a, ENC>
|
impl<'a, ENC> Serializer for SerdeEncoder<'a, ENC>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
//! |alloc | Yes |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec`|
|
//! |alloc | Yes |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec`|
|
||||||
//! |atomic| Yes |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`||
|
//! |atomic| Yes |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`||
|
||||||
//! |derive| Yes |||Enables the `BorrowDecode`, `Decode` and `Encode` derive macros|
|
//! |derive| Yes |||Enables the `BorrowDecode`, `Decode` and `Encode` derive macros|
|
||||||
//! |serde | No |TODO|TODO|TODO|
|
//! |serde | No |`Compat` and `BorrowCompat`, which will work for all types that implement serde's traits|serde-specific encode/decode functions in the [serde] module|Note: There are several [known issues](serde/index.html#known-issues) when using serde and bincode|
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
|
|
|
||||||
|
|
@ -61,16 +61,16 @@ fn test_serialize_deserialize_borrowed_data() {
|
||||||
|
|
||||||
let mut result = [0u8; 20];
|
let mut result = [0u8; 20];
|
||||||
let len =
|
let len =
|
||||||
bincode::serde_encode_to_slice(&input, &mut result, Configuration::standard()).unwrap();
|
bincode::serde::encode_to_slice(&input, &mut result, Configuration::standard()).unwrap();
|
||||||
let result = &result[..len];
|
let result = &result[..len];
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
|
||||||
let result = bincode::serde_encode_to_vec(&input, Configuration::standard()).unwrap();
|
let result = bincode::serde::encode_to_vec(&input, Configuration::standard()).unwrap();
|
||||||
|
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
|
||||||
let output: SerdeWithBorrowedData =
|
let output: SerdeWithBorrowedData =
|
||||||
bincode::serde_decode_borrowed_from_slice(&result, Configuration::standard()).unwrap();
|
bincode::serde::decode_borrowed_from_slice(&result, Configuration::standard()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SerdeWithBorrowedData {
|
SerdeWithBorrowedData {
|
||||||
b: 0, // remember: b is skipped
|
b: 0, // remember: b is skipped
|
||||||
|
|
@ -107,16 +107,16 @@ fn test_serialize_deserialize_owned_data() {
|
||||||
|
|
||||||
let mut result = [0u8; 20];
|
let mut result = [0u8; 20];
|
||||||
let len =
|
let len =
|
||||||
bincode::serde_encode_to_slice(&input, &mut result, Configuration::standard()).unwrap();
|
bincode::serde::encode_to_slice(&input, &mut result, Configuration::standard()).unwrap();
|
||||||
let result = &result[..len];
|
let result = &result[..len];
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
|
||||||
let result = bincode::serde_encode_to_vec(&input, Configuration::standard()).unwrap();
|
let result = bincode::serde::encode_to_vec(&input, Configuration::standard()).unwrap();
|
||||||
|
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
|
||||||
let output: SerdeWithOwnedData =
|
let output: SerdeWithOwnedData =
|
||||||
bincode::serde_decode_from_slice(&result, Configuration::standard()).unwrap();
|
bincode::serde::decode_from_slice(&result, Configuration::standard()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SerdeWithOwnedData {
|
SerdeWithOwnedData {
|
||||||
b: 0, // remember: b is skipped
|
b: 0, // remember: b is skipped
|
||||||
|
|
@ -125,3 +125,53 @@ fn test_serialize_deserialize_owned_data() {
|
||||||
output
|
output
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "derive")]
|
||||||
|
mod derive {
|
||||||
|
use bincode::{config::Configuration, Decode, Encode};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(crate = "serde_incl")]
|
||||||
|
pub struct SerdeType {
|
||||||
|
pub a: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Decode, Encode, PartialEq, Debug)]
|
||||||
|
pub struct StructWithSerde {
|
||||||
|
#[bincode(with_serde)]
|
||||||
|
pub serde: SerdeType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Decode, Encode, PartialEq, Debug)]
|
||||||
|
pub enum EnumWithSerde {
|
||||||
|
Unit(#[bincode(with_serde)] SerdeType),
|
||||||
|
Struct {
|
||||||
|
#[bincode(with_serde)]
|
||||||
|
serde: SerdeType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serde_derive() {
|
||||||
|
fn test_encode_decode<T>(start: T)
|
||||||
|
where
|
||||||
|
T: bincode::Encode + bincode::Decode + PartialEq + core::fmt::Debug,
|
||||||
|
{
|
||||||
|
let mut slice = [0u8; 100];
|
||||||
|
let len =
|
||||||
|
bincode::encode_into_slice(&start, &mut slice, Configuration::standard()).unwrap();
|
||||||
|
let slice = &slice[..len];
|
||||||
|
let result: T = bincode::decode_from_slice(&slice, Configuration::standard()).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(start, result);
|
||||||
|
}
|
||||||
|
test_encode_decode(StructWithSerde {
|
||||||
|
serde: SerdeType { a: 5 },
|
||||||
|
});
|
||||||
|
test_encode_decode(EnumWithSerde::Unit(SerdeType { a: 5 }));
|
||||||
|
test_encode_decode(EnumWithSerde::Struct {
|
||||||
|
serde: SerdeType { a: 5 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue