pinecone/
varint.rs

1use serde::{Serialize, Serializer};
2
3/// A wrapper type that exists as a `usize` at rest, but is serialized
4/// to or deserialized from a varint.
5#[derive(Debug)]
6pub struct VarintUsize(pub usize);
7
8impl Serialize for VarintUsize {
9    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
10    where
11        S: Serializer,
12    {
13        let mut buf = Self::new_buf();
14        let used_buf = self.to_buf(&mut buf);
15        serializer.serialize_bytes(used_buf)
16    }
17}
18
19/// Type alias for the largest buffer needed to store
20/// a `usize` varint as bytes
21///
22/// NOTE: This size is different depending on your target
23/// platform! For 32 bit platforms, this will be [u8; 5].
24/// For 64 bit platforms, this will be [u8; 10].
25pub type VarintBuf = [u8; VarintUsize::varint_usize_max()];
26
27impl VarintUsize {
28    pub fn to_buf<'a, 'b>(&'a self, out: &'b mut VarintBuf) -> &'b mut [u8] {
29        let mut value = self.0;
30        for i in 0..Self::varint_usize_max() {
31            out[i] = (value & 0x7F) as u8;
32            value >>= 7;
33            if value != 0 {
34                out[i] |= 0x80;
35            } else {
36                return &mut out[..=i];
37            }
38        }
39        debug_assert_eq!(value, 0);
40        &mut out[..]
41    }
42
43    pub const fn new_buf() -> VarintBuf {
44        [0u8; Self::varint_usize_max()]
45    }
46
47    pub const fn varint_usize_max() -> usize {
48        const BITS_PER_BYTE: usize = 8;
49        const BITS_PER_VARINT_BYTE: usize = 7;
50
51        // How many data bits do we need for a usize on this platform?
52        let bits = core::mem::size_of::<usize>() * BITS_PER_BYTE;
53
54        // We add (BITS_PER_BYTE - 1), to ensure any integer divisions
55        // with a remainder will always add exactly one full byte, but
56        // an evenly divided number of bits will be the same
57        let roundup_bits = bits + (BITS_PER_BYTE - 1);
58
59        // Apply division, using normal "round down" integer division
60        roundup_bits / BITS_PER_VARINT_BYTE
61    }
62}