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 {}