musli_descriptive/
integer_encoding.rs1use musli::Context;
2
3use musli_utils::int::continuation as c;
4use musli_utils::int::zigzag as zig;
5use musli_utils::int::{Signed, Unsigned};
6use musli_utils::{Reader, Writer};
7
8use crate::tag::{Kind, NumberKind, Tag};
9
10#[inline]
11pub(crate) fn encode_typed_unsigned<C, W, T>(
12 cx: &C,
13 writer: W,
14 bits: u8,
15 value: T,
16) -> Result<(), C::Error>
17where
18 C: ?Sized + Context,
19 W: Writer,
20 T: Unsigned,
21{
22 encode_typed(cx, writer, bits, value)
23}
24
25#[inline]
26pub(crate) fn decode_typed_unsigned<'de, C, R, T>(cx: &C, reader: R) -> Result<T, C::Error>
27where
28 C: ?Sized + Context,
29 R: Reader<'de>,
30 T: Unsigned + TryFrom<T::Signed>,
31{
32 let (value, kind): (T, NumberKind) = decode_typed(cx, reader)?;
33
34 match kind {
35 NumberKind::Signed => {
36 let value = zig::decode(value);
37
38 let Ok(value) = T::try_from(value) else {
39 return Err(cx.message(format_args!("Unsigned value outside of signed range")));
40 };
41
42 Ok(value)
43 }
44 NumberKind::Unsigned | NumberKind::Float => Ok(value),
45 kind => Err(cx.message(format_args!(
46 "Expected signed or unsigned number, got {:?}",
47 kind
48 ))),
49 }
50}
51
52#[inline]
53fn encode_typed<C, W, T>(cx: &C, mut writer: W, bits: u8, value: T) -> Result<(), C::Error>
54where
55 C: ?Sized + Context,
56 W: Writer,
57 T: Unsigned,
58{
59 writer.write_byte(cx, Tag::new(Kind::Number, bits).byte())?;
60 c::encode(cx, writer, value)
61}
62
63#[inline]
64fn decode_typed<'de, C, R, T>(cx: &C, mut reader: R) -> Result<(T, NumberKind), C::Error>
65where
66 C: ?Sized + Context,
67 R: Reader<'de>,
68 T: Unsigned,
69{
70 let tag = Tag::from_byte(reader.read_byte(cx)?);
71
72 if tag.kind() != Kind::Number {
73 return Err(cx.message(format_args!("Expected {:?}, got {tag:?}", Kind::Number)));
74 }
75
76 let kind = tag.number_kind();
77 Ok((c::decode(cx, reader)?, kind))
78}
79
80#[inline]
81pub(crate) fn encode_typed_signed<C, W, T>(
82 cx: &C,
83 writer: W,
84 bits: u8,
85 value: T,
86) -> Result<(), C::Error>
87where
88 C: ?Sized + Context,
89 W: Writer,
90 T: Signed,
91{
92 encode_typed(cx, writer, bits, zig::encode(value))
93}
94
95#[inline]
96pub(crate) fn decode_typed_signed<'de, C, R, T>(cx: &C, reader: R) -> Result<T, C::Error>
97where
98 C: ?Sized + Context,
99 R: Reader<'de>,
100 T: Signed + TryFrom<<T as Signed>::Unsigned>,
101{
102 let (value, kind): (T::Unsigned, NumberKind) = decode_typed(cx, reader)?;
103
104 match kind {
105 NumberKind::Signed => Ok(zig::decode(value)),
106 NumberKind::Unsigned => {
107 let Ok(value) = T::try_from(value) else {
108 return Err(cx.message(format_args!("Unsigned value outside of signed range")));
109 };
110
111 Ok(value)
112 }
113 kind => Err(cx.message(format_args!(
114 "Expected signed or unsigned number, got {:?}",
115 kind
116 ))),
117 }
118}