Skip to main content

sark_http/h1/codec/
numbers.rs

1use std::num::NonZero;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Error {
5    Overflow {
6        current: usize,
7        added: NonZero<usize>,
8    },
9    Capacity {
10        required: NonZero<usize>,
11        actual: usize,
12    },
13}
14
15pub trait Wire {
16    fn decimal_len(self) -> NonZero<usize>;
17
18    /// Encodes once backwards, borrowing only the initialized decimal suffix.
19    fn decimal(self, buf: &mut [u8; 20]) -> &[u8];
20
21    /// Writes the complete decimal at `offset`, returning its exclusive end.
22    /// A rejected range leaves the destination unchanged.
23    fn try_write(self, buf: &mut [u8], offset: usize) -> Result<NonZero<usize>, Error>;
24}
25
26impl Wire for usize {
27    fn decimal_len(mut self) -> NonZero<usize> {
28        let mut len = NonZero::<usize>::MIN;
29        while self >= 10 {
30            self /= 10;
31            len = len.saturating_add(1);
32        }
33        len
34    }
35
36    fn decimal(mut self, buf: &mut [u8; 20]) -> &[u8] {
37        let mut start = buf.len();
38        loop {
39            start -= 1;
40            buf[start] = take(&mut self);
41            if self == 0 {
42                return &buf[start..];
43            }
44        }
45    }
46
47    fn try_write(self, buf: &mut [u8], offset: usize) -> Result<NonZero<usize>, Error> {
48        let width = self.decimal_len();
49        let end = width.checked_add(offset).ok_or(Error::Overflow {
50            current: offset,
51            added: width,
52        })?;
53        let actual = buf.len();
54        let digits = buf.get_mut(offset..end.get()).ok_or(Error::Capacity {
55            required: end,
56            actual,
57        })?;
58        let mut value = self;
59        for digit in digits.iter_mut().rev() {
60            *digit = take(&mut value);
61        }
62        Ok(end)
63    }
64}
65
66fn take(value: &mut usize) -> u8 {
67    let digit = b'0' + (*value % 10) as u8;
68    *value /= 10;
69    digit
70}
71
72const _: () = assert!(usize::BITS <= u64::BITS);