etherparse/transport/
tcp_options.rs

1use 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)]
129pub 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
140impl 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]
146    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    /// ```
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    /// ```
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]
401    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]
407    pub fn len_u8(&self) -> u8 {
408        self.len
409    }
410
411    /// Number of bytes in the buffer.
412    #[inline]
413    pub fn len(&self) -> usize {
414        self.len as usize
415    }
416
417    /// Returns true if the options contain no elements.
418    #[inline]
419    pub fn is_empty(&self) -> bool {
420        0 == self.len
421    }
422
423    /// Slice containing the options.
424    #[inline]
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]
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]
459    pub fn elements_iter(&self) -> TcpOptionsIterator {
460        TcpOptionsIterator {
461            options: self.as_slice(),
462        }
463    }
464}
465
466impl Default for TcpOptions {
467    #[inline]
468    fn default() -> Self {
469        Self {
470            len: 0,
471            buf: [0; 40],
472        }
473    }
474}
475
476impl core::cmp::Eq for TcpOptions {}
477impl PartialEq for TcpOptions {
478    fn eq(&self, other: &Self) -> bool {
479        self.as_slice() == other.as_slice()
480    }
481}
482
483impl<'a> TryFrom<&'a [u8]> for TcpOptions {
484    type Error = TcpOptionWriteError;
485
486    #[inline]
487    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
488        TcpOptions::try_from_slice(value)
489    }
490}
491
492impl<'a> TryFrom<&'a [TcpOptionElement]> for TcpOptions {
493    type Error = TcpOptionWriteError;
494
495    #[inline]
496    fn try_from(value: &'a [TcpOptionElement]) -> Result<Self, Self::Error> {
497        TcpOptions::try_from_elements(value)
498    }
499}
500
501impl core::fmt::Debug for TcpOptions {
502    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
503        self.elements_iter().fmt(f)
504    }
505}
506
507impl core::hash::Hash for TcpOptions {
508    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
509        self.as_slice().hash(state);
510    }
511}
512
513impl core::cmp::PartialOrd for TcpOptions {
514    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
515        Some(self.as_slice().cmp(other.as_slice()))
516    }
517}
518
519impl core::cmp::Ord for TcpOptions {
520    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
521        self.as_slice().cmp(other.as_slice())
522    }
523}
524
525impl core::ops::Deref for TcpOptions {
526    type Target = [u8];
527
528    #[inline]
529    fn deref(&self) -> &[u8] {
530        self.as_slice()
531    }
532}
533
534impl AsRef<TcpOptions> for TcpOptions {
535    #[inline]
536    fn as_ref(&self) -> &TcpOptions {
537        self
538    }
539}
540
541impl AsMut<TcpOptions> for TcpOptions {
542    #[inline]
543    fn as_mut(&mut self) -> &mut TcpOptions {
544        self
545    }
546}
547
548impl AsRef<[u8]> for TcpOptions {
549    #[inline]
550    fn as_ref(&self) -> &[u8] {
551        self.as_slice()
552    }
553}
554
555impl AsMut<[u8]> for TcpOptions {
556    #[inline]
557    fn as_mut(&mut self) -> &mut [u8] {
558        self.as_mut_slice()
559    }
560}
561
562macro_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
581from_static_array!(4);
582from_static_array!(8);
583from_static_array!(12);
584from_static_array!(16);
585from_static_array!(20);
586from_static_array!(24);
587from_static_array!(28);
588from_static_array!(32);
589from_static_array!(36);
590
591impl From<[u8; 40]> for TcpOptions {
592    fn from(values: [u8; 40]) -> Self {
593        TcpOptions {
594            len: 40,
595            buf: values,
596        }
597    }
598}
599
600#[cfg(test)]
601mod 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]
609    fn new() {
610        assert_eq!(
611            TcpOptions::new(),
612            TcpOptions {
613                len: 0,
614                buf: [0; 40]
615            }
616        );
617    }
618
619    #[test]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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}