#[doc(hidden)]
pub use self::internal::*;
use core::marker::PhantomData;
#[derive(Copy, Clone, Debug)]
pub struct Configuration<
E = LittleEndian,
I = Varint,
L = NoLimit,
B = SkipBitPacking,
O = LsbFirst,
F = FingerprintDisabled,
FO = BincodeFormat,
> {
_e: PhantomData<E>,
_i: PhantomData<I>,
_l: PhantomData<L>,
_b: PhantomData<B>,
_o: PhantomData<O>,
_f: PhantomData<F>,
_fo: PhantomData<FO>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum CborDeterministicMode {
None = 0,
Core = 1,
LengthFirst = 2,
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CborOptions {
pub deterministic_mode: CborDeterministicMode,
pub preferred_float: bool,
pub canonical_nan: bool,
pub normalize_neg_zero: bool,
pub allow_indefinite: bool,
pub strict_tags: bool,
}
impl CborOptions {
pub const DEFAULT: Self = Self {
deterministic_mode: CborDeterministicMode::None,
preferred_float: true,
canonical_nan: true,
normalize_neg_zero: false,
allow_indefinite: true,
strict_tags: false,
};
pub const DETERMINISTIC: Self = Self {
deterministic_mode: CborDeterministicMode::Core,
preferred_float: true,
canonical_nan: true,
normalize_neg_zero: false, allow_indefinite: false,
strict_tags: true,
};
}
#[must_use]
pub const fn standard() -> Configuration {
generate()
}
#[must_use]
pub const fn legacy() -> Configuration<
LittleEndian,
Fixint,
NoLimit,
SkipBitPacking,
LsbFirst,
FingerprintDisabled,
BincodeFormat,
> {
generate()
}
impl<E, I, L, B, O, F, FO> Default for Configuration<E, I, L, B, O, F, FO> {
fn default() -> Self {
generate()
}
}
const fn generate<E, I, L, B, O, F, FO>() -> Configuration<E, I, L, B, O, F, FO> {
Configuration {
_e: PhantomData,
_i: PhantomData,
_l: PhantomData,
_b: PhantomData,
_o: PhantomData,
_f: PhantomData,
_fo: PhantomData,
}
}
impl<E, I, L, B, O, F, FO> Configuration<E, I, L, B, O, F, FO> {
#[must_use]
pub const fn with_big_endian(self) -> Configuration<BigEndian, I, L, B, MsbFirst, F, FO> {
generate()
}
#[must_use]
pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, L, B, LsbFirst, F, FO> {
generate()
}
#[must_use]
pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, L, B, O, F, FO> {
generate()
}
#[must_use]
pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, L, B, O, F, FO> {
generate()
}
#[must_use]
pub const fn with_limit<const N: usize>(self) -> Configuration<E, I, Limit<N>, B, O, F, FO> {
generate()
}
#[must_use]
pub const fn with_no_limit(self) -> Configuration<E, I, NoLimit, B, O, F, FO> {
generate()
}
#[must_use]
pub const fn with_bit_packing(self) -> Configuration<E, I, L, AllowBitPacking, O, F, FO> {
generate()
}
#[must_use]
pub const fn with_no_bit_packing(self) -> Configuration<E, I, L, SkipBitPacking, O, F, FO> {
generate()
}
#[must_use]
pub const fn with_fingerprint(self) -> Configuration<E, I, L, B, O, FingerprintEnabled<0>, FO> {
generate()
}
#[must_use]
pub const fn with_fingerprint_and_seed<const SEED: u64>(
self
) -> Configuration<E, I, L, B, O, FingerprintEnabled<SEED>, FO> {
generate()
}
#[must_use]
pub const fn with_legacy_fingerprint<const EXPECTED: u64>(
self
) -> Configuration<E, I, L, B, O, FingerprintLegacy<EXPECTED>, FO> {
generate()
}
#[must_use]
pub const fn with_cbor_format(self) -> Configuration<E, I, L, B, O, F, CborFormat> {
generate()
}
#[must_use]
pub const fn with_deterministic_cbor(
self
) -> Configuration<E, I, L, B, O, F, CborDeterministicFormat> {
generate()
}
#[must_use]
pub const fn with_deterministic_bincode(
self
) -> Configuration<E, I, L, B, O, F, BincodeDeterministicFormat> {
generate()
}
#[must_use]
pub const fn with_cbor_options<
const DET: u8,
const PREF: bool,
const NAN: bool,
const NZ: bool,
const INDEF: bool,
const TAGS: bool,
>(
self
) -> Configuration<E, I, L, B, O, F, CborConfig<DET, PREF, NAN, NZ, INDEF, TAGS>> {
generate()
}
}
pub trait Config:
InternalEndianConfig
+ InternalIntEncodingConfig
+ InternalLimitConfig
+ InternalBitPackingConfig
+ InternalBitOrderingConfig
+ InternalFingerprintConfig
+ InternalFormatConfig
+ InternalConfigFingerprint
+ InternalFingerprintConfigExt
+ Copy
+ Clone
{
fn endianness(&self) -> Endianness;
fn int_encoding(&self) -> IntEncoding;
fn limit(&self) -> Option<usize>;
fn bit_packing_enabled(&self) -> bool;
fn bit_ordering(&self) -> BitOrdering;
fn fingerprint_mode(&self) -> FingerprintMode;
fn format(&self) -> Format;
fn cbor_options(&self) -> CborOptions;
}
impl<T> Config for T
where
T: InternalEndianConfig
+ InternalIntEncodingConfig
+ InternalLimitConfig
+ InternalBitPackingConfig
+ InternalBitOrderingConfig
+ InternalFingerprintConfig
+ InternalFormatConfig
+ InternalConfigFingerprint
+ InternalFingerprintConfigExt
+ Copy
+ Clone,
{
fn endianness(&self) -> Endianness {
<T as InternalEndianConfig>::ENDIAN
}
fn int_encoding(&self) -> IntEncoding {
<T as InternalIntEncodingConfig>::INT_ENCODING
}
fn limit(&self) -> Option<usize> {
<T as InternalLimitConfig>::LIMIT
}
fn bit_packing_enabled(&self) -> bool {
matches!(
<T as InternalBitPackingConfig>::BIT_PACKING,
BitPacking::Enabled
)
}
fn bit_ordering(&self) -> BitOrdering {
<T as InternalBitOrderingConfig>::BIT_ORDERING
}
fn fingerprint_mode(&self) -> FingerprintMode {
<T as InternalFingerprintConfig>::FINGERPRINT_MODE
}
fn format(&self) -> Format {
<T as InternalFormatConfig>::FORMAT
}
fn cbor_options(&self) -> CborOptions {
<T as InternalFormatConfig>::CBOR_OPTIONS
}
}
#[derive(Copy, Clone, Debug)]
pub struct BigEndian;
impl InternalEndianConfig for BigEndian {
const ENDIAN: Endianness = Endianness::Big;
}
#[derive(Copy, Clone, Debug)]
pub struct LittleEndian;
impl InternalEndianConfig for LittleEndian {
const ENDIAN: Endianness = Endianness::Little;
}
#[derive(Copy, Clone, Debug)]
pub struct Fixint;
impl InternalIntEncodingConfig for Fixint {
const INT_ENCODING: IntEncoding = IntEncoding::Fixed;
}
#[derive(Copy, Clone, Debug)]
pub struct Varint;
impl InternalIntEncodingConfig for Varint {
const INT_ENCODING: IntEncoding = IntEncoding::Variable;
}
#[derive(Copy, Clone, Debug)]
pub struct NoLimit;
impl InternalLimitConfig for NoLimit {
const LIMIT: Option<usize> = None;
}
#[derive(Copy, Clone, Debug)]
pub struct Limit<const N: usize>;
impl<const N: usize> InternalLimitConfig for Limit<N> {
const LIMIT: Option<usize> = Some(N);
}
#[derive(Copy, Clone, Debug)]
pub struct AllowBitPacking;
impl InternalBitPackingConfig for AllowBitPacking {
const BIT_PACKING: BitPacking = BitPacking::Enabled;
}
#[derive(Copy, Clone, Debug)]
pub struct SkipBitPacking;
impl InternalBitPackingConfig for SkipBitPacking {
const BIT_PACKING: BitPacking = BitPacking::Disabled;
}
#[derive(Copy, Clone, Debug)]
pub struct MsbFirst;
impl InternalBitOrderingConfig for MsbFirst {
const BIT_ORDERING: BitOrdering = BitOrdering::Msb;
}
#[derive(Copy, Clone, Debug)]
pub struct LsbFirst;
impl InternalBitOrderingConfig for LsbFirst {
const BIT_ORDERING: BitOrdering = BitOrdering::Lsb;
}
#[derive(Copy, Clone, Debug)]
pub struct FingerprintDisabled;
impl InternalFingerprintConfig for FingerprintDisabled {
const FINGERPRINT_MODE: FingerprintMode = FingerprintMode::Disabled;
}
#[derive(Copy, Clone, Debug)]
pub struct FingerprintEnabled<const SEED: u64>;
impl<const SEED: u64> InternalFingerprintConfig for FingerprintEnabled<SEED> {
const FINGERPRINT_MODE: FingerprintMode = FingerprintMode::Enabled { seed: SEED };
}
#[derive(Copy, Clone, Debug)]
pub struct FingerprintLegacy<const EXPECTED: u64>;
impl<const EXPECTED: u64> InternalFingerprintConfig for FingerprintLegacy<EXPECTED> {
const FINGERPRINT_MODE: FingerprintMode = FingerprintMode::Legacy { expected: EXPECTED };
}
#[derive(Copy, Clone, Debug)]
pub struct BincodeFormat;
impl InternalFormatConfig for BincodeFormat {
const CBOR_OPTIONS: CborOptions = CborOptions::DEFAULT;
const FORMAT: Format = Format::Bincode;
}
#[derive(Copy, Clone, Debug)]
pub struct BincodeDeterministicFormat;
impl InternalFormatConfig for BincodeDeterministicFormat {
const CBOR_OPTIONS: CborOptions = CborOptions::DEFAULT;
const FORMAT: Format = Format::BincodeDeterministic;
}
#[derive(Copy, Clone, Debug)]
pub struct CborConfig<
const DET: u8,
const PREF: bool,
const NAN: bool,
const NZ: bool,
const INDEF: bool,
const TAGS: bool,
>;
impl<
const DET: u8,
const PREF: bool,
const NAN: bool,
const NZ: bool,
const INDEF: bool,
const TAGS: bool,
> InternalFormatConfig for CborConfig<DET, PREF, NAN, NZ, INDEF, TAGS>
{
const CBOR_OPTIONS: CborOptions = CborOptions {
deterministic_mode: match DET {
| 1 => CborDeterministicMode::Core,
| 2 => CborDeterministicMode::LengthFirst,
| _ => CborDeterministicMode::None,
},
preferred_float: PREF,
canonical_nan: NAN,
normalize_neg_zero: NZ,
allow_indefinite: INDEF,
strict_tags: TAGS,
};
const FORMAT: Format = if DET == 0 {
Format::Cbor
} else {
Format::CborDeterministic
};
}
pub type CborFormat = CborConfig<0, true, true, false, true, false>;
pub type CborDeterministicFormat = CborConfig<1, true, true, false, false, true>;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Endianness {
Little,
Big,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum IntEncoding {
Fixed,
Variable,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum BitPacking {
Enabled,
Disabled,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum BitOrdering {
Lsb,
Msb,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum FingerprintMode {
Disabled,
Enabled {
seed: u64,
},
Legacy {
expected: u64,
},
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Format {
Bincode,
BincodeDeterministic,
Cbor,
CborDeterministic,
}
#[doc(hidden)]
pub mod internal {
use super::BitOrdering;
use super::BitPacking;
use super::Configuration;
use super::Endianness;
use super::FingerprintMode;
use super::IntEncoding;
pub trait InternalEndianConfig {
const ENDIAN: Endianness;
}
impl<E: InternalEndianConfig, I, L, B, O, F, FO> InternalEndianConfig
for Configuration<E, I, L, B, O, F, FO>
{
const ENDIAN: Endianness = E::ENDIAN;
}
pub trait InternalIntEncodingConfig {
const INT_ENCODING: IntEncoding;
}
impl<E, I: InternalIntEncodingConfig, L, B, O, F, FO> InternalIntEncodingConfig
for Configuration<E, I, L, B, O, F, FO>
{
const INT_ENCODING: IntEncoding = I::INT_ENCODING;
}
pub trait InternalLimitConfig {
const LIMIT: Option<usize>;
}
impl<E, I, L: InternalLimitConfig, B, O, F, FO> InternalLimitConfig
for Configuration<E, I, L, B, O, F, FO>
{
const LIMIT: Option<usize> = L::LIMIT;
}
pub trait InternalBitPackingConfig {
const BIT_PACKING: BitPacking;
}
impl<E, I, L, B: InternalBitPackingConfig, O, F, FO> InternalBitPackingConfig
for Configuration<E, I, L, B, O, F, FO>
{
const BIT_PACKING: BitPacking = B::BIT_PACKING;
}
pub trait InternalBitOrderingConfig {
const BIT_ORDERING: BitOrdering;
}
impl<E, I, L, B, O: InternalBitOrderingConfig, F, FO> InternalBitOrderingConfig
for Configuration<E, I, L, B, O, F, FO>
{
const BIT_ORDERING: BitOrdering = O::BIT_ORDERING;
}
pub trait InternalFingerprintConfig {
const FINGERPRINT_MODE: FingerprintMode;
}
impl<E, I, L, B, O, F: InternalFingerprintConfig, FO> InternalFingerprintConfig
for Configuration<E, I, L, B, O, F, FO>
{
const FINGERPRINT_MODE: FingerprintMode = F::FINGERPRINT_MODE;
}
pub trait InternalFingerprintConfigExt {
type Mode;
}
impl<E, I, L, B, O, F, FO> InternalFingerprintConfigExt for Configuration<E, I, L, B, O, F, FO> {
type Mode = F;
}
pub trait InternalFingerprintGuard<D, C: super::Config> {
fn decode_check<R: crate::de::read::Reader>(
_config: &C,
reader: &mut R,
) -> core::result::Result<(), crate::error::DecodeError>;
fn encode_check<W: crate::enc::write::Writer>(
_config: &C,
writer: &mut W,
) -> core::result::Result<(), crate::error::EncodeError>;
}
impl<D, C: super::Config> InternalFingerprintGuard<D, C> for super::FingerprintDisabled {
#[inline(always)]
fn decode_check<R: crate::de::read::Reader>(
_config: &C,
_reader: &mut R,
) -> core::result::Result<(), crate::error::DecodeError> {
core::result::Result::Ok(())
}
#[inline(always)]
fn encode_check<W: crate::enc::write::Writer>(
_config: &C,
_writer: &mut W,
) -> core::result::Result<(), crate::error::EncodeError> {
core::result::Result::Ok(())
}
}
impl<D: crate::fingerprint::Fingerprint<C>, C: super::Config, const SEED: u64>
InternalFingerprintGuard<D, C> for super::FingerprintEnabled<SEED>
{
#[inline]
fn decode_check<R: crate::de::read::Reader>(
_config: &C,
reader: &mut R,
) -> core::result::Result<(), crate::error::DecodeError> {
let mut bytes = [0u8; 8];
reader.read(&mut bytes)?;
let actual = u64::from_le_bytes(bytes);
if actual != D::SCHEMA_HASH {
return crate::error::cold_decode_error_schema_mismatch(D::SCHEMA_HASH, actual);
}
core::result::Result::Ok(())
}
#[inline]
fn encode_check<W: crate::enc::write::Writer>(
_config: &C,
writer: &mut W,
) -> core::result::Result<(), crate::error::EncodeError> {
writer.write(&D::SCHEMA_HASH.to_le_bytes())
}
}
impl<D, C: super::Config, const EXPECTED: u64> InternalFingerprintGuard<D, C>
for super::FingerprintLegacy<EXPECTED>
{
#[inline]
fn decode_check<R: crate::de::read::Reader>(
_config: &C,
reader: &mut R,
) -> core::result::Result<(), crate::error::DecodeError> {
let mut bytes = [0u8; 8];
reader.read(&mut bytes)?;
let actual = u64::from_le_bytes(bytes);
if actual != EXPECTED {
return crate::error::cold_decode_error_schema_mismatch(EXPECTED, actual);
}
core::result::Result::Ok(())
}
#[inline]
fn encode_check<W: crate::enc::write::Writer>(
_config: &C,
_writer: &mut W,
) -> core::result::Result<(), crate::error::EncodeError> {
core::result::Result::Ok(())
}
}
pub trait InternalConfigFingerprint {
const CONFIG_HASH: u64;
}
impl<E, I, L, B, O, F, FO> InternalConfigFingerprint for Configuration<E, I, L, B, O, F, FO>
where
E: InternalEndianConfig,
I: InternalIntEncodingConfig,
L: InternalLimitConfig,
B: InternalBitPackingConfig,
O: InternalBitOrderingConfig,
{
const CONFIG_HASH: u64 = rapidhash::v3::rapidhash_v3_seeded(
&[
crate::BINCODE_MAJOR_VERSION as u8,
E::ENDIAN as u8,
I::INT_ENCODING as u8,
match L::LIMIT {
| None => 0,
| Some(_) => 1,
},
B::BIT_PACKING as u8,
O::BIT_ORDERING as u8,
],
&rapidhash::v3::RapidSecrets::seed_cpp(0),
);
}
pub trait InternalFormatConfig {
const FORMAT: super::Format;
const CBOR_OPTIONS: super::CborOptions;
}
impl<E, I, L, B, O, F, FO: InternalFormatConfig> InternalFormatConfig
for Configuration<E, I, L, B, O, F, FO>
{
const CBOR_OPTIONS: super::CborOptions = FO::CBOR_OPTIONS;
const FORMAT: super::Format = FO::FORMAT;
}
}