Included spec.md into cargo's documentation, fixed the issues, changed the [u8; N] implementations to [T; N]
This commit is contained in:
parent
435e030182
commit
151edf46d3
66
docs/spec.md
66
docs/spec.md
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
*NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization with `serde-derive` is supported as well. `serde-derive` has the same guarantees as `bincode_derive` for now.
|
*NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization with `serde-derive` is supported as well. `serde-derive` has the same guarantees as `bincode_derive` for now.
|
||||||
|
|
||||||
Related issue: https://github.com/serde-rs/serde/issues/1756#issuecomment-689682123
|
Related issue: <https://github.com/serde-rs/serde/issues/1756#issuecomment-689682123>
|
||||||
|
|
||||||
## Endian
|
## Endian
|
||||||
|
|
||||||
|
|
@ -17,12 +17,14 @@ All basic numeric types will be encoded based on the configured [IntEncoding](#I
|
||||||
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.
|
||||||
|
|
||||||
All tuples have no additional bytes, and are encoded in their specified order, e.g.
|
All tuples have no additional bytes, and are encoded in their specified order, e.g.
|
||||||
```rs
|
```rust
|
||||||
|
use bincode::config::Configuration;
|
||||||
|
|
||||||
let tuple = (u32::min_value(), i32::max_value()); // 8 bytes
|
let tuple = (u32::min_value(), i32::max_value()); // 8 bytes
|
||||||
let encoded = bincode::encode_to_vec_with_options(&tuple, Options::default().with_fixint_encoding()).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(tuple, Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[
|
assert_eq!(encoded.as_slice(), &[
|
||||||
0, 0, 0, 0, // 4 bytes for first type: u32
|
0, 0, 0, 0, // 4 bytes for first type: u32
|
||||||
255, 255, 255, 255 // 4 bytes for second type: i32
|
255, 255, 255, 127 // 4 bytes for second type: i32
|
||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -56,7 +58,9 @@ Enums are encoded with their variant first, followed by optionally the variant f
|
||||||
|
|
||||||
Both named and unnamed fields are serialized with their values only, and therefor encode to the same value.
|
Both named and unnamed fields are serialized with their values only, and therefor encode to the same value.
|
||||||
|
|
||||||
```rs
|
```rust
|
||||||
|
use bincode::config::Configuration;
|
||||||
|
|
||||||
#[derive(bincode::Encode)]
|
#[derive(bincode::Encode)]
|
||||||
pub enum SomeEnum {
|
pub enum SomeEnum {
|
||||||
A,
|
A,
|
||||||
|
|
@ -65,23 +69,23 @@ pub enum SomeEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SomeEnum::A
|
// SomeEnum::A
|
||||||
let encoded = bincode::encode_to_vec_with_options(&SomeEnum::A, Options::default().with_fixint_encoding()).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(SomeEnum::A, Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[
|
assert_eq!(encoded.as_slice(), &[
|
||||||
0, 0, 0, 0, // first variant, A
|
0, 0, 0, 0, // first variant, A
|
||||||
// no extra bytes because A has no fields
|
// no extra bytes because A has no fields
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// SomeEnum::B(0)
|
// SomeEnum::B(0)
|
||||||
let encoded = bincode::encode_to_vec_with_options(&SomeEnum::B(0), Options::default().with_fixint_encoding()).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(SomeEnum::B(0), Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[
|
assert_eq!(encoded.as_slice(), &[
|
||||||
0, 0, 0, 1, // first variant, B
|
1, 0, 0, 0, // first variant, B
|
||||||
0, 0, 0, 0 // B has 1 unnamed field, which is an u32, so 4 bytes
|
0, 0, 0, 0 // B has 1 unnamed field, which is an u32, so 4 bytes
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// SomeEnum::C { value: 0u32 }
|
// SomeEnum::C { value: 0u32 }
|
||||||
let encoded = bincode::encode_to_vec_with_options(&SomeEnum::C { value: 0u32 }, Options::default().with_fixint_encoding()).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(SomeEnum::C { value: 0u32 }, Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[
|
assert_eq!(encoded.as_slice(), &[
|
||||||
0, 0, 0, 2, // first variant, C
|
2, 0, 0, 0, // first variant, C
|
||||||
0, 0, 0, 0 // C has 1 named field which is a u32, so 4 bytes
|
0, 0, 0, 0 // C has 1 named field which is a u32, so 4 bytes
|
||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
@ -92,16 +96,17 @@ Collections are encoded with their length value first, following by each entry o
|
||||||
|
|
||||||
**note**: fixed array length do not have their `len` encoded. See [Arrays](#arrays)
|
**note**: fixed array length do not have their `len` encoded. See [Arrays](#arrays)
|
||||||
|
|
||||||
```rs
|
```rust
|
||||||
|
use bincode::config::Configuration;
|
||||||
let list = vec![
|
let list = vec![
|
||||||
0u8,
|
0u8,
|
||||||
1u8,
|
1u8,
|
||||||
2u8
|
2u8
|
||||||
];
|
];
|
||||||
|
|
||||||
let encoded = bincode::encode_to_vec_with_options(&list, Options::default().with_fixint_encoding()).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(list, Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[
|
assert_eq!(encoded.as_slice(), &[
|
||||||
0, 0, 0, 0, 0, 0, 0, 3, // length of 3u64
|
3, 0, 0, 0, 0, 0, 0, 0, // length of 3u64
|
||||||
0, // entry 0
|
0, // entry 0
|
||||||
1, // entry 1
|
1, // entry 1
|
||||||
2, // entry 2
|
2, // entry 2
|
||||||
|
|
@ -114,30 +119,39 @@ This also applies to e.g. `HashMap`, where each entry is a [tuple](#basic-types)
|
||||||
|
|
||||||
Both `String` and `&str` are treated as a `Vec<u8>`. See [Collections](#collections) for more information.
|
Both `String` and `&str` are treated as a `Vec<u8>`. See [Collections](#collections) for more information.
|
||||||
|
|
||||||
```rs
|
```rust
|
||||||
|
use bincode::config::Configuration;
|
||||||
|
|
||||||
let str = "Hello"; // Could also be `String::new(...)`
|
let str = "Hello"; // Could also be `String::new(...)`
|
||||||
|
|
||||||
let encoded = bincode::encode_to_vec_with_options(&list, Options::default().with_fixint_encoding()).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(str, Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[
|
assert_eq!(encoded.as_slice(), &[
|
||||||
0, 0, 0, 0, 0, 0, 0, 5, // length of the string, 5 bytes
|
5, 0, 0, 0, 0, 0, 0, 0, // length of the string, 5 bytes
|
||||||
b'H', b'e', b'l', b'l', b'o'
|
b'H', b'e', b'l', b'l', b'o'
|
||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
# Arrays
|
# Arrays
|
||||||
|
|
||||||
Arrays are encoded *without* a length.
|
Arrays are encoded *with* a length by default.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use bincode::config::Configuration;
|
||||||
|
|
||||||
```rs
|
|
||||||
let arr: [u8; 5] = [10, 20, 30, 40, 50];
|
let arr: [u8; 5] = [10, 20, 30, 40, 50];
|
||||||
let encoded = bincode::encode_to_vec(&list).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(arr, Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[10, 20, 30, 40 50]);
|
assert_eq!(encoded.as_slice(), &[
|
||||||
|
5, 0, 0, 0, 0, 0, 0, 0, // The length, as a u64
|
||||||
|
10, 20, 30, 40, 50, // the bytes
|
||||||
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
This applies to any type `T` that implements `Encodabl`/`Decodabl`
|
This applies to any type `T` that implements `Encodabl`/`Decodabl`
|
||||||
|
|
||||||
```rs
|
```rust
|
||||||
#[derive(bincode::Encodabl)]
|
use bincode::config::Configuration;
|
||||||
|
|
||||||
|
#[derive(bincode::Encode)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
first: u8,
|
first: u8,
|
||||||
second: u8
|
second: u8
|
||||||
|
|
@ -154,7 +168,11 @@ let arr: [Foo; 2] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let encoded = bincode::encode_to_vec(&list).unwrap();
|
let encoded = bincode::encode_to_vec_with_config(arr, Configuration::legacy()).unwrap();
|
||||||
assert_eq!(encoded.as_slice(), &[10, 20, 30, 40]);
|
assert_eq!(encoded.as_slice(), &[
|
||||||
|
2, 0, 0, 0, 0, 0, 0, 0, // Length of the array
|
||||||
|
10, 20, // First Foo
|
||||||
|
30, 40, // Second Foo
|
||||||
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -382,9 +382,11 @@ impl<'a, 'de: 'a> BorrowDecode<'de> for &'a str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Decode for [u8; N] {
|
impl<T, const N: usize> Decode for [T; N]
|
||||||
|
where
|
||||||
|
T: Decode + Sized,
|
||||||
|
{
|
||||||
fn decode<D: Decoder>(mut decoder: D) -> Result<Self, DecodeError> {
|
fn decode<D: Decoder>(mut decoder: D) -> Result<Self, DecodeError> {
|
||||||
let mut array = [0u8; N];
|
|
||||||
if !D::C::SKIP_FIXED_ARRAY_LENGTH {
|
if !D::C::SKIP_FIXED_ARRAY_LENGTH {
|
||||||
let length = usize::decode(&mut decoder)?;
|
let length = usize::decode(&mut decoder)?;
|
||||||
if length != N {
|
if length != N {
|
||||||
|
|
@ -394,8 +396,38 @@ impl<const N: usize> Decode for [u8; N] {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decoder.reader().read(&mut array)?;
|
|
||||||
Ok(array)
|
// Safety: this is taken from the example of https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html
|
||||||
|
// and is therefor assumed to be safe
|
||||||
|
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
|
// Create an uninitialized array of `MaybeUninit`. The `assume_init` is
|
||||||
|
// safe because the type we are claiming to have initialized here is a
|
||||||
|
// bunch of `MaybeUninit`s, which do not require initialization.
|
||||||
|
let mut data: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||||
|
|
||||||
|
// Dropping a `MaybeUninit` does nothing. Thus using raw pointer
|
||||||
|
// assignment instead of `ptr::write` does not cause the old
|
||||||
|
// uninitialized value to be dropped. Also if there is a panic during
|
||||||
|
// this loop, we have a memory leak, but there is no memory safety
|
||||||
|
// issue.
|
||||||
|
for elem in &mut data[..] {
|
||||||
|
elem.write(T::decode(&mut decoder)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything is initialized. Transmute the array to the
|
||||||
|
// initialized type.
|
||||||
|
|
||||||
|
// BlockedTODO: https://github.com/rust-lang/rust/issues/61956
|
||||||
|
// let result = unsafe { transmute::<_, [T; N]>(data) };
|
||||||
|
|
||||||
|
// Const generics don't work well with transmute at the moment
|
||||||
|
// The above issue recommends doing the following
|
||||||
|
let ptr = &mut data as *mut _ as *mut [T; N];
|
||||||
|
let res = unsafe { ptr.read() };
|
||||||
|
core::mem::forget(data);
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,12 +338,18 @@ impl Encode for &'_ str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Encode for [u8; N] {
|
impl<T, const N: usize> Encode for [T; N]
|
||||||
|
where
|
||||||
|
T: Encode,
|
||||||
|
{
|
||||||
fn encode<E: Encoder>(&self, mut encoder: E) -> Result<(), EncodeError> {
|
fn encode<E: Encoder>(&self, mut encoder: E) -> Result<(), EncodeError> {
|
||||||
if !E::C::SKIP_FIXED_ARRAY_LENGTH {
|
if !E::C::SKIP_FIXED_ARRAY_LENGTH {
|
||||||
N.encode(&mut encoder)?;
|
N.encode(&mut encoder)?;
|
||||||
}
|
}
|
||||||
encoder.writer().write(self)
|
for item in self.iter() {
|
||||||
|
item.encode(&mut encoder)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,3 +91,7 @@ pub fn decode_with_config<'__de, D: de::BorrowDecode<'__de>, C: Config>(
|
||||||
let mut decoder = de::DecoderImpl::<_, C>::new(reader, _config);
|
let mut decoder = de::DecoderImpl::<_, C>::new(reader, _config);
|
||||||
D::borrow_decode(&mut decoder)
|
D::borrow_decode(&mut decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod spec {
|
||||||
|
#![doc = include_str!("../docs/spec.md")]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ where
|
||||||
C: Config,
|
C: Config,
|
||||||
CMP: Fn(&V, &V) -> bool,
|
CMP: Fn(&V, &V) -> bool,
|
||||||
{
|
{
|
||||||
let mut buffer = [0u8; 1024];
|
let mut buffer = [0u8; 2048];
|
||||||
let len = bincode::encode_into_slice_with_config(&element, &mut buffer, config).unwrap();
|
let len = bincode::encode_into_slice_with_config(&element, &mut buffer, config).unwrap();
|
||||||
println!(
|
println!(
|
||||||
"{:?}: {:?} ({:?})",
|
"{:?}: {:?} ({:?})",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue