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

Moved Configuration::standard() and ::legacy() to the config module #481

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
5 changes: 2 additions & 3 deletions benches/inline.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use bincode::config;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use bincode::config::Configuration;

fn inline_decoder_claim_bytes_read(c: &mut Criterion) {
let config = Configuration::standard().with_limit::<100000>();
let config = config::standard().with_limit::<100000>();
let slice = bincode::encode_to_vec(vec![String::from("Hello world"); 1000], config).unwrap();

c.bench_function("inline_decoder_claim_bytes_read", |b| {
Expand Down
19 changes: 9 additions & 10 deletions benches/varint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use bincode::config;
use criterion::{criterion_group, criterion_main, Criterion};

use bincode::config::Configuration;
use rand::distributions::Distribution;

fn slice_varint_u8(c: &mut Criterion) {
Expand All @@ -9,7 +8,7 @@ fn slice_varint_u8(c: &mut Criterion) {
let input: Vec<u8> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("slice_varint_u8", |b| {
Expand All @@ -25,7 +24,7 @@ fn slice_varint_u16(c: &mut Criterion) {
let input: Vec<u16> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("slice_varint_u16", |b| {
Expand All @@ -41,7 +40,7 @@ fn slice_varint_u32(c: &mut Criterion) {
let input: Vec<u32> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("slice_varint_u32", |b| {
Expand All @@ -57,7 +56,7 @@ fn slice_varint_u64(c: &mut Criterion) {
let input: Vec<u64> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("slice_varint_u64", |b| {
Expand All @@ -73,7 +72,7 @@ fn bufreader_varint_u8(c: &mut Criterion) {
let input: Vec<u8> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("bufreader_varint_u8", |b| {
Expand All @@ -91,7 +90,7 @@ fn bufreader_varint_u16(c: &mut Criterion) {
let input: Vec<u16> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("bufreader_varint_u16", |b| {
Expand All @@ -109,7 +108,7 @@ fn bufreader_varint_u32(c: &mut Criterion) {
let input: Vec<u32> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("bufreader_varint_u32", |b| {
Expand All @@ -127,7 +126,7 @@ fn bufreader_varint_u64(c: &mut Criterion) {
let input: Vec<u64> = std::iter::from_fn(|| Some(dist.sample(&mut rng)))
.take(10_000)
.collect();
let config = Configuration::standard();
let config = config::standard();
let bytes = bincode::encode_to_vec(&input, config).unwrap();

c.bench_function("bufreader_varint_u64", |b| {
Expand Down
31 changes: 10 additions & 21 deletions docs/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ All floating point types will take up exactly 4 (for `f32`) or 8 (for `f64`) byt

All tuples have no additional bytes, and are encoded in their specified order, e.g.
```rust
use bincode::config::Configuration;

let tuple = (u32::min_value(), i32::max_value()); // 8 bytes
let encoded = bincode::encode_to_vec(tuple, Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(tuple, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
0, 0, 0, 0, // 4 bytes for first type: u32
255, 255, 255, 127 // 4 bytes for second type: i32
Expand Down Expand Up @@ -59,8 +57,6 @@ 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.

```rust
use bincode::config::Configuration;

#[derive(bincode::Encode)]
pub enum SomeEnum {
A,
Expand All @@ -69,21 +65,21 @@ pub enum SomeEnum {
}

// SomeEnum::A
let encoded = bincode::encode_to_vec(SomeEnum::A, Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(SomeEnum::A, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
0, 0, 0, 0, // first variant, A
// no extra bytes because A has no fields
]);

// SomeEnum::B(0)
let encoded = bincode::encode_to_vec(SomeEnum::B(0), Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(SomeEnum::B(0), bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
1, 0, 0, 0, // first variant, B
0, 0, 0, 0 // B has 1 unnamed field, which is an u32, so 4 bytes
]);

// SomeEnum::C { value: 0u32 }
let encoded = bincode::encode_to_vec(SomeEnum::C { value: 0u32 }, Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(SomeEnum::C { value: 0u32 }, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
2, 0, 0, 0, // first variant, C
0, 0, 0, 0 // C has 1 named field which is a u32, so 4 bytes
Expand All @@ -97,14 +93,13 @@ Collections are encoded with their length value first, following by each entry o
**note**: fixed array length may not have their `len` encoded. See [Arrays](#arrays)

```rust
use bincode::config::Configuration;
let list = vec![
0u8,
1u8,
2u8
];

let encoded = bincode::encode_to_vec(list, Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(list, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
3, 0, 0, 0, 0, 0, 0, 0, // length of 3u64
0, // entry 0
Expand All @@ -120,11 +115,9 @@ 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.

```rust
use bincode::config::Configuration;

let str = "Hello"; // Could also be `String::new(...)`

let encoded = bincode::encode_to_vec(str, Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(str, bincode::config::legacy()).unwrap();
assert_eq!(encoded.as_slice(), &[
5, 0, 0, 0, 0, 0, 0, 0, // length of the string, 5 bytes
b'H', b'e', b'l', b'l', b'o'
Expand All @@ -139,16 +132,14 @@ Note that `&[T]` is encoded as a [Collection](#collections).


```rust
use bincode::config::Configuration;

let arr: [u8; 5] = [10, 20, 30, 40, 50];
let encoded = bincode::encode_to_vec(arr, Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(arr, bincode::config::legacy()).unwrap();
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
]);

let encoded = bincode::encode_to_vec(arr, Configuration::legacy().skip_fixed_array_length()).unwrap();
let encoded = bincode::encode_to_vec(arr, bincode::config::legacy().skip_fixed_array_length()).unwrap();
assert_eq!(encoded.as_slice(), &[
// no length
10, 20, 30, 40, 50, // the bytes
Expand All @@ -158,8 +149,6 @@ assert_eq!(encoded.as_slice(), &[
This applies to any type `T` that implements `Encode`/`Decode`

```rust
use bincode::config::Configuration;

#[derive(bincode::Encode)]
struct Foo {
first: u8,
Expand All @@ -177,14 +166,14 @@ let arr: [Foo; 2] = [
},
];

let encoded = bincode::encode_to_vec(&arr, Configuration::legacy()).unwrap();
let encoded = bincode::encode_to_vec(&arr, bincode::config::legacy()).unwrap();
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
]);

let encoded = bincode::encode_to_vec(&arr, Configuration::legacy().skip_fixed_array_length()).unwrap();
let encoded = bincode::encode_to_vec(&arr, bincode::config::legacy().skip_fixed_array_length()).unwrap();
assert_eq!(encoded.as_slice(), &[
// no length
10, 20, // First Foo
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ enum AllTypes {
}

fuzz_target!(|data: &[u8]| {
let config = bincode::config::Configuration::standard().with_limit::<1024>();
let config = bincode::config::standard().with_limit::<1024>();
let result: Result<(AllTypes, _), _> = bincode::decode_from_slice(data, config);

if let Ok((before, _)) = result {
Expand Down
6 changes: 3 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ library.
## Example

```rust
use bincode::{config::Configuration, Decode, Encode};
use bincode::{config, Decode, Encode};

#[derive(Encode, Decode, PartialEq, Debug)]
struct Entity {
Expand All @@ -42,7 +42,7 @@ struct Entity {
struct World(Vec<Entity>);

fn main() {
let config = Configuration::standard();
let config = config::standard();

let world = World(vec![Entity { x: 0.0, y: 4.0 }, Entity { x: 10.0, y: 20.5 }]);

Expand Down Expand Up @@ -103,7 +103,7 @@ Bincode 2.0 is still in development and does not yet have a targetted MSRV. Once

### Why does bincode not respect `#[repr(u8)]`?

Bincode will encode enum variants as a `u32`. If you're worried about storage size, we can recommend enabling `Configuration::with_varint_encoding()`. This option is enabled by default with the `standard` configuration. In this case enum variants will almost always be encoded as a `u8`.
Bincode will encode enum variants as a `u32`. If you're worried about storage size, we can recommend enabling `Configuration::with_variable_int_encoding()`. This option is enabled by default with the `standard` configuration. In this case enum variants will almost always be encoded as a `u8`.

Currently we have not found a compelling case to respect `#[repr(...)]`. You're most likely trying to interop with a format that is similar-but-not-quite-bincode. We only support our own protocol ([spec](https://github.com/bincode-org/bincode/blob/trunk/docs/spec.md)).

Expand Down
84 changes: 45 additions & 39 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
//! To use a config, first create a type of [Configuration]. This type will implement trait [Config] for use with bincode.
//!
//! ```
//! use bincode::config::{Config, Configuration};
//! let config = Configuration::standard()
//! let config = bincode::config::standard()
//! // pick one of:
//! .with_big_endian()
//! .with_little_endian()
Expand Down Expand Up @@ -47,42 +46,49 @@ pub struct Configuration<E = LittleEndian, I = Varint, A = SkipFixedArrayLength,
_l: PhantomData<L>,
}

impl Configuration {
/// The default config for bincode 2.0. By default this will be:
/// - Little endian
/// - Variable int encoding
/// - Skip fixed array length
pub const fn standard() -> Self {
Self::generate()
}
/// The default config for bincode 2.0. By default this will be:
/// - Little endian
/// - Variable int encoding
/// - Skip fixed array length
pub const fn standard() -> Configuration {
generate()
}

/// Creates the "legacy" default config. This is the default config that was present in bincode 1.0
/// - Little endian
/// - Fixed int length encoding
/// - Write array lengths
pub const fn legacy() -> Configuration<LittleEndian, Fixint, WriteFixedArrayLength, NoLimit> {
Self::generate()
}
/// Creates the "legacy" default config. This is the default config that was present in bincode 1.0
/// - Little endian
/// - Fixed int length encoding
/// - Write array lengths
pub const fn legacy() -> Configuration<LittleEndian, Fixint, WriteFixedArrayLength, NoLimit> {
generate()
}

impl<E, I, A, L> Configuration<E, I, A, L> {
const fn generate<_E, _I, _A, _L>() -> Configuration<_E, _I, _A, _L> {
Configuration {
_e: PhantomData,
_i: PhantomData,
_a: PhantomData,
_l: PhantomData,
}
const fn generate<_E, _I, _A, _L>() -> Configuration<_E, _I, _A, _L> {
Configuration {
_e: PhantomData,
_i: PhantomData,
_a: PhantomData,
_l: PhantomData,
}
}

// When adding more features to configuration, follow these steps:
// - Create 2 or more structs that can be used as a type (e.g. Limit and NoLimit)
// - Add an `Internal...Config` to the `internal` module
// - Make sure `Config` and `impl<T> Config for T` extend from this new trait
// - Add a generic to `Configuration`
// - Add this generic to `const fn generate<...>()`
// - Add this generic to _every_ function in `Configuration`
// - Add your new methods

impl<E, I, A, L> Configuration<E, I, A, L> {
/// Makes bincode encode all integer types in big endian.
pub const fn with_big_endian(self) -> Configuration<BigEndian, I, A> {
Self::generate()
pub const fn with_big_endian(self) -> Configuration<BigEndian, I, A, L> {
generate()
}

/// Makes bincode encode all integer types in little endian.
pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, A> {
Self::generate()
pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, A, L> {
generate()
}

/// Makes bincode encode all integer types with a variable integer encoding.
Expand Down Expand Up @@ -142,37 +148,37 @@ impl<E, I, A, L> Configuration<E, I, A, L> {
///
/// Note that u256 and the like are unsupported by this format; if and when they are added to the
/// language, they may be supported via the extension point given by the 255 byte.
pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, A> {
Self::generate()
pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, A, L> {
generate()
}

/// Fixed-size integer encoding.
///
/// * Fixed size integers are encoded directly
/// * Enum discriminants are encoded as u32
/// * Lengths and usize are encoded as u64
pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, A> {
Self::generate()
pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, A, L> {
generate()
}

/// Skip writing the length of fixed size arrays (`[u8; N]`) before writing the array
pub const fn skip_fixed_array_length(self) -> Configuration<E, I, SkipFixedArrayLength> {
Self::generate()
pub const fn skip_fixed_array_length(self) -> Configuration<E, I, SkipFixedArrayLength, L> {
generate()
}

/// Write the length of fixed size arrays (`[u8; N]`) before writing the array
pub const fn write_fixed_array_length(self) -> Configuration<E, I, WriteFixedArrayLength> {
Self::generate()
pub const fn write_fixed_array_length(self) -> Configuration<E, I, WriteFixedArrayLength, L> {
generate()
}

/// Sets the byte limit to `limit`.
pub const fn with_limit<const N: usize>(self) -> Configuration<E, I, A, Limit<N>> {
Self::generate()
generate()
}

/// Clear the byte limit.
pub const fn with_no_limit(self) -> Configuration<E, I, A, NoLimit> {
Self::generate()
generate()
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/de/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ use crate::{config::Config, error::DecodeError, utils::Sealed};
/// # let slice: &[u8] = &[0, 0, 0, 0];
/// # let some_reader = bincode::de::read::SliceReader::new(slice);
/// use bincode::de::{DecoderImpl, Decode};
/// use bincode::config;
/// let mut decoder = DecoderImpl::new(some_reader, config::Configuration::standard());
/// let mut decoder = DecoderImpl::new(some_reader, bincode::config::standard());
/// // this u32 can be any Decode
/// let value = u32::decode(&mut decoder).unwrap();
/// ```
Expand Down
Loading