Skip to content

[Breaking change] Made all decode_from_slice also return the number of bytes read #445

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

Merged
merged 2 commits into from
Dec 11, 2021
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
8 changes: 4 additions & 4 deletions benches/varint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn slice_varint_u8(c: &mut Criterion) {

c.bench_function("slice_varint_u8", |b| {
b.iter(|| {
let _: Vec<u8> = bincode::decode_from_slice(&bytes, config).unwrap();
let _: (Vec<u8>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
Expand All @@ -30,7 +30,7 @@ fn slice_varint_u16(c: &mut Criterion) {

c.bench_function("slice_varint_u16", |b| {
b.iter(|| {
let _: Vec<u16> = bincode::decode_from_slice(&bytes, config).unwrap();
let _: (Vec<u8>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
Expand All @@ -46,7 +46,7 @@ fn slice_varint_u32(c: &mut Criterion) {

c.bench_function("slice_varint_u32", |b| {
b.iter(|| {
let _: Vec<u32> = bincode::decode_from_slice(&bytes, config).unwrap();
let _: (Vec<u16>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
Expand All @@ -62,7 +62,7 @@ fn slice_varint_u64(c: &mut Criterion) {

c.bench_function("slice_varint_u64", |b| {
b.iter(|| {
let _: Vec<u64> = bincode::decode_from_slice(&bytes, config).unwrap();
let _: (Vec<u64>, usize) = bincode::decode_from_slice(&bytes, config).unwrap();
})
});
}
Expand Down
1 change: 1 addition & 0 deletions derive/src/parse/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ impl Generics {
}

#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
enum Generic {
Lifetime(Lifetime),
Simple(SimpleGeneric),
Expand Down
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ fn main() {
// The 4 floats are encoded in 4 bytes each.
assert_eq!(encoded.len(), 1 + 4 * 4);

let decoded: World = bincode::decode_from_slice(&encoded[..], config).unwrap();
let (decoded, len): (World, usize) = bincode::decode_from_slice(&encoded[..], config).unwrap();

assert_eq!(world, decoded);
assert_eq!(len, encoded.len()); // read all bytes
}
```

Expand Down
1 change: 1 addition & 0 deletions src/de/impl_core.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(unused_unsafe)]
#![allow(clippy::needless_borrow)]

//! Contains implementations for rust core that have not been stabilized
//!
Expand Down
2 changes: 1 addition & 1 deletion src/de/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub trait BorrowReader<'storage>: Reader {

/// A reader type for `&[u8]` slices. Implements both [Reader] and [BorrowReader], and thus can be used for borrowed data.
pub struct SliceReader<'storage> {
slice: &'storage [u8],
pub(crate) slice: &'storage [u8],
}

impl<'storage> SliceReader<'storage> {
Expand Down
8 changes: 5 additions & 3 deletions src/features/serde/de_owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ use crate::{
};
use serde_incl::de::*;

/// Decode an owned type from the given slice.
/// Decode an owned type from the given slice. Will return the decoded type `T` as well as the amount of bytes that were read.
///
/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [decode_borrowed_from_slice].
///
/// [decode_borrowed_from_slice]: fn.decode_borrowed_from_slice.html
pub fn decode_from_slice<T, C>(slice: &[u8], config: C) -> Result<T, DecodeError>
pub fn decode_from_slice<T, C>(slice: &[u8], config: C) -> Result<(T, usize), DecodeError>
where
T: DeserializeOwned,
C: Config,
{
let reader = crate::de::read::SliceReader::new(slice);
let mut decoder = crate::de::DecoderImpl::new(reader, config);
let serde_decoder = SerdeDecoder { de: &mut decoder };
T::deserialize(serde_decoder)
let result = T::deserialize(serde_decoder)?;
let bytes_read = slice.len() - decoder.reader().slice.len();
Ok((result, bytes_read))
}

pub(crate) struct SerdeDecoder<'a, DE: Decoder> {
Expand Down
10 changes: 6 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
//!
//! // Decoding works the same as encoding.
//! // The trait used is `de::Decode`, and can also be automatically implemented with the `derive` feature.
//! let decoded: (u8, u32, i128, char, [u8; 4]) = bincode::decode_from_slice(slice, Configuration::standard()).unwrap();
//! let decoded: (u8, u32, i128, char, [u8; 4]) = bincode::decode_from_slice(slice, Configuration::standard()).unwrap().0;
//!
//! assert_eq!(decoded, input);
//! ```
Expand All @@ -67,7 +67,7 @@ mod features;
pub(crate) mod utils;
pub(crate) mod varint;

use de::read::Reader;
use de::{read::Reader, Decoder};
use enc::write::Writer;
pub use features::*;

Expand Down Expand Up @@ -120,10 +120,12 @@ pub fn encode_into_writer<E: enc::Encode, W: Writer, C: Config>(
pub fn decode_from_slice<'a, D: de::BorrowDecode<'a>, C: Config>(
src: &'a [u8],
config: C,
) -> Result<D, error::DecodeError> {
) -> Result<(D, usize), error::DecodeError> {
let reader = de::read::SliceReader::new(src);
let mut decoder = de::DecoderImpl::<_, C>::new(reader, config);
D::borrow_decode(&mut decoder)
let result = D::borrow_decode(&mut decoder)?;
let bytes_read = src.len() - decoder.reader().slice.len();
Ok((result, bytes_read))
}

/// Attempt to decode a given type `D` from the given [Reader].
Expand Down
4 changes: 3 additions & 1 deletion tests/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ fn test_vec() {
let vec = bincode::encode_to_vec(Foo { a: 5, b: 10 }, Configuration::standard()).unwrap();
assert_eq!(vec, &[5, 10]);

let foo: Foo = bincode::decode_from_slice(&vec, Configuration::standard()).unwrap();
let (foo, len): (Foo, usize) =
bincode::decode_from_slice(&vec, Configuration::standard()).unwrap();
assert_eq!(foo.a, 5);
assert_eq!(foo.b, 10);
assert_eq!(len, 2);
}

#[test]
Expand Down
21 changes: 14 additions & 7 deletions tests/basic_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,10 @@ fn test_slice() {
bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap();
assert_eq!(&buffer[..8], &[7, 1, 2, 3, 4, 5, 6, 7]);

let output: &[u8] =
let (output, len): (&[u8], usize) =
bincode::decode_from_slice(&mut buffer[..8], Configuration::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, 8);
}

#[test]
Expand All @@ -148,18 +149,20 @@ fn test_option_slice() {
let n = bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap();
assert_eq!(&buffer[..n], &[1, 7, 1, 2, 3, 4, 5, 6, 7]);

let output: Option<&[u8]> =
let (output, len): (Option<&[u8]>, usize) =
bincode::decode_from_slice(&buffer[..n], Configuration::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);

let mut buffer = [0u8; 32];
let input: Option<&[u8]> = None;
let n = bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap();
assert_eq!(&buffer[..n], &[0]);

let output: Option<&[u8]> =
let (output, len): (Option<&[u8]>, usize) =
bincode::decode_from_slice(&buffer[..n], Configuration::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);
}

#[test]
Expand All @@ -172,9 +175,10 @@ fn test_str() {
&[11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
);

let output: &str =
let (output, len): (&str, usize) =
bincode::decode_from_slice(&mut buffer[..12], Configuration::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, 12);
}

#[test]
Expand All @@ -187,18 +191,20 @@ fn test_option_str() {
&[1, 11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
);

let output: Option<&str> =
let (output, len): (Option<&str>, usize) =
bincode::decode_from_slice(&buffer[..n], Configuration::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);

let mut buffer = [0u8; 32];
let input: Option<&str> = None;
let n = bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap();
assert_eq!(&buffer[..n], &[0]);

let output: Option<&str> =
let (output, len): (Option<&str>, usize) =
bincode::decode_from_slice(&buffer[..n], Configuration::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, n);
}

#[test]
Expand All @@ -208,7 +214,8 @@ fn test_array() {
bincode::encode_into_slice(input, &mut buffer, Configuration::standard()).unwrap();
assert_eq!(&buffer[..10], &[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);

let output: [u8; 10] =
let (output, len): ([u8; 10], usize) =
bincode::decode_from_slice(&mut buffer[..10], Configuration::standard()).unwrap();
assert_eq!(input, output);
assert_eq!(len, 10);
}
25 changes: 18 additions & 7 deletions tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ fn test_decode() {
c: 1024u32,
};
let slice = [5, 10, 251, 0, 4];
let result: Test2<u32> = bincode::decode_from_slice(&slice, Configuration::standard()).unwrap();
let (result, len): (Test2<u32>, usize) =
bincode::decode_from_slice(&slice, Configuration::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 5);
}

#[test]
Expand All @@ -79,8 +81,11 @@ fn test_encode_decode_str() {
let mut slice = [0u8; 100];

let len = bincode::encode_into_slice(&start, &mut slice, Configuration::standard()).unwrap();
let end: Test3 = bincode::decode_from_slice(&slice[..len], Configuration::standard()).unwrap();
assert_eq!(len, 21);
let (end, len): (Test3, usize) =
bincode::decode_from_slice(&slice[..len], Configuration::standard()).unwrap();
assert_eq!(end, start);
assert_eq!(len, 21);
}

#[test]
Expand All @@ -97,9 +102,10 @@ fn test_encode_tuple() {
fn test_decode_tuple() {
let start = TestTupleStruct(5, 10, 1024);
let mut slice = [5, 10, 251, 0, 4];
let result: TestTupleStruct =
let (result, len): (TestTupleStruct, usize) =
bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 5);
}

#[test]
Expand All @@ -116,9 +122,10 @@ fn test_encode_enum_struct_variant() {
fn test_decode_enum_struct_variant() {
let start = TestEnum::Bar { name: 5u32 };
let mut slice = [1, 5];
let result: TestEnum =
let (result, len): (TestEnum, usize) =
bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 2);
}

#[test]
Expand All @@ -135,9 +142,10 @@ fn test_encode_enum_tuple_variant() {
fn test_decode_enum_unit_variant() {
let start = TestEnum::Foo;
let mut slice = [0];
let result: TestEnum =
let (result, len): (TestEnum, usize) =
bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 1);
}

#[test]
Expand All @@ -154,9 +162,10 @@ fn test_encode_enum_unit_variant() {
fn test_decode_enum_tuple_variant() {
let start = TestEnum::Baz(5, 10, 1024);
let mut slice = [2, 5, 10, 251, 0, 4];
let result: TestEnum =
let (result, len): (TestEnum, usize) =
bincode::decode_from_slice(&mut slice, Configuration::standard()).unwrap();
assert_eq!(result, start);
assert_eq!(len, 6);
}

#[derive(bincode::Decode, bincode::Encode, PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -185,7 +194,9 @@ fn test_c_style_enum() {
assert_eq!(ser(CStyleEnum::E), 6);

fn de(num: u8) -> Result<CStyleEnum, bincode::error::DecodeError> {
bincode::decode_from_slice(&[num], Configuration::standard())
let (result, len) = bincode::decode_from_slice(&[num], Configuration::standard())?;
assert_eq!(len, 1);
Ok(result)
}

fn expected_err(idx: u32) -> Result<CStyleEnum, bincode::error::DecodeError> {
Expand Down
4 changes: 3 additions & 1 deletion tests/issues/issue_431.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ fn test() {
};
let vec = bincode::encode_to_vec(&t, Configuration::standard()).unwrap();

let decoded: T<String> = bincode::decode_from_slice(&vec, Configuration::standard()).unwrap();
let (decoded, len): (T<String>, usize) =
bincode::decode_from_slice(&vec, Configuration::standard()).unwrap();

assert_eq!(t, decoded);
assert_eq!(len, 12);
}
33 changes: 22 additions & 11 deletions tests/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ fn test_serde_round_trip() {
let bytes =
bincode::encode_to_vec(SerdeRoundtrip { a: 15, b: 15 }, Configuration::standard()).unwrap();
assert_eq!(bytes, &[15, 15]);
let result: SerdeRoundtrip =
let (result, len): (SerdeRoundtrip, usize) =
bincode::decode_from_slice(&bytes, Configuration::standard()).unwrap();
assert_eq!(result.a, 15);
assert_eq!(result.b, 15);
assert_eq!(len, 2);
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
Expand Down Expand Up @@ -115,7 +116,7 @@ fn test_serialize_deserialize_owned_data() {

assert_eq!(result, expected);

let output: SerdeWithOwnedData =
let (output, len): (SerdeWithOwnedData, usize) =
bincode::serde::decode_from_slice(&result, Configuration::standard()).unwrap();
assert_eq!(
SerdeWithOwnedData {
Expand All @@ -124,6 +125,7 @@ fn test_serialize_deserialize_owned_data() {
},
output
);
assert_eq!(len, 13);
}

#[cfg(feature = "derive")]
Expand Down Expand Up @@ -154,24 +156,33 @@ mod derive {

#[test]
fn test_serde_derive() {
fn test_encode_decode<T>(start: T)
fn test_encode_decode<T>(start: T, expected_len: usize)
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();
assert_eq!(len, expected_len);
let slice = &slice[..len];
let result: T = bincode::decode_from_slice(&slice, Configuration::standard()).unwrap();
let (result, len): (T, usize) =
bincode::decode_from_slice(&slice, Configuration::standard()).unwrap();

assert_eq!(start, result);
assert_eq!(len, expected_len);
}
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 },
});
test_encode_decode(
StructWithSerde {
serde: SerdeType { a: 5 },
},
1,
);
test_encode_decode(EnumWithSerde::Unit(SerdeType { a: 5 }), 2);
test_encode_decode(
EnumWithSerde::Struct {
serde: SerdeType { a: 5 },
},
2,
);
}
}
Loading