1pub struct ConstWriter<'a> {
3 buf: &'a mut [u8],
4 pos: usize,
5}
6
7impl<'a> ConstWriter<'a> {
8 pub const fn new(buf: &'a mut [u8]) -> Self {
9 Self { buf, pos: 0 }
10 }
11
12 pub const fn write_bytes(&mut self, bytes: &[u8]) {
13 let mut i = 0;
14 while i < bytes.len() {
15 self.buf[self.pos] = bytes[i];
16 self.pos += 1;
17 i += 1;
18 }
19 }
20
21 pub const fn write_u16_le(&mut self, v: u16) {
22 self.write_bytes(&v.to_le_bytes());
23 }
24
25 pub const fn write_u64_le(&mut self, v: u64) {
26 self.write_bytes(&v.to_le_bytes());
27 }
28
29 #[allow(clippy::cast_possible_truncation)]
30 pub const fn write_str(&mut self, s: &str) {
31 let len = s.len() as u16;
32 self.write_u16_le(len);
33 self.write_bytes(s.as_bytes());
34 }
35
36 pub const fn write_str_opt(&mut self, s: Option<&str>) {
37 match s {
38 Some(s) => {
39 self.write_bytes(&[1]);
40 self.write_str(s);
41 }
42 None => self.write_bytes(&[0]),
43 }
44 }
45}
46
47pub struct ConstReader<'a> {
52 buf: &'a [u8],
53 pos: usize,
54}
55
56impl<'a> ConstReader<'a> {
57 #[must_use]
58 pub const fn new(buf: &'a [u8]) -> Self {
59 Self { buf, pos: 0 }
60 }
61
62 pub const fn read_bytes(&mut self, n: usize) -> Option<&'a [u8]> {
63 let Some((_, rest)) = self.buf.split_at_checked(self.pos) else {
64 return None;
65 };
66 let Some((head, _)) = rest.split_at_checked(n) else {
67 return None;
68 };
69 self.pos += n;
70 Some(head)
71 }
72
73 pub const fn read_u16_le(&mut self) -> Option<u16> {
74 let Some(bytes) = self.read_bytes(2) else {
75 return None;
76 };
77 Some(u16::from_le_bytes([bytes[0], bytes[1]]))
78 }
79
80 pub const fn read_u64_le(&mut self) -> Option<u64> {
81 let Some(bytes) = self.read_bytes(8) else {
82 return None;
83 };
84 Some(u64::from_le_bytes([
85 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
86 ]))
87 }
88
89 pub const fn read_str(&mut self) -> Option<&'a str> {
90 let Some(len) = self.read_u16_le() else {
91 return None;
92 };
93 let Some(bytes) = self.read_bytes(len as usize) else {
94 return None;
95 };
96 match std::str::from_utf8(bytes) {
97 Ok(s) => Some(s),
98 Err(_) => None,
99 }
100 }
101
102 #[allow(clippy::option_option)]
106 pub const fn read_str_opt(&mut self) -> Option<Option<&'a str>> {
107 let Some(tag) = self.read_bytes(1) else {
108 return None;
109 };
110 match tag[0] {
111 0 => Some(None),
112 1 => match self.read_str() {
113 Some(s) => Some(Some(s)),
114 None => None,
115 },
116 _ => None,
117 }
118 }
119
120 pub const fn skip(&mut self, n: usize) -> Option<()> {
121 match self.read_bytes(n) {
122 Some(_) => Some(()),
123 None => None,
124 }
125 }
126}