micro_http/protocol/
message.rs

1use bytes::{Buf, Bytes};
2
3/// Represents a HTTP message that can either be a header or payload.
4///
5/// This enum is used to handle both request and response messages in the HTTP protocol.
6/// The generic parameter `T` typically represents the header type (request or response header),
7/// while `Data` represents the type of the payload data (defaults to `Bytes`).
8#[derive(Debug)]
9pub enum Message<T, Data: Buf = Bytes> {
10    /// Contains the header information of type `T`
11    Header(T),
12    /// Contains a chunk of payload data or EOF marker
13    Payload(PayloadItem<Data>),
14}
15
16/// Represents an item in the HTTP message payload stream.
17///
18/// This enum is used by the payload decoder to produce either data chunks
19/// or signal the end of the payload stream (EOF).
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum PayloadItem<Data: Buf = Bytes> {
22    /// A chunk of payload data
23    Chunk(Data),
24    /// Marks the end of the payload stream
25    Eof,
26}
27
28/// Represents the size information of an HTTP payload.
29///
30/// This enum is used to determine how the payload should be processed:
31/// - Known length: Process exact number of bytes
32/// - Chunked: Process using chunked transfer encoding
33/// - Empty: No payload to process
34#[derive(Debug, Copy, Clone, PartialEq, Eq)]
35pub enum PayloadSize {
36    /// Payload with known length in bytes
37    Length(u64),
38    /// Payload using chunked transfer encoding
39    Chunked,
40    /// Empty payload (no body)
41    Empty,
42}
43
44impl PayloadSize {
45    #[inline(always)]
46    pub fn new_chunked() -> Self {
47        PayloadSize::Chunked
48    }
49
50    #[inline(always)]
51    pub fn new_empty() -> Self {
52        PayloadSize::Empty
53    }
54
55    #[inline(always)]
56    pub fn new_length(length: u64) -> Self {
57        PayloadSize::Length(length)
58    }
59
60    /// Returns true if the payload uses chunked transfer encoding
61    #[inline]
62    pub fn is_chunked(&self) -> bool {
63        matches!(self, PayloadSize::Chunked)
64    }
65
66    /// Returns true if the payload is empty
67    #[inline]
68    pub fn is_empty(&self) -> bool {
69        matches!(self, PayloadSize::Empty)
70    }
71
72    #[inline]
73    pub fn is_not_empty(&self) -> bool {
74        !self.is_empty()
75    }
76}
77
78impl<T> Message<T> {
79    /// Returns true if this message contains payload data
80    #[inline]
81    pub fn is_payload(&self) -> bool {
82        matches!(self, Message::Payload(_))
83    }
84
85    /// Returns true if this message contains header information
86    #[inline]
87    pub fn is_header(&self) -> bool {
88        matches!(self, Message::Header(_))
89    }
90
91    /// Converts the message into a PayloadItem if it contains payload data
92    ///
93    /// Returns None if the message contains header information
94    pub fn into_payload_item(self) -> Option<PayloadItem> {
95        match self {
96            Message::Header(_) => None,
97            Message::Payload(payload_item) => Some(payload_item),
98        }
99    }
100}
101
102/// Converts bytes into a Message
103///
104/// This allows bytes to be directly converted into a Message for sending payload data.
105/// The generic type T is unused since this only creates payload messages.
106impl<T> From<Bytes> for Message<T> {
107    fn from(bytes: Bytes) -> Self {
108        Self::Payload(PayloadItem::Chunk(bytes))
109    }
110}
111
112impl<D: Buf> PayloadItem<D> {
113    /// Returns true if this item represents the end of the payload stream
114    #[inline]
115    pub fn is_eof(&self) -> bool {
116        matches!(self, PayloadItem::Eof)
117    }
118
119    /// Returns true if this item contains chunk data
120    #[inline]
121    pub fn is_chunk(&self) -> bool {
122        matches!(self, PayloadItem::Chunk(_))
123    }
124}
125
126impl PayloadItem {
127    /// Returns a reference to the contained bytes if this is a Chunk
128    ///
129    /// Returns None if this is an EOF marker
130    pub fn as_bytes(&self) -> Option<&Bytes> {
131        match self {
132            PayloadItem::Chunk(bytes) => Some(bytes),
133            PayloadItem::Eof => None,
134        }
135    }
136
137    /// Returns a mutable reference to the contained bytes if this is a Chunk
138    ///
139    /// Returns None if this is an EOF marker
140    pub fn as_mut_bytes(&mut self) -> Option<&mut Bytes> {
141        match self {
142            PayloadItem::Chunk(bytes) => Some(bytes),
143            PayloadItem::Eof => None,
144        }
145    }
146
147    /// Consumes the PayloadItem and returns the contained bytes if this is a Chunk
148    ///
149    /// Returns None if this is an EOF marker
150    pub fn into_bytes(self) -> Option<Bytes> {
151        match self {
152            PayloadItem::Chunk(bytes) => Some(bytes),
153            PayloadItem::Eof => None,
154        }
155    }
156}