etherparse/transport/igmp/membership_report_v1_slice.rs
1use crate::{igmp::*, *};
2
3/// Zero-copy slice of an IGMPv1 "Membership Report" (type `0x12`).
4///
5/// ```text
6/// 0 1 2 3
7/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
8/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
9/// | Type = 0x12 | Unused | Checksum |
10/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11/// | Group Address |
12/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13/// ```
14#[derive(Clone, Debug, Eq, PartialEq)]
15pub struct MembershipReportV1Slice<'a> {
16 slice: &'a [u8],
17}
18
19impl<'a> MembershipReportV1Slice<'a> {
20 /// Creates a slice from bytes without checking the length.
21 ///
22 /// # Safety
23 ///
24 /// The caller must guarantee that `slice` is at least
25 /// [`MembershipReportV1Type::LEN`] (8) bytes long.
26 #[inline]
27 pub(crate) unsafe fn from_slice_unchecked(slice: &'a [u8]) -> MembershipReportV1Slice<'a> {
28 debug_assert!(slice.len() >= MembershipReportV1Type::LEN);
29 MembershipReportV1Slice { slice }
30 }
31
32 /// Returns the "checksum" value stored in the IGMP header.
33 #[inline]
34 pub fn checksum(&self) -> u16 {
35 // SAFETY: from_slice_unchecked guarantees at least 8 bytes.
36 unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) }
37 }
38
39 /// The IP multicast group address of the group being reported.
40 #[inline]
41 pub fn group_address(&self) -> GroupAddress {
42 // SAFETY: from_slice_unchecked guarantees at least 8 bytes.
43 GroupAddress::new(unsafe {
44 [
45 *self.slice.get_unchecked(4),
46 *self.slice.get_unchecked(5),
47 *self.slice.get_unchecked(6),
48 *self.slice.get_unchecked(7),
49 ]
50 })
51 }
52
53 /// Decodes the fixed fields into an owned [`MembershipReportV1Type`].
54 #[inline]
55 pub fn to_header(&self) -> MembershipReportV1Type {
56 MembershipReportV1Type {
57 group_address: self.group_address(),
58 }
59 }
60
61 /// Returns the bytes after the 8-byte header (usually empty).
62 #[inline]
63 pub fn payload(&self) -> &'a [u8] {
64 // SAFETY: from_slice_unchecked guarantees at least 8 bytes.
65 unsafe {
66 core::slice::from_raw_parts(
67 self.slice.as_ptr().add(MembershipReportV1Type::LEN),
68 self.slice.len() - MembershipReportV1Type::LEN,
69 )
70 }
71 }
72
73 /// Returns the slice containing the entire IGMP message.
74 #[inline]
75 pub fn slice(&self) -> &'a [u8] {
76 self.slice
77 }
78}