mirror of https://git.sr.ht/~stygianentity/bincode
Config rewrite (#412)
Rewrite the config system to be slightly more friendly to adding new options
This commit is contained in:
parent
2fd2a8d8e2
commit
684f2562b1
185
src/config.rs
185
src/config.rs
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue