zenoh_codec/core/
zint.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14use zenoh_buffers::{
15    reader::{DidntRead, Reader},
16    writer::{DidntWrite, Writer},
17};
18
19use crate::{LCodec, RCodec, WCodec, Zenoh080, Zenoh080Bounded};
20
21const VLE_LEN_MAX: usize = vle_len(u64::MAX);
22
23const fn vle_len(x: u64) -> usize {
24    const B1: u64 = u64::MAX << 7;
25    const B2: u64 = u64::MAX << (7 * 2);
26    const B3: u64 = u64::MAX << (7 * 3);
27    const B4: u64 = u64::MAX << (7 * 4);
28    const B5: u64 = u64::MAX << (7 * 5);
29    const B6: u64 = u64::MAX << (7 * 6);
30    const B7: u64 = u64::MAX << (7 * 7);
31    const B8: u64 = u64::MAX << (7 * 8);
32
33    if (x & B1) == 0 {
34        1
35    } else if (x & B2) == 0 {
36        2
37    } else if (x & B3) == 0 {
38        3
39    } else if (x & B4) == 0 {
40        4
41    } else if (x & B5) == 0 {
42        5
43    } else if (x & B6) == 0 {
44        6
45    } else if (x & B7) == 0 {
46        7
47    } else if (x & B8) == 0 {
48        8
49    } else {
50        9
51    }
52}
53
54impl LCodec<u64> for Zenoh080 {
55    fn w_len(self, x: u64) -> usize {
56        vle_len(x)
57    }
58}
59
60impl LCodec<usize> for Zenoh080 {
61    fn w_len(self, x: usize) -> usize {
62        self.w_len(x as u64)
63    }
64}
65
66impl LCodec<u32> for Zenoh080 {
67    fn w_len(self, x: u32) -> usize {
68        self.w_len(x as u64)
69    }
70}
71
72impl LCodec<u16> for Zenoh080 {
73    fn w_len(self, x: u16) -> usize {
74        self.w_len(x as u64)
75    }
76}
77
78impl LCodec<u8> for Zenoh080 {
79    fn w_len(self, _: u8) -> usize {
80        1
81    }
82}
83
84// u8
85impl<W> WCodec<u8, &mut W> for Zenoh080
86where
87    W: Writer,
88{
89    type Output = Result<(), DidntWrite>;
90
91    fn write(self, writer: &mut W, x: u8) -> Self::Output {
92        writer.write_u8(x)
93    }
94}
95
96impl<R> RCodec<u8, &mut R> for Zenoh080
97where
98    R: Reader,
99{
100    type Error = DidntRead;
101
102    fn read(self, reader: &mut R) -> Result<u8, Self::Error> {
103        reader.read_u8()
104    }
105}
106
107// u64
108impl<W> WCodec<u64, &mut W> for Zenoh080
109where
110    W: Writer,
111{
112    type Output = Result<(), DidntWrite>;
113
114    fn write(self, writer: &mut W, mut x: u64) -> Self::Output {
115        let write = move |buffer: &mut [u8]| {
116            let mut len = 0;
117            while (x & !0x7f_u64) != 0 {
118                // SAFETY: buffer is guaranteed to be VLE_LEN long where VLE_LEN is
119                //         the maximum number of bytes a VLE can take once encoded.
120                //         I.e.: x is shifted 7 bits to the right every iteration,
121                //         the loop is at most VLE_LEN iterations.
122                unsafe {
123                    *buffer.get_unchecked_mut(len) = (x as u8) | 0x80_u8;
124                }
125                len += 1;
126                x >>= 7;
127            }
128            // In case len == VLE_LEN then all the bits have already been written in the latest iteration.
129            // Else we haven't written all the necessary bytes yet.
130            if len != VLE_LEN_MAX {
131                // SAFETY: buffer is guaranteed to be VLE_LEN long where VLE_LEN is
132                //         the maximum number of bytes a VLE can take once encoded.
133                //         I.e.: x is shifted 7 bits to the right every iteration,
134                //         the loop is at most VLE_LEN iterations.
135                unsafe {
136                    *buffer.get_unchecked_mut(len) = x as u8;
137                }
138                len += 1;
139            }
140            // The number of written bytes
141            len
142        };
143        // SAFETY: write algorithm guarantees than returned length is lesser than or equal to
144        // `VLE_LEN_MAX`.
145        unsafe { writer.with_slot(VLE_LEN_MAX, write)? };
146        Ok(())
147    }
148}
149
150impl<R> RCodec<u64, &mut R> for Zenoh080
151where
152    R: Reader,
153{
154    type Error = DidntRead;
155
156    fn read(self, reader: &mut R) -> Result<u64, Self::Error> {
157        let mut b = reader.read_u8()?;
158
159        let mut v = 0;
160        let mut i = 0;
161        // 7 * VLE_LEN is beyond the maximum number of shift bits
162        while (b & 0x80_u8) != 0 && i != 7 * (VLE_LEN_MAX - 1) {
163            v |= ((b & 0x7f_u8) as u64) << i;
164            b = reader.read_u8()?;
165            i += 7;
166        }
167        v |= (b as u64) << i;
168        Ok(v)
169    }
170}
171
172// Derive impls
173macro_rules! uint_impl {
174    ($uint:ty) => {
175        impl<W> WCodec<$uint, &mut W> for Zenoh080
176        where
177            W: Writer,
178        {
179            type Output = Result<(), DidntWrite>;
180
181            fn write(self, writer: &mut W, x: $uint) -> Self::Output {
182                self.write(writer, x as u64)
183            }
184        }
185
186        impl<R> RCodec<$uint, &mut R> for Zenoh080
187        where
188            R: Reader,
189        {
190            type Error = DidntRead;
191
192            fn read(self, reader: &mut R) -> Result<$uint, Self::Error> {
193                let x: u64 = self.read(reader)?;
194                Ok(x as $uint)
195            }
196        }
197    };
198}
199
200uint_impl!(u16);
201uint_impl!(u32);
202uint_impl!(usize);
203
204macro_rules! uint_ref_impl {
205    ($uint:ty) => {
206        impl<W> WCodec<&$uint, &mut W> for Zenoh080
207        where
208            W: Writer,
209        {
210            type Output = Result<(), DidntWrite>;
211
212            fn write(self, writer: &mut W, x: &$uint) -> Self::Output {
213                self.write(writer, *x)
214            }
215        }
216    };
217}
218
219uint_ref_impl!(u8);
220uint_ref_impl!(u16);
221uint_ref_impl!(u32);
222uint_ref_impl!(u64);
223uint_ref_impl!(usize);
224
225// Encode unsigned integer and verify that the size boundaries are respected
226macro_rules! zint_impl_codec {
227    ($zint:ty, $bound:ty) => {
228        impl<W> WCodec<$zint, &mut W> for Zenoh080Bounded<$bound>
229        where
230            W: Writer,
231        {
232            type Output = Result<(), DidntWrite>;
233
234            fn write(self, writer: &mut W, x: $zint) -> Self::Output {
235                if (x as u64 & !(<$bound>::MAX as u64)) != 0 {
236                    return Err(DidntWrite);
237                }
238                Zenoh080.write(writer, x as u64)
239            }
240        }
241
242        impl<R> RCodec<$zint, &mut R> for Zenoh080Bounded<$bound>
243        where
244            R: Reader,
245        {
246            type Error = DidntRead;
247
248            fn read(self, reader: &mut R) -> Result<$zint, Self::Error> {
249                let x: u64 = Zenoh080.read(reader)?;
250                if (x & !(<$bound>::MAX as u64)) != 0 {
251                    return Err(DidntRead);
252                }
253                Ok(x as $zint)
254            }
255        }
256    };
257}
258macro_rules! zint_impl {
259    ($zint:ty) => {
260        zint_impl_codec!($zint, u8);
261        zint_impl_codec!($zint, u16);
262        zint_impl_codec!($zint, u32);
263        zint_impl_codec!($zint, u64);
264        zint_impl_codec!($zint, usize);
265    };
266}
267
268zint_impl!(u8);
269zint_impl!(u16);
270zint_impl!(u32);
271zint_impl!(u64);
272zint_impl!(usize);
273
274// const MAX_LEN: usize = 9;
275// const VLE_THR: u64 = 0xf8; // 248
276// impl<W> WCodec<u64, &mut W> for Zenoh080
277// where
278//     W: Writer,
279// {
280//     type Output = Result<(), DidntWrite>;
281//     fn write(self, writer: &mut W, mut x: u64) -> Self::Output {
282//         writer.with_slot(MAX_LEN, move |into| {
283//             if x < VLE_THR {
284//                 into[0] = x as u8;
285//                 return 1;
286//             }
287//             x -= VLE_THR - 1;
288//             // SAFETY
289//             // The `if x < VLE_THR` check at the beginning followed by `x -= VLE_THR - 1`
290//             // guarantees at this point that `x` is never `0`. Since `x` is 64bit,
291//             // then `n` is guaranteed to have a value between 1 and 8, both inclusives.
292//             // `into` is guaranteed to be exactly 9 bytes long. Therefore, copying at most
293//             // 8 bytes with a pointer offset of 1 is actually safe.
294//             let n = 8 - (x.leading_zeros() / 8) as usize;
295//             unsafe {
296//                 core::ptr::copy_nonoverlapping(
297//                     x.to_le_bytes().as_ptr(),
298//                     into.as_mut_ptr().offset(1),
299//                     n,
300//                 )
301//             }
302//             into[0] = VLE_THR as u8 | (n - 1) as u8;
303//             1 + n
304//         })
305//     }
306// }
307
308// impl<R> RCodec<u64, &mut R> for Zenoh080
309// where
310//     R: Reader,
311// {
312//     type Error = DidntRead;
313//     fn read(self, reader: &mut R) -> Result<u64, Self::Error> {
314//         let b = reader.read_u8()?;
315//         if b < (VLE_THR as u8) {
316//             return Ok(b as u64);
317//         }
318//         let n = (1 + (b & !VLE_THR as u8)) as usize;
319//         let mut u64: [u8; 8] = 0u64.to_le_bytes();
320//         reader.read_exact(&mut u64[0..n])?;
321//         let u64 = u64::from_le_bytes(u64);
322//         Ok(u64.saturating_add(VLE_THR - 1))
323//     }
324// }
325
326// mod tests {
327//     #[test]
328//     fn u64_overhead() {
329//         use crate::{WCodec, Zenoh080};
330//         use zenoh_buffers::{
331//             reader::{HasReader, Reader},
332//             writer::HasWriter,
333//         };
334
335//         fn overhead(x: u64) -> usize {
336//             let codec = Zenoh080::new();
337//             let mut b = vec![];
338//             let mut w = b.writer();
339//             codec.write(&mut w, x).unwrap();
340//             let r = b.reader().remaining();
341//             println!("{} {}", x, r);
342//             r
343//         }
344
345//         assert_eq!(overhead(247), 1);
346//         assert_eq!(overhead(248), 2);
347//         assert_eq!(overhead(502), 2);
348//         assert_eq!(overhead(503), 3);
349//         assert_eq!(overhead(65_782), 3);
350//         assert_eq!(overhead(65_783), 4);
351//         assert_eq!(overhead(16_777_462), 4);
352//         assert_eq!(overhead(16_777_463), 5);
353//         assert_eq!(overhead(4_294_967_542), 5);
354//         assert_eq!(overhead(4_294_967_543), 6);
355//         assert_eq!(overhead(1_099_511_628_022), 6);
356//         assert_eq!(overhead(1_099_511_628_023), 7);
357//         assert_eq!(overhead(281_474_976_710_902), 7);
358//         assert_eq!(overhead(281_474_976_710_903), 8);
359//         assert_eq!(overhead(72_057_594_037_928_182), 8);
360//         assert_eq!(overhead(72_057_594_037_928_183), 9);
361//         assert_eq!(overhead(u64::MAX), 9);
362//     }
363// }
364
365// macro_rules! non_zero_array {
366//     ($($i: expr,)*) => {
367//         [$(match NonZeroU8::new($i) {Some(x) => x, None => panic!("Attempted to place 0 in an array of non-zeros literal")}),*]
368//     };
369// }
370
371// impl Zenoh080 {
372//     pub const fn preview_length(&self, x: u64) -> NonZeroU8 {
373//         let x = match NonZeroU64::new(x) {
374//             Some(x) => x,
375//             None => {
376//                 return unsafe { NonZeroU8::new_unchecked(1) };
377//             }
378//         };
379//         let needed_bits = u64::BITS - x.leading_zeros();
380//         const LENGTH: [NonZeroU8; 65] = non_zero_array![
381//             1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
382//             5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9,
383//             9, 9, 9, 9, 9, 9, 9,
384//         ];
385//         LENGTH[needed_bits as usize]
386//     }
387// }
388
389// impl<W> WCodec<u64, &mut W> for Zenoh080
390// where
391//     W: Writer,
392// {
393//     type Output = Result<(), DidntWrite>;
394
395//     fn write(self, writer: &mut W, x: u64) -> Self::Output {
396//         const VLE_LEN: usize = 9;
397//         const VLE_MASK: [u8; VLE_LEN] = [
398//             0b11111111, // This is padding to avoid needless subtractions on index access
399//             0, 0b00000001, 0b00000011, 0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111,
400//         ];
401//         const VLE_SHIFT: [u8; 65] = [
402//             1, // This is padding to avoid needless subtractions on index access
403//             1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5,
404//             5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 0, 0,
405//             0, 0, 0, 0, 0, 0,
406//         ];
407
408//         writer.with_slot(VLE_LEN, move |buffer| {
409//             // since leading_zeros will jump conditionally on 0 anyway (`asm {bsr 0}` is UB), might as well jump to return
410//             let x = match NonZeroU64::new(x) {
411//                 Some(x) => x,
412//                 None => {
413//                     buffer[0] = 0;
414//                     return 1;
415//                 }
416//             };
417
418//             let needed_bits = u64::BITS - x.leading_zeros();
419//             let payload_size = VLE_SHIFT[needed_bits as usize];
420//             let shift_payload = payload_size == 0;
421//             let mut x: u64 = x.into();
422//             x <<= payload_size;
423//             let serialized = x.to_le_bytes();
424
425//             unsafe {
426//                 ptr::copy_nonoverlapping(
427//                     serialized.as_ptr(),
428//                     buffer.as_mut_ptr().offset(shift_payload as isize),
429//                     u64::BITS as usize / 8,
430//                 )
431//             };
432
433//             let needed_bytes = payload_size as usize;
434//             buffer[0] |= VLE_MASK[needed_bytes];
435//             if shift_payload {
436//                 VLE_LEN
437//             } else {
438//                 needed_bytes
439//             }
440//         })?;
441
442//         Ok(())
443//     }
444// }
445
446// impl<W> WCodec<&u64, &mut W> for Zenoh080
447// where
448//     W: Writer,
449// {
450//     type Output = Result<(), DidntWrite>;
451
452//     fn write(self, writer: &mut W, x: &u64) -> Self::Output {
453//         self.write(writer, *x)
454//     }
455// }
456
457// impl<R> RCodec<u64, &mut R> for Zenoh080
458// where
459//     R: Reader,
460// {
461//     type Error = DidntRead;
462
463//     fn read(self, reader: &mut R) -> Result<u64, Self::Error> {
464//         let mut buffer = [0; 8];
465//         buffer[0] = reader.read_u8()?;
466
467//         // GCC: `__builtin_ctz(~buffer[0])`, clang: `__tzcnt_u64(~buffer[0])`
468//         let byte_count = (buffer[0].trailing_ones()) as usize;
469//         if byte_count == 0 {
470//             return Ok(u64::from_le_bytes(buffer) >> 1);
471//         }
472
473//         let shift_payload = (byte_count == 8) as usize; // branches are evil
474//         let shift_payload_multiplier = 1 - shift_payload;
475
476//         let len = byte_count + shift_payload_multiplier;
477//         reader.read_exact(&mut buffer[shift_payload_multiplier..len])?;
478
479//         // the shift also removes the mask
480//         Ok(u64::from_le_bytes(buffer) >> ((byte_count + 1) * shift_payload_multiplier) as u32)
481//     }
482// }
483
484// // usize
485// impl<W> WCodec<usize, &mut W> for Zenoh080
486// where
487//     W: Writer,
488// {
489//     type Output = Result<(), DidntWrite>;
490
491//     fn write(self, writer: &mut W, x: usize) -> Self::Output {
492//         let x: u64 = x.try_into().map_err(|_| DidntWrite)?;
493//         self.write(writer, x)
494//     }
495// }
496
497// impl<R> RCodec<usize, &mut R> for Zenoh080
498// where
499//     R: Reader,
500// {
501//     type Error = DidntRead;
502
503//     fn read(self, reader: &mut R) -> Result<usize, Self::Error> {
504//         let x: u64 = <Self as RCodec<u64, &mut R>>::read(self, reader)?;
505//         x.try_into().map_err(|_| DidntRead)
506//     }
507// }
508
509// #[cfg(test)]
510// mod test {
511//     #[test]
512//     fn u64_fuzz() {
513//         use crate::*;
514//         use rand::Rng;
515//         use zenoh_buffers::{reader::HasReader, writer::HasWriter};
516
517//         const NUM: usize = 1_000;
518//         const LIMIT: [u64; 4] = [u8::MAX as u64, u16::MAX as u64, u32::MAX as u64, u64::MAX];
519
520//         let codec = Zenoh080::new();
521//         let mut rng = rand::thread_rng();
522
523//         for l in LIMIT.iter() {
524//             let mut values = Vec::with_capacity(NUM);
525//             let mut buffer = vec![];
526
527//             let mut writer = buffer.writer();
528
529//             for _ in 0..NUM {
530//                 let x: u64 = rng.gen_range(0..=*l);
531//                 values.push(x);
532//                 codec.write(&mut writer, x).unwrap();
533//             }
534
535//             let mut reader = buffer.reader();
536
537//             for x in values.drain(..).take(NUM) {
538//                 let y: u64 = codec.read(&mut reader).unwrap();
539//                 println!("{x} {y}");
540//                 assert_eq!(x, y);
541//             }
542
543//             assert!(reader.is_empty());
544//         }
545//     }
546// }