Skip to main content

subc_protocol/
frame.rs

1//! The complete wire frame: the decoded envelope header plus its opaque body.
2//!
3//! `Frame` is the natural companion to [`EnvelopeHeader`](crate::EnvelopeHeader)
4//! — a header and the `len` opaque body bytes that follow it. It is pure data
5//! (no async, no tokio); the async read/write loop lives in `subc-transport`,
6//! the crate that owns the authenticated stream.
7
8use std::{error::Error, fmt};
9
10use crate::{EnvelopeHeader, Flags, FrameType, PROTOCOL_VERSION};
11
12/// A complete wire frame: the decoded envelope header plus its opaque body.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct Frame {
15    pub header: EnvelopeHeader,
16    pub body: Vec<u8>,
17}
18
19impl Frame {
20    /// Build a v1 frame, filling `len` from the opaque body bytes.
21    pub fn build(
22        ty: FrameType,
23        flags: Flags,
24        channel: u16,
25        corr: u64,
26        body: Vec<u8>,
27    ) -> Result<Self, FrameBuildError> {
28        Self::build_with_version(PROTOCOL_VERSION, ty, flags, channel, corr, body)
29    }
30
31    /// Build a frame for an already-negotiated envelope version, filling `len`
32    /// from the opaque body bytes.
33    pub fn build_with_version(
34        ver: u8,
35        ty: FrameType,
36        flags: Flags,
37        channel: u16,
38        corr: u64,
39        body: Vec<u8>,
40    ) -> Result<Self, FrameBuildError> {
41        let len = u32::try_from(body.len()).map_err(|_| FrameBuildError::BodyTooLarge {
42            body_len: body.len(),
43        })?;
44        Ok(Self {
45            header: EnvelopeHeader {
46                len,
47                ver,
48                ty,
49                flags,
50                channel,
51                corr,
52            },
53            body,
54        })
55    }
56
57    /// Assemble a frame from an already-decoded header and its body bytes.
58    ///
59    /// Callers must ensure `header.len == body.len()`; frame readers obtain the
60    /// body by reading exactly `header.len` bytes, so this holds by construction.
61    pub fn from_wire(header: EnvelopeHeader, body: Vec<u8>) -> Self {
62        debug_assert_eq!(header.len as usize, body.len());
63        Self { header, body }
64    }
65}
66
67/// Why a frame could not be constructed or emitted coherently.
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub enum FrameBuildError {
70    /// The opaque body cannot be represented by the envelope's `u32` length.
71    BodyTooLarge { body_len: usize },
72}
73
74impl fmt::Display for FrameBuildError {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match self {
77            Self::BodyTooLarge { body_len } => {
78                write!(f, "frame body is too large for u32 len: {body_len} bytes")
79            }
80        }
81    }
82}
83
84impl Error for FrameBuildError {}