rust_leb128/
seq.rs

1use core::mem;
2
3use super::{Sealed, Util, Varint};
4
5macro_rules! const_assert {
6    ($($tt:tt)+) => {
7        const _: () = assert!($($tt)+);
8    };
9}
10
11/// A sequence of [`Varint`][super::int::Varint]s.
12pub trait Seq: Sealed {
13    /// Returns the number of bytes needed to encode the
14    /// integers.
15    fn encoded_len(&self) -> usize;
16}
17
18macro_rules! impl_slice_x8 {
19    ($name:ty) => {
20        impl Sealed for &[$name] {}
21        impl Seq for &[$name] {
22            fn encoded_len(&self) -> usize {
23                let mut sum = 0;
24                for x in *self {
25                    sum += x.to_unsigned().encoded_len();
26                }
27                sum
28            }
29        }
30    };
31}
32impl_slice_x8!(u8);
33impl_slice_x8!(i8);
34
35macro_rules! impl_slice_x16 {
36    ($name:ty) => {
37        impl Sealed for &[$name] {}
38        impl Seq for &[$name] {
39            fn encoded_len(&self) -> usize {
40                let n = (self.len() / 32) * 32;
41                let mut sum = n;
42                let mut iter = self.iter();
43                // LLVM autovectorizes this loop.
44                for &x in (&mut iter).take(n) {
45                    let x: u16 = x.to_unsigned();
46                    if x > 0x7F {
47                        sum += 1;
48                    }
49                    if x > 0x3FFF {
50                        sum += 1;
51                    }
52                }
53                for x in iter {
54                    sum += x.encoded_len();
55                }
56                sum
57            }
58        }
59    };
60}
61impl_slice_x16!(u16);
62impl_slice_x16!(i16);
63
64macro_rules! impl_slice_x32 {
65    ($name:ty) => {
66        impl Sealed for &[$name] {}
67        impl Seq for &[$name] {
68            fn encoded_len(&self) -> usize {
69                let n = (self.len() / 32) * 32;
70                let mut sum = n;
71                let mut iter = self.iter();
72                // LLVM autovectorizes this loop.
73                for &x in (&mut iter).take(n) {
74                    let x: u32 = x.to_unsigned();
75                    if x > 0x7F {
76                        sum += 1;
77                    }
78                    if x > 0x3FFF {
79                        sum += 1;
80                    }
81                    if x > 0x1FFFFF {
82                        sum += 1;
83                    }
84                    if x > 0xFFFFFFF {
85                        sum += 1;
86                    }
87                }
88                for x in iter {
89                    sum += x.encoded_len();
90                }
91                sum
92            }
93        }
94    };
95}
96impl_slice_x32!(u32);
97impl_slice_x32!(i32);
98
99macro_rules! impl_slice_x64 {
100    ($name:ty) => {
101        impl Sealed for &[$name] {}
102        impl Seq for &[$name] {
103            fn encoded_len(&self) -> usize {
104                let n = (self.len() / 32) * 32;
105                let mut sum = n;
106                let mut iter = self.iter();
107                // LLVM autovectorizes this loop.
108                for &x in (&mut iter).take(n) {
109                    let mut x: u64 = x.to_unsigned();
110                    let tmp = if x > 1 << 35 { u64::MAX } else { 0 };
111                    sum += (5 & tmp) as usize;
112                    x >>= 35 & tmp;
113                    if x > 0x7F {
114                        sum += 1;
115                    }
116                    if x > 0x3FFF {
117                        sum += 1;
118                    }
119                    if x > 0x1FFFFF {
120                        sum += 1;
121                    }
122                    if x > 0xFFFFFFF {
123                        sum += 1;
124                    }
125                }
126                for x in iter {
127                    sum += x.encoded_len();
128                }
129                sum
130            }
131        }
132    };
133}
134impl_slice_x64!(u64);
135impl_slice_x64!(i64);
136
137macro_rules! impl_slice_x128 {
138    ($name:ty) => {
139        impl Sealed for &[$name] {}
140        impl Seq for &[$name] {
141            fn encoded_len(&self) -> usize {
142                let mut sum = 0;
143                for x in *self {
144                    sum += x.to_unsigned().encoded_len();
145                }
146                sum
147            }
148        }
149    };
150}
151impl_slice_x128!(u128);
152impl_slice_x128!(i128);
153
154/// # Safety
155///
156/// `Alias` must have the same memory layout as the type that
157/// `Xsize` is implemented for.
158unsafe trait Xsize {
159    type Alias;
160}
161const_assert!(mem::size_of::<usize>() == mem::size_of::<<usize as Xsize>::Alias>(),);
162const_assert!(mem::size_of::<isize>() == mem::size_of::<<isize as Xsize>::Alias>(),);
163
164macro_rules! xsize_impl {
165    ($cfg:literal, $unsigned:ty, $signed:ty) => {
166        #[cfg(target_pointer_width = $cfg)]
167        // SAFETY: `$unsigned` and `usize` have the same memory
168        // layout.
169        unsafe impl Xsize for usize {
170            type Alias = $unsigned;
171        }
172        #[cfg(target_pointer_width = $cfg)]
173        // SAFETY: `$signed` and `isize` have the same memory
174        // layout.
175        unsafe impl Xsize for isize {
176            type Alias = $signed;
177        }
178    };
179}
180xsize_impl!("64", u64, i64);
181xsize_impl!("32", u32, i32);
182xsize_impl!("16", u16, i16);
183
184macro_rules! impl_slice_xsize {
185    ($name:ty) => {
186        impl Sealed for &[$name] {}
187        impl Seq for &[$name] {
188            fn encoded_len(&self) -> usize {
189                let data =
190                    // SAFETY: `$name` and `Xsize::Type` have
191                    // same memory layout.
192                    unsafe { &*(*self as *const [$name] as *const [<$name as Xsize>::Alias]) };
193                data.encoded_len()
194            }
195        }
196    };
197}
198impl_slice_xsize!(usize);
199impl_slice_xsize!(isize);
200
201macro_rules! impl_vec {
202    ($($ty:ty),+ $(,)?) => {
203        $(
204            #[cfg(feature = "alloc")]
205            impl Sealed for ::alloc::vec::Vec<$ty> {}
206
207            #[cfg(feature = "alloc")]
208            #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
209            impl Seq for ::alloc::vec::Vec<$ty> {
210                fn encoded_len(&self) -> usize {
211                    self.as_slice().encoded_len()
212                }
213            }
214        )+
215    }
216}
217impl_vec! {
218    u8, u16, u32, u64, u128, usize,
219    i8, i16, i32, i64, i128, isize,
220}
221
222#[cfg(test)]
223mod tests {
224    use rand::prelude::*;
225
226    use super::*;
227
228    macro_rules! test_encoded_len {
229        ($name:ident, $ty:ty) => {
230            #[test]
231            fn $name() {
232                fn encoded_len(data: &[$ty]) -> usize {
233                    let mut n = 0;
234                    for x in data {
235                        n += x.encoded_len();
236                    }
237                    n
238                }
239                let data = (0..100_000).map(|_| random()).collect::<Vec<$ty>>();
240                let got = data.encoded_len();
241                let want = encoded_len(&data);
242                assert_eq!(got, want);
243            }
244        };
245    }
246    test_encoded_len!(test_encoded_len_usize, usize);
247    test_encoded_len!(test_encoded_len_isize, isize);
248    test_encoded_len!(test_encoded_len_u64, u64);
249    test_encoded_len!(test_encoded_len_i64, i64);
250    test_encoded_len!(test_encoded_len_u32, u32);
251    test_encoded_len!(test_encoded_len_i32, i32);
252    test_encoded_len!(test_encoded_len_u16, u16);
253    test_encoded_len!(test_encoded_len_i16, i16);
254    test_encoded_len!(test_encoded_len_u8, u8);
255    test_encoded_len!(test_encoded_len_i8, i8);
256}