pw_varint/
pw_varint.rs

1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15//! # pw_varint
16//!
17//! `pw_varint` provides support for encoding and decoding variable length
18//! integers.  Small values require less memory than they do with fixed
19//! encoding.  Signed integers are first zig-zag encoded to allow small
20//! negative numbers to realize the memory savings.  For more information see
21//! [Pigweed's pw_varint documentation](https://pigweed.dev/pw_varint).
22//!
23//! The encoding format used is compatible with
24//! [Protocol Buffers](https://developers.google.com/protocol-buffers/docs/encoding#varints).
25//!
26//! Encoding and decoding is provided through the [VarintEncode] and
27//! [VarintDecode] traits.
28//!
29//! # Example
30//!
31//! ```
32//! use pw_varint::{VarintEncode, VarintDecode};
33//!
34//! let mut buffer = [0u8; 64];
35//!
36//! let encoded_len = (-1i64).varint_encode(&mut buffer).unwrap();
37//!
38//! let (decoded_len, val) = i64::varint_decode(&buffer ).unwrap();
39//! ```
40
41#![cfg_attr(not(feature = "std"), no_std)]
42
43use core::num::Wrapping;
44
45use pw_status::{Error, Result};
46
47/// A trait for objects than can be decoded from a varint.
48///
49/// `pw_varint` provides implementations for [i16], [u16], [i32], [u32],
50/// [i64], and [u64].
51pub trait VarintDecode: Sized {
52    /// Decode a type from a varint encoded series of bytes.
53    ///
54    /// Signed values will be implicitly zig-zag decoded.
55    fn varint_decode(data: &[u8]) -> Result<(usize, Self)>;
56}
57
58/// A trait for objects than can be encoded into a varint.
59///
60/// `pw_varint` provides implementations for [i16], [u16], [i32], [u32],
61/// [i64], and [u64].
62pub trait VarintEncode: Sized {
63    /// Encode a type into a varint encoded series of bytes.
64    ///
65    /// Signed values will be implicitly zig-zag encoded.
66    fn varint_encode(self, data: &mut [u8]) -> Result<usize>;
67}
68
69macro_rules! unsigned_varint_impl {
70    ($t:ty) => {
71        impl VarintDecode for $t {
72            fn varint_decode(data: &[u8]) -> Result<(usize, Self)> {
73                let (data, val) = decode_u64(data)?;
74                Ok((data, val as Self))
75            }
76        }
77
78        impl VarintEncode for $t {
79            fn varint_encode(self, data: &mut [u8]) -> Result<usize> {
80                encode_u64(data, self as u64)
81            }
82        }
83    };
84}
85
86macro_rules! signed_varint_impl {
87    ($t:ty) => {
88        impl VarintDecode for $t {
89            fn varint_decode(data: &[u8]) -> Result<(usize, Self)> {
90                let (data, val) = decode_u64(data)?;
91                Ok((data, zig_zag_decode(val) as Self))
92            }
93        }
94
95        impl VarintEncode for $t {
96            fn varint_encode(self, data: &mut [u8]) -> Result<usize> {
97                encode_u64(data, zig_zag_encode(self as i64))
98            }
99        }
100    };
101}
102
103unsigned_varint_impl!(u8);
104unsigned_varint_impl!(u16);
105unsigned_varint_impl!(u32);
106unsigned_varint_impl!(u64);
107
108signed_varint_impl!(i8);
109signed_varint_impl!(i16);
110signed_varint_impl!(i32);
111signed_varint_impl!(i64);
112
113fn decode_u64(data: &[u8]) -> Result<(usize, u64)> {
114    let mut value: u64 = 0;
115    for (i, d) in data.iter().enumerate() {
116        value |= (*d as u64 & 0x7f) << (i * 7);
117
118        if (*d & 0x80) == 0 {
119            return Ok((i + 1, value));
120        }
121    }
122    Err(Error::OutOfRange)
123}
124
125fn encode_u64(data: &mut [u8], value: u64) -> Result<usize> {
126    let mut value = value;
127    for (i, d) in data.iter_mut().enumerate() {
128        let mut byte: u8 = (value & 0x7f) as u8;
129        value >>= 7;
130        if value > 0 {
131            byte |= 0x80;
132        }
133        *d = byte;
134        if value == 0 {
135            return Ok(i + 1);
136        }
137    }
138    Err(Error::OutOfRange)
139}
140
141// ZigZag encodes a signed integer. This maps small negative numbers to small,
142// unsigned positive numbers, which improves their density for LEB128 encoding.
143//
144// ZigZag encoding works by moving the sign bit from the most-significant bit to
145// the least-significant bit. For the signed k-bit integer n, the formula is
146//
147//   (n << 1) ^ (n >> (k - 1))
148//
149// See the following for a description of ZigZag encoding:
150//   https://protobuf.dev/programming-guides/encoding/#signed-ints
151fn zig_zag_encode(value: i64) -> u64 {
152    ((value as u64) << 1) ^ ((value >> (i64::BITS - 1)) as u64)
153}
154
155fn zig_zag_decode(value: u64) -> i64 {
156    let value = Wrapping(value);
157    ((value >> 1) ^ (!(value & Wrapping(1)) + Wrapping(1))).0 as i64
158}
159
160#[cfg(test)]
161mod test {
162    use super::*;
163
164    fn success_cases_u8<T>() -> Vec<(Vec<u8>, T)>
165    where
166        T: From<u8>,
167    {
168        vec![
169            // From varint_test.cc EncodeSizeUnsigned32_SmallSingleByte.
170            (vec![0x00], 0x00.into()),
171            (vec![0x01], 0x01.into()),
172            (vec![0x02], 0x02.into()),
173            // From varint_test.cc EncodeSizeUnsigned32_LargeSingleByte.
174            (vec![0x3f], 0x3f.into()),
175            (vec![0x40], 0x40.into()),
176            (vec![0x7e], 0x7e.into()),
177            (vec![0x7f], 0x7f.into()),
178            // From varint_test.cc EncodeSizeUnsigned32_MultiByte.
179            (vec![0x80, 0x01], 128.into()),
180            (vec![0x81, 0x01], 129.into()),
181            // From https://protobuf.dev/programming-guides/encoding/.
182            (vec![0x96, 0x01], 150.into()),
183        ]
184    }
185
186    fn success_cases_i8<T>() -> Vec<(Vec<u8>, T)>
187    where
188        T: From<i8>,
189    {
190        vec![
191            // From varint_test.cc EncodeSizeSigned32_SmallSingleByte.
192            (vec![0x00], 0i8.into()),
193            (vec![0x01], (-1i8).into()),
194            (vec![0x02], 1i8.into()),
195            (vec![0x03], (-2i8).into()),
196            (vec![0x04], 2i8.into()),
197            // From varint_test.cc EncodeSizeSigned32_LargeSingleByte.
198            (vec![125], (-63i8).into()),
199            (vec![126], (63i8).into()),
200            (vec![127], (-64i8).into()),
201            // From varint_test.cc EncodeSizeSigned32_MultiByte.
202            (vec![0x80, 0x1], 64i8.into()),
203            (vec![0x81, 0x1], (-65i8).into()),
204            (vec![0x82, 0x1], 65i8.into()),
205        ]
206    }
207
208    fn success_cases_u32<T>() -> Vec<(Vec<u8>, T)>
209    where
210        T: From<u32>,
211    {
212        vec![
213            // From varint_test.cc EncodeSizeUnsigned32_MultiByte.
214            (vec![0xfe, 0xff, 0xff, 0xff, 0x0f], 0xffff_fffe.into()),
215            (vec![0xff, 0xff, 0xff, 0xff, 0x0f], 0xffff_ffff.into()),
216        ]
217    }
218
219    fn success_cases_i32<T>() -> Vec<(Vec<u8>, T)>
220    where
221        T: From<i32>,
222    {
223        vec![
224            // From varint_test.cc EncodeSizeSigned32_MultiByte.
225            (vec![0xff, 0xff, 0xff, 0xff, 0x0f], i32::MIN.into()),
226            (vec![0xfe, 0xff, 0xff, 0xff, 0x0f], i32::MAX.into()),
227        ]
228    }
229
230    #[test]
231    fn decode_test_u16() {
232        for case in success_cases_u8::<u16>() {
233            assert_eq!(u16::varint_decode(&case.0), Ok((case.0.len(), case.1)));
234        }
235
236        assert_eq!(u16::varint_decode(&[0x96]), Err(Error::OutOfRange));
237    }
238
239    #[test]
240    fn decode_test_i16() {
241        for case in success_cases_i8::<i16>() {
242            assert_eq!(i16::varint_decode(&case.0), Ok((case.0.len(), case.1)));
243        }
244
245        assert_eq!(i16::varint_decode(&[0x96]), Err(Error::OutOfRange));
246    }
247
248    #[test]
249    fn decode_test_u32() {
250        for case in success_cases_u8::<u32>()
251            .into_iter()
252            .chain(success_cases_u32::<u32>())
253        {
254            assert_eq!(u32::varint_decode(&case.0), Ok((case.0.len(), case.1)));
255        }
256
257        assert_eq!(u32::varint_decode(&[0x96]), Err(Error::OutOfRange));
258    }
259
260    #[test]
261    fn decode_test_i32() {
262        for case in success_cases_i8::<i32>()
263            .into_iter()
264            .chain(success_cases_i32::<i32>())
265        {
266            assert_eq!(i32::varint_decode(&case.0), Ok((case.0.len(), case.1)));
267        }
268
269        assert_eq!(i32::varint_decode(&[0x96]), Err(Error::OutOfRange));
270    }
271
272    #[test]
273    fn decode_test_u64() {
274        for case in success_cases_u8::<u64>()
275            .into_iter()
276            .chain(success_cases_u32::<u64>())
277        {
278            assert_eq!(u64::varint_decode(&case.0), Ok((case.0.len(), case.1)));
279        }
280
281        assert_eq!(u64::varint_decode(&[0x96]), Err(Error::OutOfRange));
282    }
283
284    #[test]
285    fn decode_test_i64() {
286        for case in success_cases_i8::<i64>()
287            .into_iter()
288            .chain(success_cases_i32::<i64>())
289        {
290            assert_eq!(i64::varint_decode(&case.0), Ok((case.0.len(), case.1)));
291        }
292
293        assert_eq!(i64::varint_decode(&[0x96]), Err(Error::OutOfRange));
294    }
295
296    #[test]
297    fn encode_test_u16() {
298        for case in success_cases_u8::<u16>() {
299            let mut buffer = [0u8; 64];
300            let len = case.1.varint_encode(&mut buffer).unwrap();
301            assert_eq!(len, case.0.len());
302            assert_eq!(&buffer[0..len], case.0);
303        }
304    }
305
306    #[test]
307    fn encode_test_i16() {
308        for case in success_cases_i8::<i16>() {
309            let mut buffer = [0u8; 64];
310            let len = case.1.varint_encode(&mut buffer).unwrap();
311            assert_eq!(len, case.0.len());
312            assert_eq!(&buffer[0..len], case.0);
313        }
314    }
315
316    #[test]
317    fn encode_test_u32() {
318        for case in success_cases_u8::<u32>()
319            .into_iter()
320            .chain(success_cases_u32::<u32>())
321        {
322            let mut buffer = [0u8; 64];
323            let len = case.1.varint_encode(&mut buffer).unwrap();
324            assert_eq!(len, case.0.len());
325            assert_eq!(&buffer[0..len], case.0);
326        }
327    }
328
329    #[test]
330    fn encode_test_i32() {
331        for case in success_cases_i8::<i32>()
332            .into_iter()
333            .chain(success_cases_i32::<i32>())
334        {
335            let mut buffer = [0u8; 64];
336            let len = case.1.varint_encode(&mut buffer).unwrap();
337            assert_eq!(len, len);
338            assert_eq!(&buffer[0..len], case.0);
339        }
340    }
341
342    #[test]
343    fn encode_test_u64() {
344        for case in success_cases_u8::<u64>()
345            .into_iter()
346            .chain(success_cases_u32::<u64>())
347        {
348            let mut buffer = [0u8; 64];
349            let len = case.1.varint_encode(&mut buffer).unwrap();
350            assert_eq!(len, case.0.len());
351            assert_eq!(&buffer[0..len], case.0);
352        }
353    }
354
355    #[test]
356    fn encode_test_i64() {
357        for case in success_cases_i8::<i64>()
358            .into_iter()
359            .chain(success_cases_i32::<i64>())
360        {
361            let mut buffer = [0u8; 64];
362            let len = case.1.varint_encode(&mut buffer).unwrap();
363            assert_eq!(len, case.0.len());
364            assert_eq!(&buffer[0..len], case.0);
365        }
366    }
367}