1use musli::Context;
2use musli_utils::int::continuation as c;
3use musli_utils::int::zigzag as zig;
4use musli_utils::int::{Signed, Unsigned, UnsignedOps};
5use musli_utils::{Options, Reader, Writer};
6
7use crate::tag::{Kind, Tag, DATA_MASK};
8
9#[inline]
11pub(crate) fn encode_length<C, W, const OPT: Options>(
12 cx: &C,
13 mut writer: W,
14 value: usize,
15) -> Result<(), C::Error>
16where
17 C: ?Sized + Context,
18 W: Writer,
19{
20 match musli_utils::options::length::<OPT>() {
21 musli_utils::options::Integer::Variable => {
22 if value.is_smaller_than(DATA_MASK) {
23 writer.write_byte(cx, Tag::new(Kind::Continuation, value.as_byte()).byte())
24 } else {
25 writer.write_byte(cx, Tag::empty(Kind::Continuation).byte())?;
26 c::encode(cx, writer, value)
27 }
28 }
29 _ => {
30 let bo = musli_utils::options::byteorder::<OPT>();
31 let width = musli_utils::options::length_width::<OPT>();
32 let bytes = 1u8 << width as u8;
33 writer.write_byte(cx, Tag::new(Kind::Prefix, bytes).byte())?;
34
35 macro_rules! fixed {
36 ($ty:ty) => {{
37 let Ok(value) = <$ty>::try_from(value) else {
38 return Err(cx.message("Numerical value out of bounds for usize"));
39 };
40
41 value.write_bytes(cx, writer, bo)
42 }};
43 }
44
45 musli_utils::width_arm!(width, fixed)
46 }
47 }
48}
49
50#[inline]
52pub(crate) fn decode_length<'de, C, R, const OPT: Options>(
53 cx: &C,
54 mut reader: R,
55) -> Result<usize, C::Error>
56where
57 C: ?Sized + Context,
58 R: Reader<'de>,
59{
60 match musli_utils::options::length::<OPT>() {
61 musli_utils::options::Integer::Variable => {
62 let tag = Tag::from_byte(reader.read_byte(cx)?);
63
64 if tag.kind() != Kind::Continuation {
65 return Err(cx.message("Expected continuation"));
66 }
67
68 if let Some(data) = tag.data() {
69 Ok(usize::from_byte(data))
70 } else {
71 c::decode(cx, reader)
72 }
73 }
74 _ => {
75 let bo = musli_utils::options::byteorder::<OPT>();
76 let width = musli_utils::options::length_width::<OPT>();
77
78 let bytes = 1u8 << width as u8;
79 let tag = Tag::from_byte(reader.read_byte(cx)?);
80
81 if tag != Tag::new(Kind::Prefix, bytes) {
82 return Err(cx.message(format_args!(
83 "Expected fixed {} bytes prefix tag, but got {tag:?}",
84 bytes
85 )));
86 }
87
88 macro_rules! fixed {
89 ($ty:ty) => {{
90 let Ok(value) = usize::try_from(<$ty>::read_bytes(cx, reader, bo)?) else {
91 return Err(cx.message("Value type out of bounds for usize"));
92 };
93
94 Ok(value)
95 }};
96 }
97
98 musli_utils::width_arm!(width, fixed)
99 }
100 }
101}
102
103#[inline]
105pub(crate) fn encode_unsigned<C, W, T, const OPT: Options>(
106 cx: &C,
107 mut writer: W,
108 value: T,
109) -> Result<(), C::Error>
110where
111 C: ?Sized + Context,
112 W: Writer,
113 T: UnsignedOps,
114{
115 match musli_utils::options::integer::<OPT>() {
116 musli_utils::options::Integer::Variable => {
117 if value.is_smaller_than(DATA_MASK) {
118 writer.write_byte(cx, Tag::new(Kind::Continuation, value.as_byte()).byte())
119 } else {
120 writer.write_byte(cx, Tag::empty(Kind::Continuation).byte())?;
121 c::encode(cx, writer, value)
122 }
123 }
124 _ => {
125 let bo = musli_utils::options::byteorder::<OPT>();
126 writer.write_byte(cx, Tag::new(Kind::Prefix, T::BYTES).byte())?;
127 value.write_bytes(cx, writer, bo)
128 }
129 }
130}
131
132#[inline]
134pub(crate) fn decode_unsigned<'de, C, R, T, const OPT: Options>(
135 cx: &C,
136 mut reader: R,
137) -> Result<T, C::Error>
138where
139 C: ?Sized + Context,
140 R: Reader<'de>,
141 T: UnsignedOps,
142{
143 match musli_utils::options::integer::<OPT>() {
144 musli_utils::options::Integer::Variable => {
145 let tag = Tag::from_byte(reader.read_byte(cx)?);
146
147 if tag.kind() != Kind::Continuation {
148 return Err(cx.message("Expected continuation"));
149 }
150
151 if let Some(data) = tag.data() {
152 Ok(T::from_byte(data))
153 } else {
154 c::decode(cx, reader)
155 }
156 }
157 _ => {
158 let bo = musli_utils::options::byteorder::<OPT>();
159
160 if Tag::from_byte(reader.read_byte(cx)?) != Tag::new(Kind::Prefix, T::BYTES) {
161 return Err(cx.message("Expected fixed integer"));
162 }
163
164 T::read_bytes(cx, reader, bo)
165 }
166 }
167}
168
169#[inline]
171pub(crate) fn encode_signed<C, W, T, const OPT: Options>(
172 cx: &C,
173 writer: W,
174 value: T,
175) -> Result<(), C::Error>
176where
177 C: ?Sized + Context,
178 W: Writer,
179 T: Signed,
180 T::Unsigned: UnsignedOps,
181{
182 let value = zig::encode(value);
183 encode_unsigned::<C, W, T::Unsigned, OPT>(cx, writer, value)
184}
185
186#[inline]
188pub(crate) fn decode_signed<'de, C, R, T, const OPT: Options>(
189 cx: &C,
190 reader: R,
191) -> Result<T, C::Error>
192where
193 C: ?Sized + Context,
194 R: Reader<'de>,
195 T: Signed,
196 T::Unsigned: UnsignedOps,
197{
198 let value = decode_unsigned::<C, R, T::Unsigned, OPT>(cx, reader)?;
199 Ok(zig::decode(value))
200}