Skip to main content

bilrost/encoding/
varint.rs

1use crate::buf::ReverseBuf;
2use crate::encoding::{
3    encode_varint, encoded_len_varint, encoding_implemented_via_value_encoding,
4    encoding_uses_base_empty_state, prepend_varint, Buf, BufMut, Canonicity, Capped, DecodeContext,
5    DistinguishedValueDecoder, RestrictedDecodeContext, ValueDecoder, ValueEncoder, WireType,
6    Wiretyped,
7};
8use crate::DecodeError;
9use crate::DecodeErrorKind::{InvalidValue, OutOfDomainValue};
10
11pub struct Varint;
12
13encoding_uses_base_empty_state!(Varint);
14encoding_implemented_via_value_encoding!(Varint);
15
16/// Zig-zag encoding: These functions implement storing signed in unsigned integers by encoding the
17/// sign bit in the least significant bit.
18#[inline]
19fn i8_to_unsigned(value: i8) -> u8 {
20    ((value << 1) ^ (value >> 7)) as u8
21}
22
23#[inline]
24fn u8_to_signed(value: u8) -> i8 {
25    ((value >> 1) as i8) ^ (-((value & 1) as i8))
26}
27
28#[inline]
29fn i16_to_unsigned(value: i16) -> u16 {
30    ((value << 1) ^ (value >> 15)) as u16
31}
32
33#[inline]
34fn u16_to_signed(value: u16) -> i16 {
35    ((value >> 1) as i16) ^ (-((value & 1) as i16))
36}
37
38#[inline]
39fn i32_to_unsigned(value: i32) -> u32 {
40    ((value << 1) ^ (value >> 31)) as u32
41}
42
43#[inline]
44fn u32_to_signed(value: u32) -> i32 {
45    ((value >> 1) as i32) ^ (-((value & 1) as i32))
46}
47
48#[inline]
49pub(crate) fn i64_to_unsigned(value: i64) -> u64 {
50    ((value << 1) ^ (value >> 63)) as u64
51}
52
53#[inline]
54pub(crate) fn u64_to_signed(value: u64) -> i64 {
55    ((value >> 1) as i64) ^ (-((value & 1) as i64))
56}
57
58/// Macro which emits implementations for variable width numeric encoding.
59macro_rules! varint {
60    (
61        $name:ident,
62        $ty:ty,
63        to_uint64($to_uint64_value:ident) $to_uint64:expr,
64        from_uint64($from_uint64_value:ident) $from_uint64:expr
65        $(, $($avoid_no_empty_state:tt)*)?
66    ) => {
67        impl Wiretyped<Varint, $ty> for () {
68            const WIRE_TYPE: WireType = WireType::Varint;
69        }
70
71        impl ValueEncoder<Varint, $ty> for () {
72            #[inline(always)]
73            fn encode_value<B: BufMut + ?Sized>($to_uint64_value: &$ty, buf: &mut B) {
74                encode_varint($to_uint64, buf);
75            }
76
77            #[inline(always)]
78            fn prepend_value<B: ReverseBuf + ?Sized>($to_uint64_value: &$ty, buf: &mut B) {
79                prepend_varint($to_uint64, buf);
80            }
81
82            #[inline(always)]
83            fn value_encoded_len($to_uint64_value: &$ty) -> usize {
84                encoded_len_varint($to_uint64)
85            }
86        }
87
88        impl ValueDecoder<Varint, $ty> for () {
89            #[inline(always)]
90            fn decode_value<B: Buf + ?Sized>(
91                __value: &mut $ty,
92                mut buf: Capped<B>,
93                _ctx: DecodeContext,
94            ) -> Result<(), DecodeError> {
95                let $from_uint64_value = buf.decode_varint()?;
96                *__value = $from_uint64;
97                Ok(())
98            }
99        }
100
101        impl DistinguishedValueDecoder<Varint, $ty> for () {
102            const CHECKS_EMPTY: bool = false;
103
104            #[inline]
105            fn decode_value_distinguished<const ALLOW_EMPTY: bool>(
106                value: &mut $ty,
107                buf: Capped<impl Buf + ?Sized>,
108                ctx: RestrictedDecodeContext,
109            ) -> Result<Canonicity, DecodeError> {
110                <() as ValueDecoder::<Varint, _>>::decode_value(value, buf, ctx.into_inner())?;
111                Ok(Canonicity::Canonical)
112            }
113        }
114
115        crate::encoding::delegate_value_encoding!(
116            encoding (Varint) borrows type ($ty) as owned including distinguished
117        );
118
119        #[cfg(test)]
120        mod $name {
121            use crate::encoding::Varint;
122            crate::encoding::test::check_type_test!(
123                Varint,
124                relaxed,
125                $ty,
126                WireType::Varint
127                $(, $($avoid_no_empty_state)*)?
128            );
129            crate::encoding::test::check_type_test!(
130                Varint,
131                distinguished,
132                $ty,
133                WireType::Varint
134                $(, $($avoid_no_empty_state)*)?
135            );
136        }
137    };
138}
139
140varint!(varint_bool, bool,
141to_uint64(value) {
142    u64::from(*value)
143},
144from_uint64(value) {
145    match value {
146        0 => false,
147        1 => true,
148        _ => return Err(DecodeError::new(OutOfDomainValue))
149    }
150});
151
152varint!(varint_u8, u8,
153to_uint64(value) {
154    *value as u64
155},
156from_uint64(value) {
157    u8::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
158});
159
160varint!(varint_nonzerou8, core::num::NonZeroU8,
161to_uint64(value) {
162    value.get() as u64
163},
164from_uint64(value) {
165    core::num::NonZeroU8::new(
166        u8::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
167    ).ok_or_else(|| DecodeError::new(InvalidValue))?
168}, has no empty state);
169
170varint!(varint_u16, u16,
171to_uint64(value) {
172    *value as u64
173},
174from_uint64(value) {
175    u16::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
176});
177
178varint!(varint_nonzerou16, core::num::NonZeroU16,
179to_uint64(value) {
180    value.get() as u64
181},
182from_uint64(value) {
183    core::num::NonZeroU16::new(
184        u16::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
185    ).ok_or_else(|| DecodeError::new(InvalidValue))?
186}, has no empty state);
187
188varint!(varint_u32, u32,
189to_uint64(value) {
190    *value as u64
191},
192from_uint64(value) {
193    u32::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
194});
195
196varint!(varint_nonzerou32, core::num::NonZeroU32,
197to_uint64(value) {
198    value.get() as u64
199},
200from_uint64(value) {
201    core::num::NonZeroU32::new(
202        u32::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
203    ).ok_or_else(|| DecodeError::new(InvalidValue))?
204}, has no empty state);
205
206varint!(varint_u64, u64,
207to_uint64(value) {
208    *value
209},
210from_uint64(value) {
211    value
212});
213
214varint!(varint_nonzerou64, core::num::NonZeroU64,
215to_uint64(value) {
216    value.get()
217},
218from_uint64(value) {
219    core::num::NonZeroU64::new(value).ok_or_else(|| DecodeError::new(InvalidValue))?
220}, has no empty state);
221
222varint!(varint_usize, usize,
223to_uint64(value) {
224    *value as u64
225},
226from_uint64(value) {
227    usize::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
228});
229
230varint!(varint_nonzerousize, core::num::NonZeroUsize,
231to_uint64(value) {
232    value.get() as u64
233},
234from_uint64(value) {
235    core::num::NonZeroUsize::new(
236        usize::try_from(value).map_err(|_| DecodeError::new(OutOfDomainValue))?
237    ).ok_or_else(|| DecodeError::new(InvalidValue))?
238}, has no empty state);
239
240varint!(varint_i8, i8,
241to_uint64(value) {
242    i8_to_unsigned(*value) as u64
243},
244from_uint64(value) {
245    let value = u8::try_from(value)
246        .map_err(|_| DecodeError::new(OutOfDomainValue))?;
247    u8_to_signed(value)
248});
249
250varint!(varint_nonzeroi8, core::num::NonZeroI8,
251to_uint64(value) {
252    i8_to_unsigned(value.get()) as u64
253},
254from_uint64(value) {
255    let value = u8::try_from(value)
256        .map_err(|_| DecodeError::new(OutOfDomainValue))?;
257    core::num::NonZeroI8::new(u8_to_signed(value))
258        .ok_or_else(|| DecodeError::new(InvalidValue))?
259}, has no empty state);
260
261varint!(varint_i16, i16,
262to_uint64(value) {
263    i16_to_unsigned(*value) as u64
264},
265from_uint64(value) {
266    let value = u16::try_from(value)
267        .map_err(|_| DecodeError::new(OutOfDomainValue))?;
268    u16_to_signed(value)
269});
270
271varint!(varint_nonzeroi16, core::num::NonZeroI16,
272to_uint64(value) {
273    i16_to_unsigned(value.get()) as u64
274},
275from_uint64(value) {
276    let value = u16::try_from(value)
277        .map_err(|_| DecodeError::new(OutOfDomainValue))?;
278    core::num::NonZeroI16::new(u16_to_signed(value))
279        .ok_or_else(|| DecodeError::new(InvalidValue))?
280}, has no empty state);
281
282varint!(varint_i32, i32,
283to_uint64(value) {
284    i32_to_unsigned(*value) as u64
285},
286from_uint64(value) {
287    let value = u32::try_from(value)
288        .map_err(|_| DecodeError::new(OutOfDomainValue))?;
289    u32_to_signed(value)
290});
291
292varint!(varint_nonzeroi32, core::num::NonZeroI32,
293to_uint64(value) {
294    i32_to_unsigned(value.get()) as u64
295},
296from_uint64(value) {
297    let value = u32::try_from(value)
298        .map_err(|_| DecodeError::new(OutOfDomainValue))?;
299    core::num::NonZeroI32::new(u32_to_signed(value))
300        .ok_or_else(|| DecodeError::new(InvalidValue))?
301}, has no empty state);
302
303varint!(varint_i64, i64,
304to_uint64(value) {
305    i64_to_unsigned(*value)
306},
307from_uint64(value) {
308    u64_to_signed(value)
309});
310
311varint!(varint_nonzero648, core::num::NonZeroI64,
312to_uint64(value) {
313    i64_to_unsigned(value.get())
314},
315from_uint64(value) {
316    core::num::NonZeroI64::new(u64_to_signed(value))
317        .ok_or_else(|| DecodeError::new(InvalidValue))?
318}, has no empty state);
319
320varint!(varint_isize, isize,
321to_uint64(value) {
322    i64_to_unsigned(*value as i64)
323},
324from_uint64(value) {
325    isize::try_from(u64_to_signed(value))
326        .map_err(|_| DecodeError::new(OutOfDomainValue))?
327});
328
329varint!(varint_nonzeroisize, core::num::NonZeroIsize,
330to_uint64(value) {
331    i64_to_unsigned(value.get() as i64)
332},
333from_uint64(value) {
334    let value = isize::try_from(u64_to_signed(value))
335        .map_err(|_| DecodeError::new(OutOfDomainValue))?;
336    core::num::NonZeroIsize::new(value)
337        .ok_or_else(|| DecodeError::new(InvalidValue))?
338}, has no empty state);