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