Skip to main content

net_wire/udp/
builder.rs

1//! UDP caller-buffer builder.
2
3use super::datagram::{HEADER_LENGTH, UdpDatagramMut};
4use core::fmt;
5
6/// Failure to construct a UDP datagram in caller-provided storage.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum UdpDatagramBuildError {
9    /// The destination port was not supplied.
10    MissingDestinationPort,
11    /// The requested datagram length cannot be represented in the UDP length field.
12    DatagramLengthTooLarge,
13    /// The buffer cannot hold the requested datagram.
14    BufferTooShort {
15        /// Required bytes.
16        required: usize,
17        /// Available bytes.
18        available: usize,
19    },
20}
21impl fmt::Display for UdpDatagramBuildError {
22    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Self::MissingDestinationPort => formatter.write_str("missing UDP destination port"),
25            Self::DatagramLengthTooLarge => {
26                formatter.write_str("UDP datagram length exceeds u16::MAX")
27            }
28            Self::BufferTooShort {
29                required,
30                available,
31            } => write!(
32                formatter,
33                "UDP buffer is too short: need {required} bytes, have {available}"
34            ),
35        }
36    }
37}
38
39/// Builds a UDP header in caller-owned storage.
40pub struct UdpDatagramBuilder<'a> {
41    buffer: &'a mut [u8],
42    payload_length: usize,
43    source_port: u16,
44    destination_port: Option<u16>,
45    checksum: u16,
46}
47impl<'a> UdpDatagramBuilder<'a> {
48    /// Starts a builder for `payload_length` bytes, which are left untouched.
49    #[inline]
50    pub fn new(buffer: &'a mut [u8], payload_length: usize) -> Self {
51        Self {
52            buffer,
53            payload_length,
54            source_port: 0,
55            destination_port: None,
56            checksum: 0,
57        }
58    }
59    /// Supplies the source port; it defaults to zero.
60    #[inline]
61    pub fn source_port(mut self, value: u16) -> Self {
62        self.source_port = value;
63        self
64    }
65    /// Supplies the destination port.
66    #[inline]
67    pub fn destination_port(mut self, value: u16) -> Self {
68        self.destination_port = Some(value);
69        self
70    }
71    /// Supplies the encoded checksum; it defaults to zero.
72    #[inline]
73    pub fn checksum(mut self, value: u16) -> Self {
74        self.checksum = value;
75        self
76    }
77    /// Validates all inputs, then writes only the UDP header.
78    pub fn build(self) -> Result<UdpDatagramMut<'a>, UdpDatagramBuildError> {
79        let destination_port = self
80            .destination_port
81            .ok_or(UdpDatagramBuildError::MissingDestinationPort)?;
82        let length = HEADER_LENGTH
83            .checked_add(self.payload_length)
84            .ok_or(UdpDatagramBuildError::DatagramLengthTooLarge)?;
85        let encoded_length =
86            u16::try_from(length).map_err(|_| UdpDatagramBuildError::DatagramLengthTooLarge)?;
87        if self.buffer.len() < length {
88            return Err(UdpDatagramBuildError::BufferTooShort {
89                required: length,
90                available: self.buffer.len(),
91            });
92        }
93        let bytes = &mut self.buffer[..length];
94        bytes[0..2].copy_from_slice(&self.source_port.to_be_bytes());
95        bytes[2..4].copy_from_slice(&destination_port.to_be_bytes());
96        bytes[4..6].copy_from_slice(&encoded_length.to_be_bytes());
97        bytes[6..8].copy_from_slice(&self.checksum.to_be_bytes());
98        Ok(UdpDatagramMut::from_validated(bytes))
99    }
100}