Skip to main content

sark_core/http/codec/encode/
wire.rs

1use o3::buffer::{ByteSink, Owned, Shared};
2
3pub struct Wire;
4
5impl Wire {
6    pub const fn decimal_len(mut n: usize) -> usize {
7        let mut len = 1;
8        while n >= 10 {
9            n /= 10;
10            len += 1;
11        }
12        len
13    }
14
15    pub fn write_dec(n: usize, buf: &mut [u8]) -> usize {
16        let len = Self::decimal_len(n);
17        let mut n = n;
18        let mut i = len;
19        loop {
20            i -= 1;
21            buf[i] = b'0' + (n % 10) as u8;
22            n /= 10;
23            if i == 0 {
24                return len;
25            }
26        }
27    }
28
29    pub fn write_hex(n: usize, buf: &mut [u8; 16]) -> usize {
30        if n == 0 {
31            buf[0] = b'0';
32            return 1;
33        }
34        let mut i = 16;
35        let mut val = n;
36        while val > 0 {
37            i -= 1;
38            buf[i] = b"0123456789abcdef"[val & 0xf];
39            val >>= 4;
40        }
41        buf.copy_within(i..16, 0);
42        16 - i
43    }
44
45    pub fn chunk_prefix(size: usize) -> ([u8; 18], usize) {
46        let mut hex = [0u8; 16];
47        let hex_len = Self::write_hex(size, &mut hex);
48        let mut out = [0u8; 18];
49        out[..hex_len].copy_from_slice(&hex[..hex_len]);
50        out[hex_len] = b'\r';
51        out[hex_len + 1] = b'\n';
52        (out, hex_len + 2)
53    }
54
55    pub fn chunk_frame(body: Shared) -> Shared {
56        let (prefix, prefix_len) = Self::chunk_prefix(body.len());
57        let capacity = prefix_len + body.len() + 2;
58        match Owned::try_build_exact(capacity, |out| {
59            out.write_slices([&prefix[..prefix_len], &body, b"\r\n"])
60        }) {
61            Ok(out) => out.freeze(),
62            Err(_) => {
63                let mut out = Vec::with_capacity(capacity);
64                match out.write_slices([&prefix[..prefix_len], &body, b"\r\n"]) {
65                    Ok(()) => Shared::from(out),
66                    Err(error) => match error {},
67                }
68            }
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::Wire;
76
77    #[test]
78    fn decimal_writer_matches_usize_display() {
79        for value in [0, 1, 9, 10, 99, 100, 999, 1_000, usize::MAX] {
80            let expected = value.to_string();
81            let mut out = [0u8; 20];
82            let written = Wire::write_dec(value, &mut out);
83            assert_eq!(written, Wire::decimal_len(value));
84            assert_eq!(&out[..written], expected.as_bytes());
85        }
86    }
87}