use crate::int::continuation as c;
use crate::int::zigzag as zig;
use crate::int::{Signed, Unsigned};
use crate::{Context, Reader, Writer};
use super::tag::{Kind, NumberKind, Tag};
#[inline]
pub(crate) fn encode_typed_unsigned<C, W, T>(
cx: C,
writer: W,
bits: u8,
value: T,
) -> Result<(), C::Error>
where
C: Context,
W: Writer,
T: Unsigned,
{
encode_typed(cx, writer, bits, value)
}
#[inline]
pub(crate) fn decode_typed_unsigned<'de, C, R, T>(cx: C, reader: R) -> Result<T, C::Error>
where
C: Context,
R: Reader<'de>,
T: Unsigned + TryFrom<T::Signed>,
{
let (value, kind): (T, NumberKind) = decode_typed(cx, reader)?;
match kind {
NumberKind::Signed => {
let value = zig::decode(value);
let Ok(value) = T::try_from(value) else {
return Err(cx.message(format_args!("Unsigned value outside of signed range")));
};
Ok(value)
}
NumberKind::Unsigned | NumberKind::Float => Ok(value),
kind => Err(cx.message(format_args!(
"Expected signed or unsigned number, got {kind:?}"
))),
}
}
#[inline]
fn encode_typed<C, W, T>(cx: C, mut writer: W, bits: u8, value: T) -> Result<(), C::Error>
where
C: Context,
W: Writer,
T: Unsigned,
{
writer.write_byte(cx, Tag::new(Kind::Number, bits).byte())?;
c::encode(cx, writer, value)
}
#[inline]
fn decode_typed<'de, C, R, T>(cx: C, mut reader: R) -> Result<(T, NumberKind), C::Error>
where
C: Context,
R: Reader<'de>,
T: Unsigned,
{
let tag = Tag::from_byte(reader.read_byte(cx)?);
if tag.kind() != Kind::Number {
return Err(cx.message(format_args!("Expected {:?}, got {tag:?}", Kind::Number)));
}
let kind = tag.number_kind();
Ok((c::decode(cx, reader)?, kind))
}
#[inline]
pub(crate) fn encode_typed_signed<C, W, T>(
cx: C,
writer: W,
bits: u8,
value: T,
) -> Result<(), C::Error>
where
C: Context,
W: Writer,
T: Signed,
{
encode_typed(cx, writer, bits, zig::encode(value))
}
#[inline]
pub(crate) fn decode_typed_signed<'de, C, R, T>(cx: C, reader: R) -> Result<T, C::Error>
where
C: Context,
R: Reader<'de>,
T: Signed + TryFrom<<T as Signed>::Unsigned>,
{
let (value, kind): (T::Unsigned, NumberKind) = decode_typed(cx, reader)?;
match kind {
NumberKind::Signed => Ok(zig::decode(value)),
NumberKind::Unsigned => {
let Ok(value) = T::try_from(value) else {
return Err(cx.message(format_args!("Unsigned value outside of signed range")));
};
Ok(value)
}
kind => Err(cx.message(format_args!(
"Expected signed or unsigned number, got {kind:?}"
))),
}
}