tiny_varint/
traits.rs

1/// Generic trait for variable-length integer encoding
2pub trait VarInt: Copy + Sized {
3    /// The corresponding unsigned type used for internal encoding operations
4    type Unsigned: Copy + VarIntOps;
5    
6    /// Convert to the corresponding unsigned type
7    fn to_unsigned(self) -> Self::Unsigned;
8    
9    /// Convert from the corresponding unsigned type
10    fn from_unsigned(value: Self::Unsigned) -> Self;
11    
12    /// Determine how many bytes are needed to encode this value
13    fn varint_size(self) -> usize;
14}
15
16/// Operations trait for unsigned types
17pub trait VarIntOps: Copy + Sized {
18    /// Maximum number of bits for this type
19    const BITS: usize;
20    
21    /// Check if another byte is needed for encoding (value >= 0x80)
22    fn needs_another_byte(self) -> bool;
23    
24    /// Get a byte from the value and set the continuation bit
25    fn get_byte_with_continuation(self) -> u8;
26    
27    /// Get the final byte from the value
28    fn get_final_byte(self) -> u8;
29    
30    /// Shift right by 7 bits
31    fn shift_right_7(self) -> Self;
32    
33    /// Build a value from a byte
34    fn from_byte(byte: u8, shift: usize) -> Self;
35    
36    /// Get the number of leading zeros
37    fn leading_zeros(self) -> usize;
38    
39    /// Bitwise OR operation
40    fn bitor(self, other: Self) -> Self;
41}
42
43// Implement VarIntOps for unsigned types
44macro_rules! impl_varint_ops {
45    ($type:ty, $bits:expr) => {
46        impl VarIntOps for $type {
47            const BITS: usize = $bits;
48            
49            #[inline]
50            fn needs_another_byte(self) -> bool {
51                self >= 0x80
52            }
53            
54            #[inline]
55            fn get_byte_with_continuation(self) -> u8 {
56                (self as u8) | 0x80
57            }
58            
59            #[inline]
60            fn get_final_byte(self) -> u8 {
61                self as u8
62            }
63            
64            #[inline]
65            fn shift_right_7(self) -> Self {
66                self >> 7
67            }
68            
69            #[inline]
70            fn from_byte(byte: u8, shift: usize) -> Self {
71                ((byte & 0x7F) as Self) << ((shift * 7) as u32)
72            }
73            
74            #[inline]
75            fn leading_zeros(self) -> usize {
76                self.leading_zeros() as usize
77            }
78            
79            #[inline]
80            fn bitor(self, other: Self) -> Self {
81                self | other
82            }
83        }
84    };
85}
86
87// Implement VarInt for unsigned types
88macro_rules! impl_unsigned_varint {
89    ($type:ty, $bits:expr) => {
90        impl VarInt for $type {
91            type Unsigned = Self;
92            
93            #[inline]
94            fn to_unsigned(self) -> Self::Unsigned {
95                self
96            }
97            
98            #[inline]
99            fn from_unsigned(value: Self::Unsigned) -> Self {
100                value
101            }
102            
103            #[inline]
104            fn varint_size(self) -> usize {
105                if self == 0 {
106                    return 1;
107                }
108                let bits_needed = Self::Unsigned::BITS - self.leading_zeros();
109                ((bits_needed + 6) / 7) as usize // 7 bits per byte, round up
110            }
111        }
112    };
113}
114
115// Implement VarInt for signed types
116macro_rules! impl_signed_varint {
117    ($type:ty, $unsigned:ty) => {
118        impl VarInt for $type {
119            type Unsigned = $unsigned;
120            
121            #[inline]
122            fn to_unsigned(self) -> Self::Unsigned {
123                self as $unsigned
124            }
125            
126            #[inline]
127            fn from_unsigned(value: Self::Unsigned) -> Self {
128                value as Self
129            }
130            
131            #[inline]
132            fn varint_size(self) -> usize {
133                // For signed types, calculate size based on actual bit pattern
134                let value = self.to_unsigned();
135                
136                if value == 0 {
137                    return 1;
138                }
139                let bits_needed = Self::Unsigned::BITS - value.leading_zeros();
140                ((bits_needed + 6) / 7) as usize
141            }
142        }
143    };
144}
145
146// Implement for all integer types
147impl_varint_ops!(u8, 8);
148impl_varint_ops!(u16, 16);
149impl_varint_ops!(u32, 32);
150impl_varint_ops!(u64, 64);
151impl_varint_ops!(u128, 128);
152
153impl_unsigned_varint!(u8, 8);
154impl_unsigned_varint!(u16, 16);
155impl_unsigned_varint!(u32, 32);
156impl_unsigned_varint!(u64, 64);
157impl_unsigned_varint!(u128, 128);
158
159impl_signed_varint!(i8, u8);
160impl_signed_varint!(i16, u16);
161impl_signed_varint!(i32, u32);
162impl_signed_varint!(i64, u64);
163impl_signed_varint!(i128, u128);