channels_packet/frame.rs
1//! [`Frame`] and helper types.
2
3use core::fmt;
4use core::marker::PhantomData;
5use core::ops::Range;
6
7use channels_io::buf::{Buf, Chain, Cursor};
8
9use crate::flags::Flags;
10use crate::header::{Header, HeaderBytes, HeaderError};
11use crate::payload::Payload;
12use crate::seq::{FrameNum, FrameNumSequence};
13use crate::util::Error;
14use crate::wants::Wants;
15
16/// A protocol frame.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct Frame<T> {
19 /// Frame flags.
20 pub flags: Flags,
21 /// Frame number.
22 pub frame_num: FrameNum,
23 /// Frame payload data.
24 pub payload: T,
25}
26
27impl<T> Frame<T> {
28 /// Create a new [`Builder`].
29 #[inline]
30 pub const fn builder() -> Builder<T> {
31 Builder::new()
32 }
33
34 /// Convert a `Frame<T>` to a `Frame<U>` via a function _f_.
35 #[inline]
36 pub fn map_payload<U, F>(self, f: F) -> Frame<U>
37 where
38 F: FnOnce(T) -> U,
39 {
40 Frame {
41 flags: self.flags,
42 frame_num: self.frame_num,
43 payload: f(self.payload),
44 }
45 }
46
47 fn get_header(&self, data_len: u32) -> Header {
48 Header {
49 flags: self.flags,
50 frame_num: self.frame_num,
51 data_len,
52 }
53 }
54}
55
56/// Errors when parsing a frame.
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
58pub enum FrameError {
59 /// There was an error while parsing the header.
60 Header(HeaderError),
61 /// The frame is too large to fit in memory.
62 TooLarge,
63}
64
65impl fmt::Display for FrameError {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::Header(e) => e.fmt(f),
69 Self::TooLarge => f.write_str("frame too large"),
70 }
71 }
72}
73
74impl Error for FrameError {}
75
76impl Frame<Range<usize>> {
77 /// Try to parse a frame from `bytes` returning an indice to the payload.
78 ///
79 /// Returns a [`Frame`] whose payload is a [`Range`] inside `bytes`. If `bytes` does not
80 /// have a complete frame, this method returns `Ok(Err(Wants))`, the provided [`Wants`]
81 /// type can be used as an optimization hint for outside code. If `bytes` has a complete
82 /// frame but that frame contains errors or cannot be parsed, it returns `Err(...)`.
83 /// Otherwise, it returns `Ok(Ok(frame))`.
84 ///
85 /// The implementation makes no assumptions about the platform's pointer width and thus
86 /// it is possible for parsing to fail if the entire frame is larger than the address
87 /// space of the platform. Typically this is only a concern on 16-bit and 32-bit targets.
88 pub fn try_parse_range(
89 bytes: &[u8],
90 ) -> Result<Result<Self, Wants>, FrameError> {
91 let header = match Header::try_parse(bytes) {
92 Ok(Ok(x)) => x,
93 Ok(Err(wants)) => return Ok(Err(wants)),
94 Err(e) => return Err(FrameError::Header(e)),
95 };
96
97 let data_len = header
98 .data_len
99 .try_into()
100 .map_err(|_| FrameError::TooLarge)?;
101
102 let frame_len = Header::SIZE
103 .checked_add(data_len)
104 .ok_or(FrameError::TooLarge)?;
105
106 if bytes.len() < frame_len {
107 return Ok(Err(Wants(frame_len - bytes.len())));
108 }
109
110 Ok(Ok(Frame {
111 flags: header.flags,
112 frame_num: header.frame_num,
113 payload: Header::SIZE..frame_len,
114 }))
115 }
116
117 /// Get the length of the frame in bytes.
118 ///
119 /// Returns `None` if the sum of the lengths of the header and payload cannot be
120 /// represented in a `usize`. Otherwise, it returns `Some(length)`.
121 #[inline]
122 #[must_use]
123 pub fn length(&self) -> Option<usize> {
124 calculate_frame_len(self.payload.len())
125 }
126
127 /// Get the header of the frame.
128 ///
129 /// Returns `None` if the range of the payload does not fit inside a [`u32`].
130 ///
131 /// # Example
132 ///
133 /// ```
134 /// # use core::ops::Range;
135 /// # use channels_packet::{Frame, Header, FrameNum, Flags};
136 /// let frame = Frame {
137 /// flags: Flags::empty(),
138 /// frame_num: FrameNum::new(13),
139 /// payload: 8..42,
140 /// };
141 ///
142 /// assert_eq!(frame.header().unwrap(), Header {
143 /// flags: Flags::empty(),
144 /// frame_num: FrameNum::new(13),
145 /// data_len: 34,
146 /// });
147 /// ```
148 #[inline]
149 #[must_use]
150 pub fn header(&self) -> Option<Header> {
151 let len = self.payload.len().try_into().ok()?;
152 Some(self.get_header(len))
153 }
154}
155
156impl<'a> Frame<Payload<&'a [u8]>> {
157 /// Try to parse a frame from `bytes` returning the payload as a slice.
158 ///
159 /// Returns a [`Frame`] whose payload is a slice of `bytes`. If `bytes` does not
160 /// have a complete frame, this method returns `Ok(Err(Wants))`, the provided [`Wants`]
161 /// type can be used as an optimization hint for outside code. If `bytes` has a complete
162 /// frame but that frame contains errors or cannot be parsed, it returns `Err(...)`.
163 /// Otherwise, it returns `Ok(Ok(frame))`.
164 ///
165 /// The implementation makes no assumptions about the platform's pointer width and thus
166 /// it is possible for parsing to fail if the entire frame is larger than the address
167 /// space of the platform. Typically this is only a concern on 16-bit and 32-bit targets.
168 #[allow(clippy::missing_panics_doc)]
169 pub fn try_parse(
170 bytes: &'a [u8],
171 ) -> Result<Result<Self, Wants>, FrameError> {
172 let frame = match Frame::try_parse_range(bytes) {
173 Ok(Ok(x)) => x,
174 Ok(Err(wants)) => return Ok(Err(wants)),
175 Err(e) => return Err(e),
176 };
177
178 Ok(Ok(frame.map_payload(|x| {
179 // SAFETY: `try_parse_range` returns a range to the payload of the frame, so
180 // so the length of the slice represented by that range is always a
181 // 32 bit number. If this `u32` number cannot be represented using the
182 // platform's `usize`, then `try_parse_range` will fail. If `try_parse_range`
183 // succeeds, then we know that the length of the payload fits inside
184 // a `usize`. We also know that it is a valid `u32` number. `Payload::new`
185 // fails if the length of the payload cannot fit inside a `u32` or a
186 // `usize`, whichever is smaller.
187 Payload::new(&bytes[x]).expect(
188 "try_parse_range returned an invalid payload range",
189 )
190 })))
191 }
192}
193
194impl<T: AsRef<[u8]>> Frame<Payload<T>> {
195 /// Get the length of the frame in bytes.
196 ///
197 /// Returns `None` if the sum of the lengths of the header and payload cannot be
198 /// represented in a `usize`. Otherwise, it returns `Some(length)`.
199 #[inline]
200 #[must_use]
201 pub fn length(&self) -> Option<usize> {
202 calculate_frame_len(self.payload.get().as_ref().len())
203 }
204
205 /// Get the header of the frame.
206 ///
207 /// # Example
208 ///
209 /// ```
210 /// # use channels_packet::{Frame, Payload, Header, FrameNum, Flags};
211 /// let frame = Frame {
212 /// flags: Flags::empty(),
213 /// frame_num: FrameNum::new(13),
214 /// payload: Payload::new([1, 2, 3, 4]).unwrap(),
215 /// };
216 ///
217 /// assert_eq!(frame.header(), Header {
218 /// flags: Flags::empty(),
219 /// frame_num: FrameNum::new(13),
220 /// data_len: 4,
221 /// });
222 /// ```
223 #[inline]
224 #[must_use]
225 pub fn header(&self) -> Header {
226 self.get_header(self.payload.length())
227 }
228
229 /// Encode the frame.
230 ///
231 /// Returns a [`Buf`] that contains the entire frame.
232 ///
233 /// # Example
234 ///
235 /// ```rust
236 /// # use channels_packet::{Frame, Payload, FrameNum, Flags};
237 /// let frame = Frame {
238 /// flags: Flags::empty(),
239 /// frame_num: FrameNum::new(5),
240 /// payload: Payload::new([1, 2, 3, 4]).unwrap()
241 /// };
242 ///
243 /// // encode by borrowing the payload
244 /// let bytes = frame.as_ref().encode();
245 /// # let _ = bytes;
246 ///
247 /// // or, take ownership of the payload
248 /// let bytes = frame.encode();
249 /// # let _ = bytes;
250 /// ```
251 #[inline]
252 #[must_use]
253 pub fn encode(self) -> EncodedFrame<T> {
254 EncodedFrame::new(self)
255 }
256}
257
258impl<T> Frame<Payload<T>> {
259 /// Convert a `&Frame<Payload<T>>` to a `Frame<Payload<&T>>`.
260 #[inline]
261 #[must_use]
262 pub fn as_ref(&self) -> Frame<Payload<&T>> {
263 Frame {
264 flags: self.flags,
265 frame_num: self.frame_num,
266 payload: self.payload.as_ref(),
267 }
268 }
269
270 /// Convert a `&mut Frame<Payload<T>>` to a `Frame<Payload<&mut T>>`.
271 ///
272 /// [`&mut Frame<T>]: Frame
273 /// [`Frame<&mut T>`]: Frame
274 #[inline]
275 #[must_use]
276 pub fn as_mut(&mut self) -> Frame<Payload<&mut T>> {
277 Frame {
278 flags: self.flags,
279 frame_num: self.frame_num,
280 payload: self.payload.as_mut(),
281 }
282 }
283}
284
285/// An encoded frame exposed as a [`Buf`].
286#[derive(Debug, Clone)]
287pub struct EncodedFrame<T> {
288 inner: Chain<Cursor<HeaderBytes>, Cursor<T>>,
289}
290
291impl<T> EncodedFrame<T>
292where
293 T: AsRef<[u8]>,
294{
295 #[inline]
296 fn new(frame: Frame<Payload<T>>) -> Self {
297 let header = Cursor::new(frame.header().to_bytes());
298 let payload = Cursor::new(frame.payload.into_inner());
299
300 Self { inner: Buf::chain(header, payload) }
301 }
302}
303
304impl<T: AsRef<[u8]>> Buf for EncodedFrame<T> {
305 fn remaining(&self) -> usize {
306 self.inner.remaining()
307 }
308
309 fn chunk(&self) -> &[u8] {
310 self.inner.chunk()
311 }
312
313 fn advance(&mut self, n: usize) {
314 self.inner.advance(n);
315 }
316}
317
318/// [`Frame`] builder.
319///
320/// # Example
321///
322/// ```no_run
323/// # use channels_packet::{frame::{Builder, Frame}, Payload, FrameNum};
324/// let payload = Payload::new([1u8, 1, 1, 1]).unwrap();
325///
326/// let mut frame = Builder::new()
327/// .frame_num(FrameNum::new(0))
328/// .payload(payload);
329/// ```
330#[allow(missing_debug_implementations)]
331#[must_use = "builders don't do anything unless you build them"]
332pub struct Builder<T> {
333 _marker: PhantomData<T>,
334 flags: Flags,
335 frame_num: FrameNum,
336}
337
338impl<T> Builder<T> {
339 /// Create a new [`Builder`].
340 #[inline]
341 pub const fn new() -> Self {
342 Self {
343 _marker: PhantomData,
344 flags: Flags::empty(),
345 frame_num: FrameNum::new(0),
346 }
347 }
348
349 /// Set the frame flags.
350 ///
351 /// # Example
352 ///
353 /// ```no_run
354 /// # use channels_packet::{frame::Builder, Payload, Flags};
355 /// let frame = Builder::new()
356 /// // ...
357 /// .flags(Flags::empty())
358 /// // ...
359 /// # .payload(Payload::new([]).unwrap());
360 /// ```
361 #[inline]
362 pub const fn flags(mut self, flags: Flags) -> Self {
363 self.flags = flags;
364 self
365 }
366
367 /// Set the frame number.
368 ///
369 /// # Example
370 ///
371 /// ```no_run
372 /// # use channels_packet::{frame::Builder, Payload, FrameNum};
373 /// let frame = Builder::new()
374 /// // ...
375 /// .frame_num(FrameNum::new(23))
376 /// // ...
377 /// # .payload(Payload::new([]).unwrap());
378 /// ```
379 #[inline]
380 pub const fn frame_num(mut self, frame_num: FrameNum) -> Self {
381 self.frame_num = frame_num;
382 self
383 }
384
385 /// Set the frame number from the next one in `seq`.
386 ///
387 /// This method will advance `seq`.
388 ///
389 /// # Example
390 ///
391 /// ```no_run
392 /// # use channels_packet::{frame::Builder, Payload, FrameNumSequence};
393 /// let mut seq = FrameNumSequence::new();
394 ///
395 /// let frame = Builder::new()
396 /// // ...
397 /// .frame_num_from_seq(&mut seq)
398 /// // ...
399 /// # .payload(Payload::new([]).unwrap());
400 /// ```
401 #[inline]
402 pub fn frame_num_from_seq(
403 self,
404 seq: &mut FrameNumSequence,
405 ) -> Self {
406 self.frame_num(seq.advance())
407 }
408
409 /// Set the payload of the frame
410 ///
411 /// # Example
412 ///
413 /// ```
414 /// # use channels_packet::{frame::Builder, Payload};
415 /// let buf: [u8; 6] = [1, 2, 3, 4, 5, 6];
416 ///
417 /// let frame = Builder::new()
418 /// // ...
419 /// .payload(Payload::new(buf).unwrap());
420 ///
421 /// assert_eq!(frame.payload.as_slice(), &[1, 2, 3, 4, 5, 6]);
422 /// ```
423 #[inline]
424 pub const fn payload(self, payload: T) -> Frame<T> {
425 let Self { _marker, flags, frame_num } = self;
426
427 Frame { flags, frame_num, payload }
428 }
429}
430
431impl<T> Default for Builder<T> {
432 #[inline]
433 fn default() -> Self {
434 Self::new()
435 }
436}
437
438const fn calculate_frame_len(payload_len: usize) -> Option<usize> {
439 Header::SIZE.checked_add(payload_len)
440}