miltr_common/commands/
body.rs

1use bytes::BytesMut;
2
3use crate::decoding::Parsable;
4use crate::encoding::Writable;
5use crate::ProtocolError;
6
7/// An email body part received by the milter client
8#[derive(Clone, PartialEq, Debug, Default)]
9pub struct Body {
10    body: BytesMut,
11}
12
13impl From<Body> for Vec<u8> {
14    fn from(value: Body) -> Self {
15        value.body.to_vec()
16    }
17}
18
19impl From<&[u8]> for Body {
20    fn from(value: &[u8]) -> Self {
21        Self {
22            body: BytesMut::from_iter(value),
23        }
24    }
25}
26
27impl Body {
28    const CODE: u8 = b'B';
29
30    /// Access the contained body bytes.
31    #[must_use]
32    pub fn as_bytes(&self) -> &[u8] {
33        &self.body
34    }
35
36    /// Access the contained body bytes mutably.
37    #[must_use]
38    pub fn as_mut_bytes(&mut self) -> &mut [u8] {
39        &mut self.body
40    }
41
42    /// Convert this body to a `Vec<u8>`
43    #[must_use]
44    pub fn to_vec(self) -> Vec<u8> {
45        self.into()
46    }
47}
48
49impl Parsable for Body {
50    const CODE: u8 = Self::CODE;
51
52    fn parse(buffer: BytesMut) -> Result<Self, ProtocolError> {
53        Ok(Self { body: buffer })
54    }
55}
56
57impl Writable for Body {
58    fn write(&self, buffer: &mut BytesMut) {
59        buffer.extend_from_slice(&self.body);
60    }
61
62    fn len(&self) -> usize {
63        self.body.len()
64    }
65
66    fn code(&self) -> u8 {
67        Self::CODE
68    }
69
70    fn is_empty(&self) -> bool {
71        self.body.is_empty()
72    }
73}
74
75/// No more body parts will be received after this
76#[derive(Clone, PartialEq, Debug, Default)]
77pub struct EndOfBody;
78
79impl EndOfBody {
80    const CODE: u8 = b'E';
81}
82
83impl Parsable for EndOfBody {
84    const CODE: u8 = Self::CODE;
85
86    fn parse(_buffer: BytesMut) -> Result<Self, ProtocolError> {
87        Ok(Self)
88    }
89}
90
91impl Writable for EndOfBody {
92    fn write(&self, _buffer: &mut BytesMut) {}
93
94    fn len(&self) -> usize {
95        0
96    }
97
98    fn code(&self) -> u8 {
99        Self::CODE
100    }
101
102    fn is_empty(&self) -> bool {
103        false
104    }
105}
106
107#[cfg(all(test, feature = "count-allocations"))]
108mod test {
109    use super::*;
110
111    #[test]
112    fn test_parse_body() {
113        let buffer = BytesMut::from("Random body...");
114        let info = allocation_counter::measure(|| {
115            let res = Body::parse(buffer);
116            allocation_counter::opt_out(|| {
117                println!("{res:?}");
118                assert!(res.is_ok());
119            });
120        });
121        // Verify that no memory allocations are made:
122        assert_eq!(info.count_total, 0);
123    }
124}