sark_http/field/text/percent/
decoder.rs1use core::{mem, ops, ptr};
2
3use crate::field::text::percent::{octet, scan, utf8};
4
5#[derive(Debug)]
6pub enum Error {
7 Bounds {
8 capacity: usize,
9 source: ops::Range<usize>,
10 destination: usize,
11 },
12}
13
14pub struct Decoder<'a> {
15 bytes: &'a mut [u8],
16 read: usize,
17 start: usize,
18 written: usize,
19}
20
21impl<'a> Decoder<'a> {
22 pub fn new(bytes: &'a mut [u8], src: ops::Range<usize>, dst: usize) -> Result<Self, Error> {
23 let capacity = bytes.len();
24 let Some(read) = src.start.checked_sub(dst).filter(|_| src.start <= src.end) else {
25 return Err(Error::Bounds {
26 capacity,
27 source: src,
28 destination: dst,
29 });
30 };
31 let Some(bytes) = bytes.get_mut(dst..src.end) else {
32 return Err(Error::Bounds {
33 capacity,
34 source: src,
35 destination: dst,
36 });
37 };
38 Ok(Self {
39 bytes,
40 read,
41 start: dst,
42 written: 0,
43 })
44 }
45
46 pub fn decode(mut self) -> Written {
49 let mut utf8 = utf8::Utf8::new();
50 while self.read < self.bytes.len() {
51 let byte = self.bytes[self.read];
52 let rest = &self.bytes[self.read + 1..];
53 let literal = if byte == b'%' || !byte.is_ascii() {
54 0
55 } else {
56 1 + scan::Scan::new(rest).literal()
57 };
58 if literal != 0 && utf8.is_ready() {
59 self.copy(literal);
60 continue;
61 }
62 let (byte, consumed) = if literal != 0 || byte != b'%' {
63 (byte, 1)
64 } else {
65 rest.first()
66 .copied()
67 .zip(rest.get(1).copied())
68 .and_then(|(high, low)| octet::decode(high, low))
69 .map_or((byte, 1), |byte| (byte, 3))
70 };
71 utf8.push(self.bytes, &mut self.written, byte);
72 self.read += consumed;
73 }
74 utf8.finish(self.bytes, &mut self.written);
75 Written::new(self.start..self.start + self.written)
76 }
77
78 fn copy(&mut self, len: usize) {
79 unsafe {
83 let bytes = self.bytes.as_mut_ptr();
84 ptr::copy(bytes.add(self.read), bytes.add(self.written), len);
85 }
86 self.read += len;
87 self.written += len;
88 }
89}
90
91const _: () = assert!(
92 mem::size_of::<Decoder<'_>>() == mem::size_of::<&mut [u8]>() + 3 * mem::size_of::<usize>()
93);
94
95pub struct Written {
98 range: ops::Range<usize>,
99}
100
101impl Written {
102 const fn new(range: ops::Range<usize>) -> Self {
103 Self { range }
104 }
105
106 pub fn range(self) -> ops::Range<usize> {
107 self.range
108 }
109}
110
111const _: () = assert!(size_of::<Written>() == 2 * size_of::<usize>());