1 use crate::{tcp_option, TcpHeader, TcpOptionElement, TcpOptionWriteError, TcpOptionsIterator};
2 
3 /// Options present in a TCP header.
4 ///
5 /// # Examples (reading)
6 ///
7 /// The underlying bytes can be accessed via the [`TcpOptions::as_slice`] method:
8 ///
9 /// ```
10 /// use etherparse::{
11 ///     TcpOptions,
12 ///     tcp_option::{KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, KIND_END}
13 /// };
14 ///
15 /// let tcp_options = TcpOptions::from([
16 ///     KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, 2, KIND_END
17 /// ]);
18 ///
19 /// // `as_slice` allows access to the raw encoded data
20 /// let slice = tcp_options.as_slice();
21 ///
22 /// assert_eq!(
23 ///     slice,
24 ///     [KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, 2, KIND_END]
25 /// );
26 /// ```
27 ///
28 /// It also possible to iterate over the decoded [`TcpOptionElement`]s
29 /// by calling [`TcpOptions::elements_iter`]:
30 ///
31 /// ```
32 /// use etherparse::{
33 ///     TcpOptions,
34 ///     TcpOptionElement::WindowScale,
35 ///     tcp_option::{KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, KIND_END}
36 /// };
37 ///
38 /// let tcp_options = TcpOptions::from([
39 ///     KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, 2, KIND_END
40 /// ]);
41 ///
42 /// // `elements_iter` allows iteration over the decoded elements
43 /// // and decoding errors
44 /// let mut iter = tcp_options.elements_iter();
45 ///
46 /// assert_eq!(
47 ///     iter.collect::<Vec<_>>(),
48 ///     vec![Ok(WindowScale(2))]
49 /// );
50 /// ```
51 ///
52 /// # Examples (constructing)
53 ///
54 /// Arrays of type `[u8;4]`, `[u8;8]`, `[u8;12]`, `[u8;16]`, `[u8;20]`,
55 /// `[u8;24]`, `[u8;28]`, `[u8;32]`, `[u8;36]`, `[u8;40]` can directly be
56 /// converted with the `from` or `into` methods to [`TcpOptions`]:
57 ///
58 /// ```
59 /// use etherparse::TcpOptions;
60 ///
61 /// // static sized arrays of size 4,8,... 40 can directly be converted
62 /// // via `from` or `into`
63 /// let options: TcpOptions = [1,2,3,4].into();
64 ///
65 /// assert_eq!(&options[..], &[1,2,3,4]);
66 /// ```
67 ///
68 /// Slices can be converted with `try_from` or `try_into` into [`TcpOptions`].
69 /// If the len of 40 bytes is exceeded an error is returned and if the
70 /// len is not a multiple of 4 the len is automatically increased to the next
71 /// multiple of 4 value and the data filled up with zeroes (equivalent to the
72 /// TCP END option):
73 ///
74 /// ```
75 /// use etherparse::TcpOptions;
76 /// {
77 ///     let data = [1u8,2,3,4,5,6,7,8];
78 ///
79 ///     // slices can be converted into TcpOptions via `try_from` or `try_into`
80 ///     let options: TcpOptions = (&data[..]).try_into().unwrap();
81 ///
82 ///     assert_eq!(options.as_slice(), &data);
83 /// }
84 /// {
85 ///     let data = [1u8];
86 ///
87 ///     // len is automatically increased to a multiple of 4 (filled
88 ///     // with 0, also known as the END TCP option).
89 ///     let options = TcpOptions::try_from(&data[..]).unwrap();
90 ///
91 ///     assert_eq!(options.as_slice(), &[1, 0, 0, 0]);
92 /// }
93 /// {
94 ///     use etherparse::TcpOptionWriteError::NotEnoughSpace;
95 ///
96 ///     let data = [0u8;41]; // 41 bytes
97 ///
98 ///     // slices with a len bigger then 40 cause an error
99 ///     let result = TcpOptions::try_from(&data[..]);
100 ///     assert_eq!(result, Err(NotEnoughSpace(41)));
101 /// }
102 /// ```
103 ///
104 /// Slices containing [`TcpOptionElement`]s can also be converted via
105 /// `try_from` or `try_into` as long as the encoded elements are within
106 /// 40 bytes:
107 ///
108 /// ```
109 /// use etherparse::{
110 ///     TcpOptions,
111 ///     tcp_option::{KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, KIND_NOOP, KIND_END},
112 ///     TcpOptionElement::{Noop, WindowScale}
113 /// };
114 ///
115 /// let elements = [WindowScale(123), Noop, Noop];
116 ///
117 /// // try_from encodes the options into the "on the wire" format
118 /// let options = TcpOptions::try_from(&elements[..]).unwrap();
119 ///
120 /// assert_eq!(
121 ///     options.as_slice(),
122 ///     &[
123 ///         KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, 123, KIND_NOOP,
124 ///         KIND_NOOP, KIND_END, KIND_END, KIND_END
125 ///     ]
126 /// );
127 /// ```
128 #[derive(Clone)]
129 pub struct TcpOptions {
130     /// Number of bytes in the buffer.
131     pub(crate) len: u8,
132 
133     /// Buffer containing the options of the header
134     /// (note that the `len` field defines the actual length). Use
135     /// the options() method if you want to get a slice that has
136     /// the actual length of the options.
137     pub(crate) buf: [u8; 40],
138 }
139 
140 impl TcpOptions {
141     /// Maximum number of bytes that can be part of an TCP options.
142     pub const MAX_LEN: usize = 40;
143 
144     /// Constructs a new empty TcpOptions.
145     #[inline]
new() -> TcpOptions146     pub fn new() -> TcpOptions {
147         TcpOptions {
148             len: 0,
149             buf: [0; 40],
150         }
151     }
152 
153     /// Tries to convert an `u8` slice into [`TcpOptions`].
154     ///
155     /// # Examples
156     ///
157     /// Slices with a length that is a multiple of 4 and a length not
158     /// bigger than 40 can be converted one-to-one:
159     ///
160     /// ```
161     /// use etherparse::TcpOptions;
162     ///
163     /// let data = [1u8,2,3,4,5,6,7,8];
164     /// let options = TcpOptions::try_from_slice(&data[..]).unwrap();
165     /// assert_eq!(options.as_slice(), &data);
166     /// ```
167     ///
168     /// If the length is not a multiple of 4 it is automatically filled
169     /// up with `0` (value of TCP option END) to the next multiple of 4:
170     ///
171     /// ```
172     /// use etherparse::TcpOptions;
173     /// {
174     ///     let data = [1u8];
175     ///     let options = TcpOptions::try_from(&data[..]).unwrap();
176     ///     // 3 bytes of zero added so the len is a multiple of 4
177     ///     assert_eq!(options.as_slice(), &[1, 0, 0, 0]);
178     /// }
179     /// ```
180     ///
181     /// In case more than 40 bytes are passed as input an error is returned:
182     ///
183     /// ```
184     /// use etherparse::{
185     ///     TcpOptions,
186     ///     TcpOptionWriteError::NotEnoughSpace
187     /// };
188     ///
189     /// let data = [0u8;41]; // 41 bytes
190     ///
191     /// // slices with a len bigger then 40 cause an error
192     /// let result = TcpOptions::try_from(&data[..]);
193     /// assert_eq!(result, Err(NotEnoughSpace(41)));
194     /// ```
try_from_slice(slice: &[u8]) -> Result<TcpOptions, TcpOptionWriteError>195     pub fn try_from_slice(slice: &[u8]) -> Result<TcpOptions, TcpOptionWriteError> {
196         // check length
197         if Self::MAX_LEN < slice.len() {
198             Err(TcpOptionWriteError::NotEnoughSpace(slice.len()))
199         } else {
200             let len = slice.len() as u8;
201 
202             // reset all to zero to ensure padding
203             Ok(TcpOptions {
204                 len: ((len >> 2) << 2)
205                     + if 0 != len & 0b11 {
206                         // NOTE: If the slice length is not a multiple of
207                         // 4 the length is automatically increased to be
208                         // a multiple of 4 and the data is filled up with
209                         // zeroes.
210                         4
211                     } else {
212                         0
213                     },
214                 buf: {
215                     let mut buf = [0; 40];
216                     buf[..slice.len()].copy_from_slice(slice);
217                     buf
218                 },
219             })
220         }
221     }
222 
223     /// Tries to convert [`crate::TcpOptionElement`] into serialized
224     /// form as [`TcpOptions`].
225     ///
226     /// # Example
227     ///
228     /// ```
229     /// use etherparse::{
230     ///     TcpOptions,
231     ///     tcp_option::{KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, KIND_NOOP, KIND_END},
232     ///     TcpOptionElement::{Noop, WindowScale}
233     /// };
234     ///
235     /// let elements = [WindowScale(123), Noop, Noop];
236     ///
237     /// // try_from encodes the options into the "on the wire" format
238     /// let options = TcpOptions::try_from_elements(&elements[..]).unwrap();
239     ///
240     /// assert_eq!(
241     ///     options.as_slice(),
242     ///     &[
243     ///         KIND_WINDOW_SCALE, LEN_WINDOW_SCALE, 123, KIND_NOOP,
244     ///         // padding in form of "KIND_END" (0) is automatically added
245     ///         // so the resulting options length is a multiple of 4
246     ///         KIND_NOOP, KIND_END, KIND_END, KIND_END
247     ///     ]
248     /// );
249     /// ```
try_from_elements( elements: &[TcpOptionElement], ) -> Result<TcpOptions, TcpOptionWriteError>250     pub fn try_from_elements(
251         elements: &[TcpOptionElement],
252     ) -> Result<TcpOptions, TcpOptionWriteError> {
253         // calculate the required size of the options
254         use crate::TcpOptionElement::*;
255         let required_len = elements.iter().fold(0, |acc, ref x| {
256             acc + match x {
257                 Noop => 1,
258                 MaximumSegmentSize(_) => 4,
259                 WindowScale(_) => 3,
260                 SelectiveAcknowledgementPermitted => 2,
261                 SelectiveAcknowledgement(_, rest) => rest.iter().fold(10, |acc2, ref y| match y {
262                     None => acc2,
263                     Some(_) => acc2 + 8,
264                 }),
265                 Timestamp(_, _) => 10,
266             }
267         });
268 
269         if Self::MAX_LEN < required_len {
270             Err(TcpOptionWriteError::NotEnoughSpace(required_len))
271         } else {
272             // reset the options to null
273             let mut buf = [0u8; TcpOptions::MAX_LEN];
274             let mut len: usize = 0;
275 
276             // write the options to the buffer
277             use tcp_option::*;
278             for element in elements {
279                 match element {
280                     Noop => {
281                         buf[len] = KIND_NOOP;
282                         len += 1;
283                     }
284                     MaximumSegmentSize(value) => {
285                         // determine insertion area
286                         let t = &mut buf[len..len + 4];
287 
288                         // insert data
289                         let value = value.to_be_bytes();
290                         t[0] = KIND_MAXIMUM_SEGMENT_SIZE;
291                         t[1] = 4;
292                         t[2] = value[0];
293                         t[3] = value[1];
294 
295                         len += 4;
296                     }
297                     WindowScale(value) => {
298                         // determine insertion area
299                         let t = &mut buf[len..len + 3];
300 
301                         // write data
302                         t[0] = KIND_WINDOW_SCALE;
303                         t[1] = 3;
304                         t[2] = *value;
305 
306                         len += 3;
307                     }
308                     SelectiveAcknowledgementPermitted => {
309                         // determine insertion area
310                         let insert = &mut buf[len..len + 2];
311 
312                         // write data
313                         insert[0] = KIND_SELECTIVE_ACK_PERMITTED;
314                         insert[1] = 2;
315 
316                         len += 2;
317                     }
318                     SelectiveAcknowledgement(first, rest) => {
319                         //write guaranteed data
320                         {
321                             let t = &mut buf[len..len + 10];
322                             len += 10;
323 
324                             t[0] = KIND_SELECTIVE_ACK;
325                             //write the length
326                             t[1] = rest.iter().fold(10, |acc, ref y| match y {
327                                 None => acc,
328                                 Some(_) => acc + 8,
329                             });
330                             // write first
331                             t[2..6].copy_from_slice(&first.0.to_be_bytes());
332                             t[6..10].copy_from_slice(&first.1.to_be_bytes());
333                         }
334                         //write the rest
335                         for v in rest {
336                             match v {
337                                 None => {}
338                                 Some((a, b)) => {
339                                     // determine insertion area
340                                     let t = &mut buf[len..len + 8];
341 
342                                     // insert
343                                     t[0..4].copy_from_slice(&a.to_be_bytes());
344                                     t[4..8].copy_from_slice(&b.to_be_bytes());
345 
346                                     len += 8;
347                                 }
348                             }
349                         }
350                     }
351                     Timestamp(a, b) => {
352                         let t = &mut buf[len..len + 10];
353 
354                         t[0] = KIND_TIMESTAMP;
355                         t[1] = 10;
356                         t[2..6].copy_from_slice(&a.to_be_bytes());
357                         t[6..10].copy_from_slice(&b.to_be_bytes());
358 
359                         len += 10;
360                     }
361                 }
362             }
363             // set the new data offset
364             if (len > 0) && (0 != len & 0b11) {
365                 len = (len & (!0b11)) + 4;
366             }
367             // done
368             Ok(TcpOptions {
369                 len: len as u8,
370                 buf,
371             })
372         }
373     }
374 
375     /// The number of 32 bit words in the TCP Header & TCP header options.
376     ///
377     /// This indicates where the data begins relative to the start of an
378     /// TCP header in multiples of 4 bytes. This number is
379     /// present in the `data_offset` field of the header and defines
380     /// the length of the tcp options present.
381     ///
382     /// # Example
383     ///
384     /// ```
385     /// use etherparse::TcpOptions;
386     ///
387     /// {
388     ///     let options = TcpOptions::try_from_slice(&[]).unwrap();
389     ///     // in case there are no options the minimum size of the tcp
390     ///     // is returned.
391     ///     assert_eq!(5, options.data_offset());
392     /// }
393     /// {
394     ///     let options = TcpOptions::try_from_slice(&[1,2,3,4,5,6,7,8]).unwrap();
395     ///     // otherwise the base TCP header size plus the number of 4 byte
396     ///     // words in the options is returned
397     ///     assert_eq!(5 + 2, options.data_offset());
398     /// }
399     /// ```
400     #[inline]
data_offset(&self) -> u8401     pub fn data_offset(&self) -> u8 {
402         TcpHeader::MIN_DATA_OFFSET + (self.len >> 2)
403     }
404 
405     /// Number of bytes in the buffer as an unsigned 8 bit integer.
406     #[inline]
len_u8(&self) -> u8407     pub fn len_u8(&self) -> u8 {
408         self.len
409     }
410 
411     /// Number of bytes in the buffer.
412     #[inline]
len(&self) -> usize413     pub fn len(&self) -> usize {
414         self.len as usize
415     }
416 
417     /// Returns true if the options contain no elements.
418     #[inline]
is_empty(&self) -> bool419     pub fn is_empty(&self) -> bool {
420         0 == self.len
421     }
422 
423     /// Slice containing the options.
424     #[inline]
as_slice(&self) -> &[u8]425     pub fn as_slice(&self) -> &[u8] {
426         debug_assert!(self.len <= 40);
427         // SAFETY: Safe as all constructing methods verify len to be less then 40.
428         unsafe { core::slice::from_raw_parts(self.buf.as_ptr(), self.len()) }
429     }
430 
431     /// Mutable slice containing the options.
432     #[inline]
as_mut_slice(&mut self) -> &mut [u8]433     pub fn as_mut_slice(&mut self) -> &mut [u8] {
434         debug_assert!(self.len <= 40);
435         // SAFETY: Safe as all constructing methods verify len to be less then 40.
436         unsafe { core::slice::from_raw_parts_mut(self.buf.as_mut_ptr(), self.len()) }
437     }
438 
439     /// Returns an iterator that allows to iterate through the
440     /// decoded option elements.
441     ///
442     /// # Example
443     ///
444     /// ```
445     /// use etherparse::{
446     ///     TcpOptions,
447     ///     TcpOptionElement::{Noop, WindowScale}
448     /// };
449     ///
450     /// let options = TcpOptions::try_from(&[WindowScale(123), Noop, Noop][..]).unwrap();
451     ///
452     /// let mut v = Vec::with_capacity(3);
453     /// for re in options.elements_iter() {
454     ///     v.push(re);
455     /// }
456     /// assert_eq!(v, vec![Ok(WindowScale(123)), Ok(Noop), Ok(Noop)]);
457     /// ```
458     #[inline]
elements_iter(&self) -> TcpOptionsIterator459     pub fn elements_iter(&self) -> TcpOptionsIterator {
460         TcpOptionsIterator {
461             options: self.as_slice(),
462         }
463     }
464 }
465 
466 impl Default for TcpOptions {
467     #[inline]
default() -> Self468     fn default() -> Self {
469         Self {
470             len: 0,
471             buf: [0; 40],
472         }
473     }
474 }
475 
476 impl core::cmp::Eq for TcpOptions {}
477 impl PartialEq for TcpOptions {
eq(&self, other: &Self) -> bool478     fn eq(&self, other: &Self) -> bool {
479         self.as_slice() == other.as_slice()
480     }
481 }
482 
483 impl<'a> TryFrom<&'a [u8]> for TcpOptions {
484     type Error = TcpOptionWriteError;
485 
486     #[inline]
try_from(value: &'a [u8]) -> Result<Self, Self::Error>487     fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
488         TcpOptions::try_from_slice(value)
489     }
490 }
491 
492 impl<'a> TryFrom<&'a [TcpOptionElement]> for TcpOptions {
493     type Error = TcpOptionWriteError;
494 
495     #[inline]
try_from(value: &'a [TcpOptionElement]) -> Result<Self, Self::Error>496     fn try_from(value: &'a [TcpOptionElement]) -> Result<Self, Self::Error> {
497         TcpOptions::try_from_elements(value)
498     }
499 }
500 
501 impl core::fmt::Debug for TcpOptions {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result502     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
503         self.elements_iter().fmt(f)
504     }
505 }
506 
507 impl core::hash::Hash for TcpOptions {
hash<H: core::hash::Hasher>(&self, state: &mut H)508     fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
509         self.as_slice().hash(state);
510     }
511 }
512 
513 impl core::cmp::PartialOrd for TcpOptions {
partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering>514     fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
515         Some(self.as_slice().cmp(other.as_slice()))
516     }
517 }
518 
519 impl core::cmp::Ord for TcpOptions {
cmp(&self, other: &Self) -> core::cmp::Ordering520     fn cmp(&self, other: &Self) -> core::cmp::Ordering {
521         self.as_slice().cmp(other.as_slice())
522     }
523 }
524 
525 impl core::ops::Deref for TcpOptions {
526     type Target = [u8];
527 
528     #[inline]
deref(&self) -> &[u8]529     fn deref(&self) -> &[u8] {
530         self.as_slice()
531     }
532 }
533 
534 impl AsRef<TcpOptions> for TcpOptions {
535     #[inline]
as_ref(&self) -> &TcpOptions536     fn as_ref(&self) -> &TcpOptions {
537         self
538     }
539 }
540 
541 impl AsMut<TcpOptions> for TcpOptions {
542     #[inline]
as_mut(&mut self) -> &mut TcpOptions543     fn as_mut(&mut self) -> &mut TcpOptions {
544         self
545     }
546 }
547 
548 impl AsRef<[u8]> for TcpOptions {
549     #[inline]
as_ref(&self) -> &[u8]550     fn as_ref(&self) -> &[u8] {
551         self.as_slice()
552     }
553 }
554 
555 impl AsMut<[u8]> for TcpOptions {
556     #[inline]
as_mut(&mut self) -> &mut [u8]557     fn as_mut(&mut self) -> &mut [u8] {
558         self.as_mut_slice()
559     }
560 }
561 
562 macro_rules! from_static_array {
563     ($x:expr) => {
564         impl From<[u8; $x]> for TcpOptions {
565             #[inline]
566             fn from(values: [u8; $x]) -> Self {
567                 let mut result = TcpOptions {
568                     len: $x,
569                     buf: [0; 40],
570                 };
571                 let r = result.buf.as_mut_ptr() as *mut [u8; $x];
572                 unsafe {
573                     *r = values;
574                 }
575                 result
576             }
577         }
578     };
579 }
580 
581 from_static_array!(4);
582 from_static_array!(8);
583 from_static_array!(12);
584 from_static_array!(16);
585 from_static_array!(20);
586 from_static_array!(24);
587 from_static_array!(28);
588 from_static_array!(32);
589 from_static_array!(36);
590 
591 impl From<[u8; 40]> for TcpOptions {
from(values: [u8; 40]) -> Self592     fn from(values: [u8; 40]) -> Self {
593         TcpOptions {
594             len: 40,
595             buf: values,
596         }
597     }
598 }
599 
600 #[cfg(test)]
601 mod test {
602     use super::*;
603     use crate::test_gens::tcp_options_any;
604     use core::ops::Deref;
605     use proptest::prelude::*;
606     use std::format;
607 
608     #[test]
new()609     fn new() {
610         assert_eq!(
611             TcpOptions::new(),
612             TcpOptions {
613                 len: 0,
614                 buf: [0; 40]
615             }
616         );
617     }
618 
619     #[test]
try_from_slice()620     fn try_from_slice() {
621         let actual = TcpOptions::try_from_slice(&[1, 2, 3, 4][..]);
622         assert_eq!(actual, Ok(TcpOptions::from([1, 2, 3, 4])));
623     }
624 
625     #[test]
try_from_elements()626     fn try_from_elements() {
627         use crate::tcp_option::KIND_NOOP;
628         use crate::TcpOptionElement::Noop;
629         let actual = TcpOptions::try_from_elements(&[Noop, Noop, Noop, Noop][..]);
630         assert_eq!(
631             actual,
632             Ok(TcpOptions::from([
633                 KIND_NOOP, KIND_NOOP, KIND_NOOP, KIND_NOOP
634             ]))
635         );
636     }
637 
638     proptest! {
639         #[test]
640         fn data_offset(
641             options in tcp_options_any()
642         ) {
643             assert_eq!(
644                 (5 + ((options.len as u64) / 4)) as u8,
645                 options.data_offset()
646             );
647         }
648     }
649     proptest! {
650         #[test]
651         fn len(
652             options in tcp_options_any()
653         ) {
654             assert_eq!(options.len(), usize::from(options.len));
655         }
656     }
657 
658     proptest! {
659         #[test]
660         fn len_u8(
661             options in tcp_options_any()
662         ) {
663             assert_eq!(options.len_u8(), options.len);
664         }
665     }
666 
667     proptest! {
668         #[test]
669         fn is_empty(
670             options in tcp_options_any()
671         ) {
672             assert_eq!(options.is_empty(), 0 == options.len);
673         }
674     }
675 
676     #[test]
as_slice()677     fn as_slice() {
678         let options = TcpOptions::from([1, 2, 3, 4]);
679         assert_eq!(options.as_slice(), &[1, 2, 3, 4][..]);
680     }
681 
682     #[test]
as_mut_slice()683     fn as_mut_slice() {
684         let mut options = TcpOptions::from([1, 2, 3, 4]);
685         let r = options.as_mut_slice();
686         r[0] = 5;
687         assert_eq!(options.as_slice(), &[5, 2, 3, 4][..]);
688     }
689 
690     #[test]
options_iterator()691     fn options_iterator() {
692         let options = TcpOptions::from([1, 2, 3, 4]);
693         assert_eq!(
694             options.elements_iter(),
695             TcpOptionsIterator {
696                 options: &[1, 2, 3, 4][..]
697             }
698         );
699     }
700 
701     #[test]
default()702     fn default() {
703         let actual: TcpOptions = Default::default();
704         assert_eq!(0, actual.len);
705         assert_eq!([0u8; 40], actual.buf);
706     }
707 
708     #[test]
try_from()709     fn try_from() {
710         // from slice
711         {
712             let actual = TcpOptions::try_from(&[1, 2, 3, 4][..]);
713             assert_eq!(actual, Ok(TcpOptions::from([1, 2, 3, 4])));
714         }
715         // from elements
716         {
717             use crate::tcp_option::KIND_NOOP;
718             use crate::TcpOptionElement::Noop;
719             let actual = TcpOptions::try_from(&[Noop, Noop, Noop, Noop][..]);
720             assert_eq!(
721                 actual,
722                 Ok(TcpOptions::from([
723                     KIND_NOOP, KIND_NOOP, KIND_NOOP, KIND_NOOP
724                 ]))
725             );
726         }
727     }
728 
729     #[test]
debug_fmt()730     fn debug_fmt() {
731         use crate::tcp_option::KIND_NOOP;
732         let data = [KIND_NOOP, KIND_NOOP, KIND_NOOP, KIND_NOOP];
733         let options = TcpOptions::from(data.clone());
734         assert_eq!(
735             format!("{:?}", TcpOptionsIterator { options: &data[..] }),
736             format!("{:?}", options)
737         );
738     }
739 
740     #[test]
clone_eq_hash_ord()741     fn clone_eq_hash_ord() {
742         let a = TcpOptions::from([1u8, 2, 3, 4]);
743         assert_eq!(a, a.clone());
744         assert_ne!(a, TcpOptions::from([5u8, 6, 7, 8]));
745         {
746             use core::hash::{Hash, Hasher};
747             use std::collections::hash_map::DefaultHasher;
748             let a_hash = {
749                 let mut hasher = DefaultHasher::new();
750                 a.hash(&mut hasher);
751                 hasher.finish()
752             };
753             let b_hash = {
754                 let mut hasher = DefaultHasher::new();
755                 a.hash(&mut hasher);
756                 hasher.finish()
757             };
758             assert_eq!(a_hash, b_hash);
759         }
760         {
761             use core::cmp::Ordering;
762             assert_eq!(a.cmp(&a), Ordering::Equal);
763         }
764     }
765 
766     #[test]
partial_cmp()767     pub fn partial_cmp() {
768         use core::cmp::Ordering;
769         let a = TcpOptions::from([1u8, 2, 3, 4]);
770         assert_eq!(a.partial_cmp(&a), Some(Ordering::Equal));
771     }
772 
773     #[test]
deref()774     fn deref() {
775         let a = TcpOptions::from([1u8, 2, 3, 4]);
776         assert_eq!(a.deref(), &[1u8, 2, 3, 4][..]);
777     }
778 
779     #[test]
as_ref()780     fn as_ref() {
781         // TcpOptions ref
782         {
783             let a = TcpOptions::from([1u8, 2, 3, 4]);
784             let b: &TcpOptions = a.as_ref();
785             assert_eq!(b, &TcpOptions::from([1u8, 2, 3, 4]));
786         }
787         // slice ref
788         {
789             let a = TcpOptions::from([1u8, 2, 3, 4]);
790             let b: &[u8] = a.as_ref();
791             assert_eq!(b, &[1u8, 2, 3, 4]);
792         }
793     }
794 
795     #[test]
as_mut()796     fn as_mut() {
797         // TcpOptions ref
798         {
799             let mut a = TcpOptions::from([1u8, 2, 3, 4]);
800             let b: &mut TcpOptions = a.as_mut();
801             *b = TcpOptions::from([5u8, 6, 7, 8]);
802             assert_eq!(a, TcpOptions::from([5u8, 6, 7, 8]));
803         }
804         // slice ref
805         {
806             let mut a = TcpOptions::from([1u8, 2, 3, 4]);
807             let b: &mut [u8] = a.as_mut();
808             assert_eq!(b, &[1u8, 2, 3, 4]);
809             b[0] = 5;
810             assert_eq!(a, TcpOptions::from([5u8, 2, 3, 4]));
811         }
812     }
813 
814     #[test]
from()815     fn from() {
816         assert_eq!(TcpOptions::from([1u8, 2, 3, 4]).as_slice(), &[1u8, 2, 3, 4]);
817         assert_eq!(
818             TcpOptions::from([1u8, 2, 3, 4, 5, 6, 7, 8]).as_slice(),
819             &[1u8, 2, 3, 4, 5, 6, 7, 8]
820         );
821         assert_eq!(
822             TcpOptions::from([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]).as_slice(),
823             &[1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
824         );
825         assert_eq!(
826             TcpOptions::from([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]).as_slice(),
827             &[1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
828         );
829         assert_eq!(
830             TcpOptions::from([
831                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
832             ])
833             .as_slice(),
834             &[1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
835         );
836         assert_eq!(
837             TcpOptions::from([
838                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
839                 23, 24
840             ])
841             .as_slice(),
842             &[
843                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
844                 23, 24
845             ]
846         );
847         assert_eq!(
848             TcpOptions::from([
849                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
850                 23, 24, 25, 26, 27, 28
851             ])
852             .as_slice(),
853             &[
854                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
855                 23, 24, 25, 26, 27, 28
856             ]
857         );
858         assert_eq!(
859             TcpOptions::from([
860                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
861                 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
862             ])
863             .as_slice(),
864             &[
865                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
866                 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
867             ]
868         );
869         assert_eq!(
870             TcpOptions::from([
871                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
872                 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36
873             ])
874             .as_slice(),
875             &[
876                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
877                 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36
878             ]
879         );
880         assert_eq!(
881             TcpOptions::from([
882                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
883                 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
884             ])
885             .as_slice(),
886             &[
887                 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
888                 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
889             ]
890         );
891     }
892 }
893