use core::fmt::{Debug, Display};
use core::hash::Hash;
use core::marker;
use crate::traits::Typed;
use crate::types::CONTINUATION;
use musli::error::Error;
use musli_binary_common::int::continuation as c;
use musli_binary_common::int::zigzag as zig;
use musli_binary_common::int::{ByteOrder, ByteOrderIo, NetworkEndian, Signed, Unsigned};
use musli_binary_common::reader::Reader;
use musli_binary_common::writer::Writer;
mod private {
pub trait Sealed {}
impl<B> Sealed for super::Fixed<B> {}
impl Sealed for super::Variable {}
}
pub trait IntegerEncoding:
Clone + Copy + Debug + Eq + Hash + Ord + PartialEq + PartialOrd + private::Sealed
{
fn encode_unsigned<W, T>(writer: W, value: T) -> Result<(), W::Error>
where
W: Writer,
T: ByteOrderIo + Typed;
fn decode_unsigned<'de, R, T>(reader: R) -> Result<T, R::Error>
where
R: Reader<'de>,
T: ByteOrderIo + Typed;
fn encode_signed<W, T>(writer: W, value: T) -> Result<(), W::Error>
where
W: Writer,
T: Signed,
T::Unsigned: ByteOrderIo + Typed;
fn decode_signed<'de, R, T>(reader: R) -> Result<T, R::Error>
where
R: Reader<'de>,
T: Signed,
T::Unsigned: ByteOrderIo<Signed = T> + Typed;
}
pub trait UsizeEncoding {
fn encode_usize<W>(writer: W, value: usize) -> Result<(), W::Error>
where
W: Writer;
fn encode_typed_usize<W>(writer: W, value: usize) -> Result<(), W::Error>
where
W: Writer;
fn decode_usize<'de, R>(reader: R) -> Result<usize, R::Error>
where
R: Reader<'de>;
fn decode_typed_usize<'de, R>(reader: R) -> Result<usize, R::Error>
where
R: Reader<'de>;
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum Variable {}
impl IntegerEncoding for Variable {
#[inline]
fn encode_unsigned<W, T>(mut writer: W, value: T) -> Result<(), W::Error>
where
W: Writer,
T: Unsigned,
{
writer.write_byte(CONTINUATION)?;
c::encode(writer, value)
}
#[inline]
fn decode_unsigned<'de, R, T>(mut reader: R) -> Result<T, R::Error>
where
R: Reader<'de>,
T: Unsigned,
{
if reader.read_byte()? != CONTINUATION {
return Err(R::Error::custom("expected CONTINUATION"));
}
c::decode(reader)
}
#[inline]
fn encode_signed<W, T>(mut writer: W, value: T) -> Result<(), W::Error>
where
W: Writer,
T: Signed,
{
writer.write_byte(CONTINUATION)?;
c::encode(writer, zig::encode(value))
}
#[inline]
fn decode_signed<'de, R, T>(mut reader: R) -> Result<T, R::Error>
where
R: Reader<'de>,
T: Signed,
T::Unsigned: Unsigned<Signed = T>,
{
if reader.read_byte()? != CONTINUATION {
return Err(R::Error::custom("expected CONTINUATION"));
}
let value: T::Unsigned = c::decode(reader)?;
Ok(zig::decode(value))
}
}
impl UsizeEncoding for Variable {
#[inline]
fn encode_usize<W>(writer: W, value: usize) -> Result<(), W::Error>
where
W: Writer,
{
c::encode(writer, value)
}
#[inline]
fn encode_typed_usize<W>(mut writer: W, value: usize) -> Result<(), W::Error>
where
W: Writer,
{
writer.write_byte(CONTINUATION)?;
c::encode(writer, value)
}
#[inline]
fn decode_usize<'de, R>(reader: R) -> Result<usize, R::Error>
where
R: Reader<'de>,
{
c::decode(reader)
}
#[inline]
fn decode_typed_usize<'de, R>(mut reader: R) -> Result<usize, R::Error>
where
R: Reader<'de>,
{
if reader.read_byte()? != CONTINUATION {
return Err(R::Error::custom("expected CONTINUATION"));
}
c::decode(reader)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub struct Fixed<B = NetworkEndian> {
_marker: marker::PhantomData<B>,
}
impl<B> IntegerEncoding for Fixed<B>
where
B: ByteOrder,
{
#[inline]
fn encode_unsigned<W, T>(mut writer: W, value: T) -> Result<(), W::Error>
where
W: Writer,
T: ByteOrderIo + Typed,
{
writer.write_byte(T::TYPE_FLAG)?;
value.write_bytes::<_, B>(writer)
}
#[inline]
fn decode_unsigned<'de, R, T>(mut reader: R) -> Result<T, R::Error>
where
R: Reader<'de>,
T: ByteOrderIo + Typed,
{
if reader.read_byte()? != T::TYPE_FLAG {
return Err(R::Error::custom("expected fixed integer"));
}
T::read_bytes::<_, B>(reader)
}
#[inline]
fn encode_signed<W, T>(mut writer: W, value: T) -> Result<(), W::Error>
where
W: Writer,
T: Signed,
T::Unsigned: ByteOrderIo + Typed,
{
writer.write_byte(T::Unsigned::TYPE_FLAG)?;
value.unsigned().write_bytes::<_, B>(writer)
}
#[inline]
fn decode_signed<'de, R, T>(mut reader: R) -> Result<T, R::Error>
where
R: Reader<'de>,
T: Signed,
T::Unsigned: ByteOrderIo<Signed = T> + Typed,
{
if reader.read_byte()? != T::Unsigned::TYPE_FLAG {
return Err(R::Error::custom("expected fixed integer"));
}
Ok(T::Unsigned::read_bytes::<_, B>(reader)?.signed())
}
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct FixedLength<L = u32, B = NetworkEndian> {
_marker: marker::PhantomData<(L, B)>,
}
impl<L, B> UsizeEncoding for FixedLength<L, B>
where
B: ByteOrder,
usize: TryFrom<L>,
L: ByteOrderIo + Typed + TryFrom<usize>,
L::Error: 'static + Debug + Display + Send + Sync,
<usize as TryFrom<L>>::Error: 'static + Debug + Display + Send + Sync,
{
#[inline]
fn encode_usize<W>(writer: W, value: usize) -> Result<(), W::Error>
where
W: Writer,
{
let value: L = value.try_into().map_err(W::Error::custom)?;
value.write_bytes::<_, B>(writer)
}
#[inline]
fn encode_typed_usize<W>(mut writer: W, value: usize) -> Result<(), W::Error>
where
W: Writer,
{
writer.write_byte(L::TYPE_FLAG)?;
let value: L = value.try_into().map_err(W::Error::custom)?;
value.write_bytes::<_, B>(writer)
}
#[inline]
fn decode_usize<'de, R>(reader: R) -> Result<usize, R::Error>
where
R: Reader<'de>,
{
usize::try_from(L::read_bytes::<_, B>(reader)?).map_err(R::Error::custom)
}
#[inline]
fn decode_typed_usize<'de, R>(mut reader: R) -> Result<usize, R::Error>
where
R: Reader<'de>,
{
if reader.read_byte()? != L::TYPE_FLAG {
return Err(R::Error::custom("expected fixed integer"));
}
usize::try_from(L::read_bytes::<_, B>(reader)?).map_err(R::Error::custom)
}
}