use crate::bitlen;
use core::fmt;
#[cfg(feature = "hybrid-array")]
use {
crate::Integer,
core::ops::Add,
hybrid_array::{Array, ArraySize, typenum::Unsigned},
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ByteOrder {
BigEndian,
LittleEndian,
}
#[cfg(feature = "hybrid-array")]
pub type ByteArray<T> = Array<u8, <T as ArrayEncoding>::ByteSize>;
#[cfg(feature = "hybrid-array")]
pub trait ArrayEncoding: Encoding {
type ByteSize: ArraySize + Add + Eq + Ord + Unsigned;
fn from_be_byte_array(bytes: ByteArray<Self>) -> Self;
fn from_le_byte_array(bytes: ByteArray<Self>) -> Self;
#[inline]
fn from_byte_array(bytes: ByteArray<Self>, byte_order: ByteOrder) -> Self {
match byte_order {
ByteOrder::BigEndian => Self::from_be_byte_array(bytes),
ByteOrder::LittleEndian => Self::from_le_byte_array(bytes),
}
}
fn to_be_byte_array(&self) -> ByteArray<Self>;
fn to_le_byte_array(&self) -> ByteArray<Self>;
#[inline]
fn to_byte_array(&self, byte_order: ByteOrder) -> ByteArray<Self> {
match byte_order {
ByteOrder::BigEndian => self.to_be_byte_array(),
ByteOrder::LittleEndian => self.to_le_byte_array(),
}
}
}
#[cfg(feature = "hybrid-array")]
pub trait ArrayDecoding {
type Output: ArrayEncoding + Integer;
fn into_uint_be(self) -> Self::Output;
fn into_uint_le(self) -> Self::Output;
}
pub trait Encoding: Sized {
type Repr: AsRef<[u8]>
+ AsMut<[u8]>
+ Clone
+ Sized
+ for<'a> TryFrom<&'a [u8], Error: core::error::Error>;
#[must_use]
fn from_be_bytes(bytes: Self::Repr) -> Self;
#[must_use]
fn from_le_bytes(bytes: Self::Repr) -> Self;
#[inline]
#[must_use]
fn from_bytes(bytes: Self::Repr, byte_order: ByteOrder) -> Self {
match byte_order {
ByteOrder::BigEndian => Self::from_be_bytes(bytes),
ByteOrder::LittleEndian => Self::from_le_bytes(bytes),
}
}
#[must_use]
fn from_be_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
assert_eq!(bits_precision, bitlen::from_bytes(size_of::<Self::Repr>()));
let bytes = truncate_be(bytes, bits_precision);
Self::from_be_bytes(bytes.try_into().expect("input too short"))
}
#[must_use]
fn from_le_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
assert_eq!(bits_precision, bitlen::from_bytes(size_of::<Self::Repr>()));
let bytes = truncate_le(bytes, bits_precision);
Self::from_le_bytes(bytes.try_into().expect("input too short"))
}
#[inline]
#[must_use]
fn from_slice_truncated(bytes: &[u8], bits_precision: u32, byte_order: ByteOrder) -> Self {
match byte_order {
ByteOrder::BigEndian => Self::from_be_slice_truncated(bytes, bits_precision),
ByteOrder::LittleEndian => Self::from_le_slice_truncated(bytes, bits_precision),
}
}
#[must_use]
fn to_be_bytes(&self) -> Self::Repr;
#[must_use]
fn to_le_bytes(&self) -> Self::Repr;
#[inline]
#[must_use]
fn to_bytes(&self, byte_order: ByteOrder) -> Self::Repr {
match byte_order {
ByteOrder::BigEndian => self.to_be_bytes(),
ByteOrder::LittleEndian => self.to_le_bytes(),
}
}
}
pub trait EncodedSize {
type Target;
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DecodeError {
Empty,
InvalidDigit,
InputSize,
Precision,
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => write!(f, "empty value provided"),
Self::InvalidDigit => {
write!(f, "invalid digit character")
}
Self::InputSize => write!(f, "input size is too small to fit in the given precision"),
Self::Precision => write!(
f,
"the deserialized number is larger than the given precision"
),
}
}
}
impl core::error::Error for DecodeError {}
pub(crate) fn truncate_be(bytes: &[u8], bits_precision: u32) -> &[u8] {
let bytes_precision = bitlen::to_bytes(bits_precision);
if bytes.len() > bytes_precision {
&bytes[bytes.len().saturating_sub(bytes_precision)..]
} else {
bytes
}
}
pub(crate) fn truncate_le(bytes: &[u8], bits_precision: u32) -> &[u8] {
let bytes_precision = bitlen::to_bytes(bits_precision);
if bytes.len() > bytes_precision {
&bytes[..bytes_precision]
} else {
bytes
}
}