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}