1use core::borrow::{Borrow, BorrowMut};
2
3#[derive(Clone)]
38pub struct Ipv4Options {
39 pub(crate) len: u8,
40 pub(crate) buf: [u8; 40],
41}
42
43impl Ipv4Options {
44 pub const MAX_LEN: u8 = 40;
46
47 #[inline]
49 pub fn new() -> Ipv4Options {
50 Ipv4Options {
51 len: 0,
52 buf: [0; 40],
53 }
54 }
55
56 #[inline]
58 pub fn as_slice(&self) -> &[u8] {
59 unsafe { core::slice::from_raw_parts(self.buf.as_ptr(), self.len.into()) }
60 }
61
62 #[inline]
64 pub fn as_mut_slice(&mut self) -> &mut [u8] {
65 unsafe { core::slice::from_raw_parts_mut(self.buf.as_mut_ptr(), self.len.into()) }
66 }
67
68 #[inline]
70 pub fn len(&self) -> usize {
71 usize::from(self.len)
72 }
73
74 #[inline]
76 pub fn len_u8(&self) -> u8 {
77 self.len
78 }
79
80 #[inline]
82 pub fn is_empty(&self) -> bool {
83 self.len == 0
84 }
85}
86
87impl TryFrom<&[u8]> for Ipv4Options {
88 type Error = crate::err::ipv4::BadOptionsLen;
89
90 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
91 if value.len() <= 40 && value.len() % 4 == 0 {
92 let mut result = Ipv4Options {
93 len: value.len() as u8,
94 buf: [0; 40],
95 };
96 unsafe {
97 core::ptr::copy_nonoverlapping(
99 value.as_ptr(),
100 result.buf.as_mut_ptr(),
101 value.len(),
102 );
103 }
104 Ok(result)
105 } else {
106 Err(Self::Error {
107 bad_len: value.len(),
108 })
109 }
110 }
111}
112
113impl Default for Ipv4Options {
114 #[inline]
115 fn default() -> Self {
116 Self {
117 len: 0,
118 buf: [0; 40],
119 }
120 }
121}
122
123impl core::fmt::Debug for Ipv4Options {
124 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125 self.as_slice().fmt(f)
126 }
127}
128
129impl PartialEq for Ipv4Options {
130 fn eq(&self, other: &Self) -> bool {
131 self.as_slice() == other.as_slice()
132 }
133}
134impl Eq for Ipv4Options {}
135
136impl core::hash::Hash for Ipv4Options {
137 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
138 self.as_slice().hash(state);
139 }
140}
141
142impl core::cmp::PartialOrd for Ipv4Options {
143 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
144 Some(self.as_slice().cmp(other.as_slice()))
145 }
146}
147
148impl core::cmp::Ord for Ipv4Options {
149 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
150 self.as_slice().cmp(other.as_slice())
151 }
152}
153
154impl From<[u8; 0]> for Ipv4Options {
155 #[inline]
156 fn from(_: [u8; 0]) -> Self {
157 Ipv4Options {
158 len: 0,
159 buf: [0; 40],
160 }
161 }
162}
163
164macro_rules! from_static_array {
165 ($x:expr) => {
166 impl From<[u8; $x]> for Ipv4Options {
167 #[inline]
168 fn from(values: [u8; $x]) -> Self {
169 let mut result = Ipv4Options {
170 len: $x,
171 buf: [0; 40],
172 };
173 let r = result.buf.as_mut_ptr() as *mut [u8; $x];
174 unsafe {
175 *r = values;
176 }
177 result
178 }
179 }
180 };
181}
182
183from_static_array!(4);
184from_static_array!(8);
185from_static_array!(12);
186from_static_array!(16);
187from_static_array!(20);
188from_static_array!(24);
189from_static_array!(28);
190from_static_array!(32);
191from_static_array!(36);
192
193impl From<[u8; 40]> for Ipv4Options {
194 fn from(values: [u8; 40]) -> Self {
195 Ipv4Options {
196 len: 40,
197 buf: values,
198 }
199 }
200}
201
202impl AsRef<Ipv4Options> for Ipv4Options {
203 fn as_ref(&self) -> &Ipv4Options {
204 self
205 }
206}
207
208impl AsRef<[u8]> for Ipv4Options {
209 fn as_ref(&self) -> &[u8] {
210 self.as_slice()
211 }
212}
213
214impl AsMut<Ipv4Options> for Ipv4Options {
215 fn as_mut(&mut self) -> &mut Ipv4Options {
216 self
217 }
218}
219
220impl AsMut<[u8]> for Ipv4Options {
221 fn as_mut(&mut self) -> &mut [u8] {
222 self.as_mut_slice()
223 }
224}
225
226impl Borrow<[u8]> for Ipv4Options {
227 fn borrow(&self) -> &[u8] {
228 self.as_slice()
229 }
230}
231
232impl BorrowMut<[u8]> for Ipv4Options {
233 fn borrow_mut(&mut self) -> &mut [u8] {
234 self.as_mut_slice()
235 }
236}
237
238impl core::ops::Deref for Ipv4Options {
239 type Target = [u8];
240
241 #[inline]
242 fn deref(&self) -> &[u8] {
243 self.as_slice()
244 }
245}
246
247impl core::ops::DerefMut for Ipv4Options {
248 #[inline]
249 fn deref_mut(&mut self) -> &mut [u8] {
250 self.as_mut_slice()
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257 use crate::test_gens::*;
258 use proptest::prelude::*;
259 use std::format;
260
261 #[test]
262 fn new() {
263 let actual = Ipv4Options::new();
264 assert_eq!(actual.len, 0);
265 assert_eq!(actual.buf, [0; 40]);
266 }
267
268 #[test]
269 fn is_empty() {
270 {
271 let actual = Ipv4Options::new();
272 assert!(actual.is_empty());
273 }
274 {
275 let actual: Ipv4Options = [1, 2, 3, 4].into();
276 assert_eq!(false, actual.is_empty());
277 }
278 }
279
280 #[test]
281 fn try_from() {
282 const DATA: [u8; 48] = [
283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
284 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
285 47, 48,
286 ];
287
288 for len_div_4 in 0usize..=10 {
290 let mut actual = Ipv4Options::try_from(&DATA[..len_div_4 * 4]).unwrap();
291 assert_eq!(actual.as_slice(), &DATA[..len_div_4 * 4]);
292 assert_eq!(actual.as_mut_slice(), &DATA[..len_div_4 * 4]);
293 assert_eq!(actual.len_u8(), (len_div_4 * 4) as u8);
294 assert_eq!(actual.len(), len_div_4 * 4);
295 }
296
297 use crate::err::ipv4::BadOptionsLen;
299 for len in 0usize..48 {
300 if (len % 4 != 0) || len > 40 {
301 assert_eq!(
302 Err(BadOptionsLen { bad_len: len }),
303 Ipv4Options::try_from(&DATA[..len])
304 )
305 }
306 }
307 }
308
309 #[test]
310 fn default() {
311 let actual: Ipv4Options = Default::default();
312 assert_eq!(actual.len, 0);
313 assert_eq!(actual.buf, [0; 40]);
314 }
315
316 proptest! {
317 #[test]
318 fn clone_dbg(options in ipv4_options_any()) {
319 assert_eq!(
320 format!("{:?}", options),
321 format!("{:?}", options.clone().as_slice())
322 );
323 }
324 }
325
326 proptest! {
327 #[test]
328 fn eq_partial_eq(
329 a in ipv4_options_any(),
330 b in ipv4_options_any()
331 ) {
332 assert_eq!(a.eq(&b), a.as_slice().eq(b.as_slice()));
333 assert_eq!(a == b, a.as_slice() == b.as_slice());
334 }
335 }
336
337 proptest! {
338 #[test]
339 fn hash(
340 options in ipv4_options_any()
341 ) {
342 use std::collections::hash_map::DefaultHasher;
343 use core::hash::{Hash, Hasher};
344 let a = {
345 let mut hasher = DefaultHasher::new();
346 options.hash(&mut hasher);
347 hasher.finish()
348 };
349 let b = {
350 let mut hasher = DefaultHasher::new();
351 options.hash(&mut hasher);
352 hasher.finish()
353 };
354 assert_eq!(a, b);
355 }
356 }
357
358 proptest! {
359 #[test]
360 fn ord_partial_ord(
361 a in ipv4_options_any(),
362 b in ipv4_options_any()
363 ) {
364 assert_eq!(a.cmp(&b), a.as_slice().cmp(&b.as_slice()));
365 assert_eq!(a.partial_cmp(&b), a.as_slice().partial_cmp(&b.as_slice()));
366 }
367 }
368
369 #[test]
370 fn from_0_byte_array() {
371 let options: Ipv4Options = [].into();
372 assert_eq!(&options[..], &[]);
373 }
374
375 macro_rules! from_static_array_test {
376 ($func_name:ident, $x:expr) => {
377 #[test]
378 fn $func_name() {
379 {
380 let options: Ipv4Options = [$x; $x].into();
381 assert_eq!(&options[..], &[$x; $x]);
382 }
383 assert_eq!(&Ipv4Options::from([$x; $x])[..], &[$x; $x]);
384 }
385 };
386 }
387
388 from_static_array_test!(from_arr_4, 4);
389 from_static_array_test!(from_arr_8, 8);
390 from_static_array_test!(from_arr_12, 12);
391 from_static_array_test!(from_arr_16, 16);
392 from_static_array_test!(from_arr_20, 20);
393 from_static_array_test!(from_arr_24, 24);
394 from_static_array_test!(from_arr_28, 28);
395 from_static_array_test!(from_arr_32, 32);
396 from_static_array_test!(from_arr_36, 36);
397 from_static_array_test!(from_arr_40, 40);
398
399 proptest! {
400 #[test]
401 fn as_ref(options in ipv4_options_any()) {
402 {
404 let r: &Ipv4Options = options.as_ref();
405 assert_eq!(r, &options);
406 }
407 {
409 let r: &[u8] = options.as_ref();
410 assert_eq!(r, options.as_slice());
411 }
412 }
413 }
414
415 proptest! {
416 #[test]
417 fn as_mut(options in ipv4_options_any()) {
418 {
420 let mut o = options.clone();
421 let r: &mut Ipv4Options = o.as_mut();
422 if r.len() > 0 {
423 r[0] = 123;
424 assert_eq!(123, o.as_slice()[0]);
425 }
426 }
427 {
429 let mut o = options.clone();
430 let r: &mut [u8] = o.as_mut();
431 if r.len() > 0 {
432 r[0] = 123;
433 assert_eq!(123, o.as_slice()[0]);
434 }
435 }
436 }
437 }
438
439 proptest! {
440 #[test]
441 fn borrow(options in ipv4_options_any()) {
442 {
444 let r: &Ipv4Options = options.borrow();
445 assert_eq!(r, &options);
446 }
447 {
449 let r: &[u8] = options.borrow();
450 assert_eq!(r, options.as_slice());
451 }
452 }
453 }
454
455 proptest! {
456 #[test]
457 fn borrow_mut(options in ipv4_options_any()) {
458 {
460 let mut o = options.clone();
461 let r: &mut Ipv4Options = o.borrow_mut();
462 if r.len() > 0 {
463 r[0] = 123;
464 assert_eq!(123, o.as_slice()[0]);
465 }
466 }
467 {
469 let mut o = options.clone();
470 let r: &mut [u8] = o.borrow_mut();
471 if r.len() > 0 {
472 r[0] = 123;
473 assert_eq!(123, o.as_slice()[0]);
474 }
475 }
476 }
477 }
478
479 #[test]
480 fn deref() {
481 let options: Ipv4Options = [1, 2, 3, 4].into();
482 let s: &[u8] = &options;
483 assert_eq!(s, &[1, 2, 3, 4]);
484 assert_eq!(&options[..], &[1, 2, 3, 4]);
485 }
486
487 #[test]
488 fn deref_mut() {
489 let mut options: Ipv4Options = [1, 2, 3, 4].into();
490 let s: &mut [u8] = &mut options;
491 assert_eq!(s, &[1, 2, 3, 4]);
492 }
493}