#[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,
F = FingerprintDisabled,
> {
_e: PhantomData<E>,
_i: PhantomData<I>,
_l: PhantomData<L>,
_b: PhantomData<B>,
_f: PhantomData<F>,
}
#[must_use]
pub const fn standard() -> Configuration {
generate()
}
#[must_use]
pub const fn legacy()
-> Configuration<LittleEndian, Fixint, NoLimit, SkipBitPacking, FingerprintDisabled> {
generate()
}
impl<E, I, L, B, F> Default for Configuration<E, I, L, B, F> {
fn default() -> Self {
generate()
}
}
const fn generate<E, I, L, B, F>() -> Configuration<E, I, L, B, F> {
Configuration {
_e: PhantomData,
_i: PhantomData,
_l: PhantomData,
_b: PhantomData,
_f: PhantomData,
}
}
impl<E, I, L, B, F> Configuration<E, I, L, B, F> {
#[must_use]
pub const fn with_big_endian(self) -> Configuration<BigEndian, I, L, B, F> {
generate()
}
#[must_use]
pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, L, B, F> {
generate()
}
#[must_use]
pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, L, B, F> {
generate()
}
#[must_use]
pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, L, B, F> {
generate()
}
#[must_use]
pub const fn with_limit<const N: usize>(self) -> Configuration<E, I, Limit<N>, B, F> {
generate()
}
#[must_use]
pub const fn with_no_limit(self) -> Configuration<E, I, NoLimit, B, F> {
generate()
}
#[must_use]
pub const fn with_bit_packing(self) -> Configuration<E, I, L, AllowBitPacking, F> {
generate()
}
#[must_use]
pub const fn with_no_bit_packing(self) -> Configuration<E, I, L, SkipBitPacking, F> {
generate()
}
#[must_use]
pub const fn with_fingerprint(self) -> Configuration<E, I, L, B, FingerprintEnabled<0>> {
generate()
}
#[must_use]
pub const fn with_fingerprint_and_seed<const SEED: u64>(
self
) -> Configuration<E, I, L, B, FingerprintEnabled<SEED>> {
generate()
}
#[must_use]
pub const fn with_legacy_fingerprint<const EXPECTED: u64>(
self
) -> Configuration<E, I, L, B, FingerprintLegacy<EXPECTED>> {
generate()
}
}
pub trait Config:
InternalEndianConfig
+ InternalIntEncodingConfig
+ InternalLimitConfig
+ InternalBitPackingConfig
+ InternalFingerprintConfig
+ 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 fingerprint_mode(&self) -> FingerprintMode;
}
impl<T> Config for T
where
T: InternalEndianConfig
+ InternalIntEncodingConfig
+ InternalLimitConfig
+ InternalBitPackingConfig
+ InternalFingerprintConfig
+ 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 fingerprint_mode(&self) -> FingerprintMode {
<T as InternalFingerprintConfig>::FINGERPRINT_MODE
}
}
#[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 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, 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 FingerprintMode {
Disabled,
Enabled {
seed: u64,
},
Legacy {
expected: u64,
},
}
#[doc(hidden)]
pub mod internal {
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, F> InternalEndianConfig for Configuration<E, I, L, B, F> {
const ENDIAN: Endianness = E::ENDIAN;
}
pub trait InternalIntEncodingConfig {
const INT_ENCODING: IntEncoding;
}
impl<E, I: InternalIntEncodingConfig, L, B, F> InternalIntEncodingConfig
for Configuration<E, I, L, B, F>
{
const INT_ENCODING: IntEncoding = I::INT_ENCODING;
}
pub trait InternalLimitConfig {
const LIMIT: Option<usize>;
}
impl<E, I, L: InternalLimitConfig, B, F> InternalLimitConfig for Configuration<E, I, L, B, F> {
const LIMIT: Option<usize> = L::LIMIT;
}
pub trait InternalBitPackingConfig {
const BIT_PACKING: BitPacking;
}
impl<E, I, L, B: InternalBitPackingConfig, F> InternalBitPackingConfig
for Configuration<E, I, L, B, F>
{
const BIT_PACKING: BitPacking = B::BIT_PACKING;
}
pub trait InternalFingerprintConfig {
const FINGERPRINT_MODE: FingerprintMode;
}
impl<E, I, L, B, F: InternalFingerprintConfig> InternalFingerprintConfig
for Configuration<E, I, L, B, F>
{
const FINGERPRINT_MODE: FingerprintMode = F::FINGERPRINT_MODE;
}
pub trait InternalFingerprintConfigExt {
type Mode;
}
impl<E, I, L, B, F> InternalFingerprintConfigExt for Configuration<E, I, L, B, F> {
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, F> InternalConfigFingerprint for Configuration<E, I, L, B, F>
where
E: InternalEndianConfig,
I: InternalIntEncodingConfig,
L: InternalLimitConfig,
B: InternalBitPackingConfig,
{
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,
],
&rapidhash::v3::RapidSecrets::seed_cpp(0),
);
}
}