Skip to main content

fxfs/serialized_types/
varint.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//! Lexicographically ordered variable-length integer (varint) encoding.
5//!
6//! This encoding ensures that the byte-wise (lexicographical) comparison of encoded values
7//! matches the numerical comparison of the original values.
8//!
9//! This is achieved by:
10//! 1. Dividing the value space into distinct length categories.
11//! 2. Assigning each category a non-overlapping range of first-byte values, ordered by length.
12//! 3. Encoding the remaining bits in Big-Endian order (which naturally matches numerical order).
13//!
14//! Encoding rules (bit-level):
15//! - `v < 0xc0` (0..191): 1 byte
16//!   - Pattern: `0b0xxxxxxx` or `0b10xxxxxx`
17//!   - First byte range: `0x00..=0xbf`
18//! - `v < 0x2000` (192..8191): 2 bytes
19//!   - Encoded as `v | 0xc000` (Big Endian)
20//!   - Pattern: `0b110xxxxx xxxxxxxx`
21//!   - First byte range: `0xc0..=0xdf`
22//! - `v < 0x1000_0000` (8192..268435455): 4 bytes
23//!   - Encoded as `v | 0xe000_0000` (Big Endian)
24//!   - Pattern: `0b1110xxxx xxxxxxxx ...`
25//!   - First byte range: `0xe0..=0xef`
26//! - `v < 0x0f00_0000_0000_0000`: 8 bytes
27//!   - Encoded as `v | 0xf000_0000_0000_0000` (Big Endian)
28//!   - Pattern: `0b1111xxxx xxxxxxxx ...`
29//!   - First byte range: `0xf0..=0xfe`
30//! - Else: 9 bytes
31//!   - Encoded as `0xff` followed by `v.to_be_bytes()`
32//!   - Pattern: `0b11111111 xxxxxxxx ...`
33//!   - First byte: `0xff`
34
35use anyhow::{Error, ensure};
36
37/// Abstraction over a contiguous in-memory byte buffer that supports appending.
38pub trait Buffer: AsRef<[u8]> + AsMut<[u8]> + Send {
39    /// Appends data to the end of the buffer.
40    fn put(&mut self, data: &[u8]);
41}
42
43impl Buffer for Vec<u8> {
44    fn put(&mut self, data: &[u8]) {
45        self.extend_from_slice(data);
46    }
47}
48
49/// Encodes `v` into an order-preserving varint returned as a fixed-size byte array and length.
50#[inline]
51pub fn encode_varint_bytes(v: u64) -> ([u8; 9], usize) {
52    let mut buf = [0u8; 9];
53    let len = if v < 0xc0 {
54        buf[0] = v as u8;
55        1
56    } else if v < 0x2000 {
57        buf[..2].copy_from_slice(&(v as u16 | 0xc000).to_be_bytes());
58        2
59    } else if v < 0x1000_0000 {
60        buf[..4].copy_from_slice(&(v as u32 | 0xe000_0000).to_be_bytes());
61        4
62    } else if v < 0x0f00_0000_0000_0000 {
63        buf[..8].copy_from_slice(&(v | 0xf000_0000_0000_0000).to_be_bytes());
64        8
65    } else {
66        buf[0] = 0xff;
67        buf[1..9].copy_from_slice(&v.to_be_bytes());
68        9
69    };
70    (buf, len)
71}
72
73/// Encodes `v` into an order-preserving varint directly written to `buf`.
74#[inline]
75pub fn encode_varint(v: u64, buf: &mut impl Buffer) -> usize {
76    if v < 0xc0 {
77        buf.put(&[v as u8]);
78        1
79    } else if v < 0x2000 {
80        buf.put(&(v as u16 | 0xc000).to_be_bytes());
81        2
82    } else if v < 0x1000_0000 {
83        buf.put(&(v as u32 | 0xe000_0000).to_be_bytes());
84        4
85    } else if v < 0x0f00_0000_0000_0000 {
86        buf.put(&(v | 0xf000_0000_0000_0000).to_be_bytes());
87        8
88    } else {
89        let mut b = [0u8; 9];
90        b[0] = 0xff;
91        b[1..9].copy_from_slice(&v.to_be_bytes());
92        buf.put(&b);
93        9
94    }
95}
96
97/// Decodes an order-preserving varint from the beginning of `data`.
98///
99/// Returns the decoded `u64` value and the remaining unconsumed slice.
100#[inline]
101pub fn decode_varint<'a>(data: &'a [u8]) -> Result<(u64, &'a [u8]), Error> {
102    ensure!(!data.is_empty(), "Data too short");
103    let b = data[0];
104    let (val, len) = if b < 0xc0 {
105        (b as u64, 1)
106    } else if b < 0xe0 {
107        ensure!(data.len() >= 2, "Data too short");
108        let v = u16::from_be_bytes(data[..2].try_into().unwrap());
109        let val = (v & !0xc000) as u64;
110        ensure!(val >= 0xc0, "Non-canonical varint");
111        (val, 2)
112    } else if b < 0xf0 {
113        ensure!(data.len() >= 4, "Data too short");
114        let v = u32::from_be_bytes(data[..4].try_into().unwrap());
115        let val = (v & !0xe000_0000) as u64;
116        ensure!(val >= 0x2000, "Non-canonical varint");
117        (val, 4)
118    } else if b < 0xff {
119        ensure!(data.len() >= 8, "Data too short");
120        let v = u64::from_be_bytes(data[..8].try_into().unwrap());
121        let val = v & !0xf000_0000_0000_0000;
122        ensure!(val >= 0x1000_0000, "Non-canonical varint");
123        (val, 8)
124    } else {
125        ensure!(data.len() >= 9, "Data too short");
126        let val = u64::from_be_bytes(data[1..9].try_into().unwrap());
127        ensure!(val >= 0x0f00_0000_0000_0000, "Non-canonical varint");
128        (val, 9)
129    };
130    Ok((val, &data[len..]))
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136
137    #[test]
138    fn test_correctness() {
139        let test_cases = vec![
140            0,
141            1,
142            0xbe,
143            0xbf,
144            0xc0,
145            0x1ffe,
146            0x1fff,
147            0x2000,
148            0x0fff_ffff,
149            0x1000_0000,
150            0x0eff_ffff_ffff_ffff,
151            0x0f00_0000_0000_0000,
152            u64::MAX,
153        ];
154        for v in test_cases {
155            let mut buf = Vec::new();
156            let len = encode_varint(v, &mut buf);
157            let (decoded, remainder) = decode_varint(&buf).unwrap();
158            assert_eq!(v, decoded);
159            assert_eq!(remainder.len(), 0);
160            assert_eq!(buf.len(), len);
161
162            let (bytes, bytes_len) = encode_varint_bytes(v);
163            assert_eq!(len, bytes_len);
164            assert_eq!(&buf[..], &bytes[..bytes_len]);
165        }
166    }
167
168    #[test]
169    fn test_ordering_correctness() {
170        let test_cases = vec![
171            0,
172            1,
173            0xbe,
174            0xbf,
175            0xc0,
176            0x1ffe,
177            0x1fff,
178            0x2000,
179            0x0fff_ffff,
180            0x1000_0000,
181            0x0eff_ffff_ffff_ffff,
182            0x0f00_0000_0000_0000,
183            u64::MAX,
184        ];
185        for i in 0..test_cases.len() {
186            for j in 0..test_cases.len() {
187                let a = test_cases[i];
188                let b = test_cases[j];
189
190                let mut buf_a = Vec::new();
191                let mut buf_b = Vec::new();
192
193                encode_varint(a, &mut buf_a);
194                encode_varint(b, &mut buf_b);
195
196                let ord_cmp = a.cmp(&b);
197                let ser_cmp = buf_a.cmp(&buf_b);
198                assert_eq!(ord_cmp, ser_cmp, "Mismatch for {} and {}", a, b);
199            }
200        }
201    }
202
203    #[test]
204    fn test_non_canonical() {
205        assert!(decode_varint(&[0xc0, 0x03]).is_err());
206        assert!(decode_varint(&[0xe0, 0x00, 0x1f, 0xff]).is_err());
207        assert!(decode_varint(&[0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff]).is_err());
208        assert!(decode_varint(&[0xff, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]).is_err());
209    }
210}