Config rewrite (#412)

Rewrite the config system to be slightly more friendly to adding new options
This commit is contained in:
Lena Hellström 2021-10-17 21:07:31 +02:00 committed by GitHub
parent 2fd2a8d8e2
commit 684f2562b1
10 changed files with 116 additions and 111 deletions

View File

@ -2,11 +2,11 @@
//!
//! *Important* make sure you use the same config for encoding and decoding, or else bincode will not work properly.
//!
//! To use a config, first create a type of [struct@Default]. This type will implement trait [Config] for further configuration.
//! To use a config, first create a type of [Configuration]. This type will implement trait [Config] for use with bincode.
//!
//! ```
//! use bincode::config::{Config, Default};
//! let config = Default
//! use bincode::config::{Config, Configuration};
//! let config = Configuration::standard()
//! // pick one of:
//! .with_big_endian()
//! .with_little_endian()
@ -23,7 +23,8 @@
pub(crate) use self::internal::*;
use core::marker::PhantomData;
/// The config trait that is implemented by all types returned by this function, as well as [struct@Default].
/// The Configuration struct is used to build bincode configurations. The [Config] trait is implemented
/// by this struct when a valid configuration has been constructed.
///
/// The following methods are mutually exclusive and will overwrite each other. The last call to one of these methods determines the behavior of the configuration:
///
@ -38,15 +39,48 @@ use core::marker::PhantomData;
/// [with_variable_int_encoding]: #method.with_variable_int_encoding
/// [skip_fixed_array_length]: #method.skip_fixed_array_length
/// [write_fixed_array_length]: #method.write_fixed_array_length
pub trait Config: InternalConfig {
#[derive(Copy, Clone)]
pub struct Configuration<E = LittleEndian, I = Varint, A = SkipFixedArrayLength> {
_e: PhantomData<E>,
_i: PhantomData<I>,
_a: PhantomData<A>,
}
impl Configuration {
/// The default config. By default this will be:
/// - Little endian
/// - Variable int encoding
/// - Skip fixed array length
pub fn standard() -> Self {
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 fn legacy() -> Configuration<LittleEndian, Fixint, WriteFixedArrayLength> {
Self::generate()
}
}
impl<E, I, A> Configuration<E, I, A> {
fn generate<_E, _I, _A>() -> Configuration<_E, _I, _A> {
Configuration {
_e: PhantomData,
_i: PhantomData,
_a: PhantomData,
}
}
/// Makes bincode encode all integer types in big endian.
fn with_big_endian(self) -> BigEndian<Self> {
BigEndian { _pd: PhantomData }
pub fn with_big_endian(self) -> Configuration<BigEndian, I, A> {
Self::generate()
}
/// Makes bincode encode all integer types in little endian.
fn with_little_endian(self) -> LittleEndian<Self> {
LittleEndian { _pd: PhantomData }
pub fn with_little_endian(self) -> Configuration<LittleEndian, I, A> {
Self::generate()
}
/// Makes bincode encode all integer types with a variable integer encoding.
@ -91,8 +125,8 @@ pub trait Config: InternalConfig {
///
/// 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.
fn with_variable_int_encoding(self) -> Varint<Self> {
Varint { _pd: PhantomData }
pub fn with_variable_int_encoding(self) -> Configuration<E, Varint, A> {
Self::generate()
}
/// Fixed-size integer encoding.
@ -100,129 +134,89 @@ pub trait Config: InternalConfig {
/// * Fixed size integers are encoded directly
/// * Enum discriminants are encoded as u32
/// * Lengths and usize are encoded as u64
fn with_fixed_int_encoding(self) -> Fixint<Self> {
Fixint { _pd: PhantomData }
pub fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, A> {
Self::generate()
}
/// Skip writing the length of fixed size arrays (`[u8; N]`) before writing the array
fn skip_fixed_array_length(self) -> SkipFixedArrayLength<Self> {
SkipFixedArrayLength { _pd: PhantomData }
pub fn skip_fixed_array_length(self) -> Configuration<E, I, SkipFixedArrayLength> {
Self::generate()
}
/// Write the length of fixed size arrays (`[u8; N]`) before writing the array
fn write_fixed_array_length(self) -> WriteFixedArrayLength<Self> {
WriteFixedArrayLength { _pd: PhantomData }
pub fn write_fixed_array_length(self) -> Configuration<E, I, WriteFixedArrayLength> {
Self::generate()
}
}
impl<T: InternalConfig> Config for T {}
/// Indicates a type is valid for controlling the bincode configuration
pub trait Config:
InternalEndianConfig + InternalArrayLengthConfig + InternalIntEncodingConfig + Copy + Clone
{
}
/// The default config. By default this will be:
/// - Little endian
/// - Variable int encoding
/// - Skip fixed array length
#[derive(Copy, Clone)]
pub struct Default;
impl InternalConfig for Default {
const ENDIAN: Endian = Endian::Little;
const INT_ENCODING: IntEncoding = IntEncoding::Variable;
const LIMIT: Option<u64> = None;
const ALLOW_TRAILING: bool = true;
const SKIP_FIXED_ARRAY_LENGTH: bool = true;
impl<T> Config for T where
T: InternalEndianConfig + InternalArrayLengthConfig + InternalIntEncodingConfig + Copy + Clone
{
}
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct BigEndian<C: Config> {
_pd: PhantomData<C>,
}
pub struct BigEndian {}
impl<C: InternalConfig> InternalConfig for BigEndian<C> {
impl InternalEndianConfig for BigEndian {
const ENDIAN: Endian = Endian::Big;
const INT_ENCODING: IntEncoding = C::INT_ENCODING;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH;
}
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct LittleEndian<C: Config> {
_pd: PhantomData<C>,
}
pub struct LittleEndian {}
impl<C: InternalConfig> InternalConfig for LittleEndian<C> {
impl InternalEndianConfig for LittleEndian {
const ENDIAN: Endian = Endian::Little;
const INT_ENCODING: IntEncoding = C::INT_ENCODING;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH;
}
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct Fixint<C: Config> {
_pd: PhantomData<C>,
}
pub struct Fixint {}
impl<C: InternalConfig> InternalConfig for Fixint<C> {
const ENDIAN: Endian = C::ENDIAN;
impl InternalIntEncodingConfig for Fixint {
const INT_ENCODING: IntEncoding = IntEncoding::Fixed;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH;
}
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct Varint<C: Config> {
_pd: PhantomData<C>,
}
pub struct Varint {}
impl<C: InternalConfig> InternalConfig for Varint<C> {
const ENDIAN: Endian = C::ENDIAN;
impl InternalIntEncodingConfig for Varint {
const INT_ENCODING: IntEncoding = IntEncoding::Variable;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH;
}
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct SkipFixedArrayLength<C: Config> {
_pd: PhantomData<C>,
}
pub struct SkipFixedArrayLength {}
impl<C: InternalConfig> InternalConfig for SkipFixedArrayLength<C> {
const ENDIAN: Endian = C::ENDIAN;
const INT_ENCODING: IntEncoding = C::INT_ENCODING;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
impl InternalArrayLengthConfig for SkipFixedArrayLength {
const SKIP_FIXED_ARRAY_LENGTH: bool = true;
}
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct WriteFixedArrayLength<C: Config> {
_pd: PhantomData<C>,
}
pub struct WriteFixedArrayLength {}
impl<C: InternalConfig> InternalConfig for WriteFixedArrayLength<C> {
const ENDIAN: Endian = C::ENDIAN;
const INT_ENCODING: IntEncoding = C::INT_ENCODING;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
impl InternalArrayLengthConfig for WriteFixedArrayLength {
const SKIP_FIXED_ARRAY_LENGTH: bool = false;
}
mod internal {
pub trait InternalConfig: Copy + Clone {
use super::Configuration;
pub trait InternalEndianConfig {
const ENDIAN: Endian;
const INT_ENCODING: IntEncoding;
const LIMIT: Option<u64>;
const ALLOW_TRAILING: bool;
const SKIP_FIXED_ARRAY_LENGTH: bool;
}
impl<E: InternalEndianConfig, I, A> InternalEndianConfig for Configuration<E, I, A> {
const ENDIAN: Endian = E::ENDIAN;
}
#[derive(PartialEq, Eq)]
@ -231,20 +225,25 @@ mod internal {
Big,
}
pub trait InternalIntEncodingConfig {
const INT_ENCODING: IntEncoding;
}
impl<E, I: InternalIntEncodingConfig, A> InternalIntEncodingConfig for Configuration<E, I, A> {
const INT_ENCODING: IntEncoding = I::INT_ENCODING;
}
#[derive(PartialEq, Eq)]
pub enum IntEncoding {
Fixed,
Variable,
}
impl<'a, C: InternalConfig> InternalConfig for &'a mut C
where
&'a mut C: Copy + Clone,
{
const ENDIAN: Endian = C::ENDIAN;
const INT_ENCODING: IntEncoding = C::INT_ENCODING;
const LIMIT: Option<u64> = C::LIMIT;
const ALLOW_TRAILING: bool = C::ALLOW_TRAILING;
const SKIP_FIXED_ARRAY_LENGTH: bool = C::SKIP_FIXED_ARRAY_LENGTH;
pub trait InternalArrayLengthConfig {
const SKIP_FIXED_ARRAY_LENGTH: bool;
}
impl<E, I, A: InternalArrayLengthConfig> InternalArrayLengthConfig for Configuration<E, I, A> {
const SKIP_FIXED_ARRAY_LENGTH: bool = A::SKIP_FIXED_ARRAY_LENGTH;
}
}

View File

@ -18,7 +18,7 @@ use crate::config::Config;
/// # 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::Default);
/// let mut decoder = DecoderImpl::new(some_reader, config::Configuration::standard());
/// // this u32 can be any Decode
/// let value = u32::decode(&mut decoder).unwrap();
/// ```

View File

@ -3,7 +3,10 @@ use super::{
BorrowDecode, BorrowDecoder, Decode, Decoder,
};
use crate::{
config::{Endian, IntEncoding, InternalConfig},
config::{
Endian, IntEncoding, InternalArrayLengthConfig, InternalEndianConfig,
InternalIntEncodingConfig,
},
error::{DecodeError, IntegerType},
};
use core::{

View File

@ -14,7 +14,7 @@ use crate::config::Config;
/// ```
/// # use bincode::enc::{write::SliceWriter, EncoderImpl, Encode};
/// # use bincode::config::{self, Config};
/// # let config = config::Default.with_fixed_int_encoding().with_big_endian();
/// # let config = config::Configuration::standard().with_fixed_int_encoding().with_big_endian();
/// let slice: &mut [u8] = &mut [0, 0, 0, 0];
/// let mut encoder = EncoderImpl::new(SliceWriter::new(slice), config);
/// // this u32 can be any Encodable

View File

@ -1,6 +1,9 @@
use super::{write::Writer, Encode, Encoder};
use crate::{
config::{Endian, IntEncoding, InternalConfig},
config::{
Endian, IntEncoding, InternalArrayLengthConfig, InternalEndianConfig,
InternalIntEncodingConfig,
},
error::EncodeError,
};
use core::{

View File

@ -24,7 +24,7 @@ impl enc::write::Writer for VecWriter {
/// Encode the given value into a `Vec<u8>`.
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn encode_to_vec<E: enc::Encode>(val: E) -> Result<Vec<u8>, EncodeError> {
encode_to_vec_with_config(val, config::Default)
encode_to_vec_with_config(val, config::Configuration::standard())
}
/// Encode the given value into a `Vec<u8>` with the given `Config`. See the [config] module for more information.

View File

@ -16,7 +16,7 @@ use std::{
/// Decode type `D` from the given reader. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`.
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn decode_from<D: Decode, R: std::io::Read>(src: &mut R) -> Result<D, DecodeError> {
decode_from_with_config(src, config::Default)
decode_from_with_config(src, config::Configuration::standard())
}
/// Decode type `D` from the given reader with the given `Config`. The reader can be any type that implements `std::io::Read`, e.g. `std::fs::File`.
@ -47,7 +47,7 @@ pub fn encode_into_write<E: Encode, W: std::io::Write>(
val: E,
dst: &mut W,
) -> Result<usize, EncodeError> {
encode_into_write_with_config(val, dst, config::Default)
encode_into_write_with_config(val, dst, config::Configuration::standard())
}
/// Encode the given value into any type that implements `std::io::Write`, e.g. `std::fs::File`, with the given `Config`. See the [config] module for more information.

View File

@ -52,7 +52,7 @@ pub fn encode_into_slice<E: enc::Encode>(
val: E,
dst: &mut [u8],
) -> Result<usize, error::EncodeError> {
encode_into_slice_with_config(val, dst, config::Default)
encode_into_slice_with_config(val, dst, config::Configuration::standard())
}
/// Encode the given value into the given slice. Returns the amount of bytes that have been written.
@ -77,7 +77,7 @@ pub fn encode_into_slice_with_config<E: enc::Encode, C: Config>(
pub fn decode<'__de, D: de::BorrowDecode<'__de>>(
src: &'__de [u8],
) -> Result<D, error::DecodeError> {
decode_with_config(src, config::Default)
decode_with_config(src, config::Configuration::standard())
}
/// Attempt to decode a given type `D` from the given slice.

View File

@ -91,7 +91,7 @@ fn test_std_commons() {
});
// Borrowed values
let config = bincode::config::Default;
let config = bincode::config::Configuration::standard();
let mut buffer = [0u8; 1024];
// &CStr

View File

@ -34,7 +34,7 @@ where
// A matrix of each different config option possible
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_little_endian()
.with_fixed_int_encoding()
.skip_fixed_array_length(),
@ -42,7 +42,7 @@ where
);
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_big_endian()
.with_fixed_int_encoding()
.skip_fixed_array_length(),
@ -50,7 +50,7 @@ where
);
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_little_endian()
.with_variable_int_encoding()
.skip_fixed_array_length(),
@ -58,7 +58,7 @@ where
);
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_big_endian()
.with_variable_int_encoding()
.skip_fixed_array_length(),
@ -66,7 +66,7 @@ where
);
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_little_endian()
.with_fixed_int_encoding()
.write_fixed_array_length(),
@ -74,7 +74,7 @@ where
);
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_big_endian()
.with_fixed_int_encoding()
.write_fixed_array_length(),
@ -82,7 +82,7 @@ where
);
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_little_endian()
.with_variable_int_encoding()
.write_fixed_array_length(),
@ -90,7 +90,7 @@ where
);
the_same_with_config(
&element,
config::Default
config::Configuration::standard()
.with_big_endian()
.with_variable_int_encoding()
.write_fixed_array_length(),