1use std::cell::RefCell;
2
3use crate::v4::error::Result;
4use log::trace;
5
6pub struct Slicer<'de> {
15 input: &'de [u8],
16 input_index: usize,
17}
18
19impl<'de> Slicer<'de> {
20 pub fn new(input: &'de [u8]) -> Self {
22 Slicer {
23 input,
24 input_index: 0,
25 }
26 }
27
28 #[inline]
31 fn parse_unchecked(&mut self, len: usize) -> &'de [u8] {
32 trace!("parse_unchecked");
33 let slice = &self.input[self.input_index..self.input_index + len];
34 self.input_index += len;
35 slice
36 }
37
38 #[inline]
40 fn parse_remainder(&mut self) -> &'de [u8] {
41 trace!("parse_remainder");
42 let slice = &self.input[self.input_index..];
43 self.input_index += slice.len();
44 slice
45 }
46
47 #[inline]
49 pub fn parse(&mut self, len: usize) -> Option<&'de [u8]> {
50 trace!("parse");
51 let slice = self.input.get(self.input_index..self.input_index + len);
52
53 if slice.is_some() {
54 self.input_index += len;
55 }
56
57 slice
58 }
59}
60
61pub struct MessageSlicer<'de> {
67 slicer: RefCell<Slicer<'de>>,
68}
69
70impl<'de> MessageSlicer<'de> {
71 #[inline]
73 pub fn new(input: &'de [u8]) -> Result<Self> {
74 if input.len() < 240 {
75 return Err("Can't decode input less than 240 bytes");
76 }
77
78 Ok(Self {
79 slicer: RefCell::new(Slicer {
80 input,
81 input_index: 0,
82 }),
83 })
84 }
85
86 #[inline]
88 pub fn parse_op(&self) -> &'de [u8] {
89 trace!("parse_op");
90 self.slicer.borrow_mut().parse_unchecked(1)
91 }
92
93 #[inline]
95 pub fn parse_htype(&self) -> &'de [u8] {
96 trace!("parse_htypes");
97 self.slicer.borrow_mut().parse_unchecked(1)
98 }
99
100 #[inline]
102 pub fn parse_hlen(&self) -> &'de [u8] {
103 trace!("parse_hlen");
104 self.slicer.borrow_mut().parse_unchecked(1)
105 }
106
107 #[inline]
109 pub fn parse_hops(&self) -> &'de [u8] {
110 trace!("parse_hops");
111 self.slicer.borrow_mut().parse_unchecked(1)
112 }
113
114 #[inline]
116 pub fn parse_xid(&self) -> &'de [u8] {
117 trace!("parse_xid");
118 self.slicer.borrow_mut().parse_unchecked(4)
119 }
120
121 #[inline]
123 pub fn parse_secs(&self) -> &'de [u8] {
124 trace!("parse_secs");
125 self.slicer.borrow_mut().parse_unchecked(2)
126 }
127
128 #[inline]
130 pub fn parse_flags(&self) -> &'de [u8] {
131 trace!("parse_flags");
132 self.slicer.borrow_mut().parse_unchecked(2)
133 }
134
135 #[inline]
137 pub fn parse_ciaddr(&self) -> &'de [u8] {
138 trace!("parse_ciaddr");
139 self.slicer.borrow_mut().parse_unchecked(4)
140 }
141
142 #[inline]
144 pub fn parse_yiaddr(&self) -> &'de [u8] {
145 trace!("parse_yiaddr");
146 self.slicer.borrow_mut().parse_unchecked(4)
147 }
148
149 #[inline]
151 pub fn parse_siaddr(&self) -> &'de [u8] {
152 trace!("parse_siaddr");
153 self.slicer.borrow_mut().parse_unchecked(4)
154 }
155
156 #[inline]
158 pub fn parse_giaddr(&self) -> &'de [u8] {
159 trace!("parse_giaddr");
160 self.slicer.borrow_mut().parse_unchecked(4)
161 }
162
163 #[inline]
165 pub fn parse_chaddr(&self) -> &'de [u8] {
166 trace!("parse_chaddr");
167 self.slicer.borrow_mut().parse_unchecked(16)
168 }
169
170 #[inline]
172 pub fn parse_sname(&self) -> &'de [u8] {
173 trace!("parse_sname");
174 self.slicer.borrow_mut().parse_unchecked(64)
175 }
176
177 #[inline]
179 pub fn parse_file(&self) -> &'de [u8] {
180 trace!("parse_file");
181 self.slicer.borrow_mut().parse_unchecked(128)
182 }
183
184 #[inline]
186 pub fn parse_magic(&self) -> &'de [u8] {
187 trace!("parse_magic");
188 self.slicer.borrow_mut().parse_unchecked(4)
189 }
190
191 #[inline]
194 pub fn parse_options(&self) -> &'de [u8] {
195 trace!("parse_options");
196 self.slicer.borrow_mut().parse_remainder()
197 }
198}
199
200#[cfg(test)]
203mod tests {
204 use super::*;
205
206 fn init_logger() {
209 let _ = env_logger::builder().is_test(true).try_init();
210 }
211
212 #[test]
213 fn test_message_slicer_with_small_input() {
214 init_logger();
215 let input = &[
216 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8,
218 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
219 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
220 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
221 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
222 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
223 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
224 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
225 2, 3, 4, 5, 6, 7, 8,
226 ];
227 let result = MessageSlicer::new(input);
228 assert!(result.is_err());
229 }
230
231 #[test]
232 fn test_message_slicer_with_large_input() {
233 init_logger();
234 let input = &[
235 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8,
237 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
238 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
239 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
240 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
241 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
242 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
243 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
244 2, 3, 4, 5, 6, 7, 8, 9,
245 ];
246 let result = MessageSlicer::new(input);
247 assert!(result.is_ok());
248 }
249}