1use std::{error::Error, fmt};
9
10use crate::{EnvelopeHeader, Flags, FrameType, MAX_FRAME_BODY_LEN, PROTOCOL_VERSION};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct Frame {
15 pub header: EnvelopeHeader,
16 pub body: Vec<u8>,
17}
18
19impl Frame {
20 pub fn build(
22 ty: FrameType,
23 flags: Flags,
24 channel: u16,
25 epoch: u32,
26 corr: u64,
27 body: Vec<u8>,
28 ) -> Result<Self, FrameBuildError> {
29 Self::build_with_version(PROTOCOL_VERSION, ty, flags, channel, epoch, corr, body)
30 }
31
32 pub fn build_with_version(
35 ver: u8,
36 ty: FrameType,
37 flags: Flags,
38 channel: u16,
39 epoch: u32,
40 corr: u64,
41 body: Vec<u8>,
42 ) -> Result<Self, FrameBuildError> {
43 if body.len() > MAX_FRAME_BODY_LEN as usize {
48 return Err(FrameBuildError::BodyExceedsMax {
49 body_len: body.len(),
50 max: MAX_FRAME_BODY_LEN,
51 });
52 }
53 let len = u32::try_from(body.len()).map_err(|_| FrameBuildError::BodyTooLarge {
54 body_len: body.len(),
55 })?;
56 Ok(Self {
57 header: EnvelopeHeader {
58 len,
59 ver,
60 ty,
61 flags,
62 channel,
63 epoch,
64 corr,
65 },
66 body,
67 })
68 }
69
70 pub fn from_wire(header: EnvelopeHeader, body: Vec<u8>) -> Self {
75 debug_assert_eq!(header.len as usize, body.len());
76 Self { header, body }
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq)]
82pub enum FrameBuildError {
83 BodyTooLarge { body_len: usize },
85 BodyExceedsMax { body_len: usize, max: u32 },
88}
89
90impl fmt::Display for FrameBuildError {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 match self {
93 Self::BodyTooLarge { body_len } => {
94 write!(f, "frame body is too large for u32 len: {body_len} bytes")
95 }
96 Self::BodyExceedsMax { body_len, max } => {
97 write!(f, "frame body {body_len} bytes exceeds max {max} bytes")
98 }
99 }
100 }
101}
102
103impl Error for FrameBuildError {}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn build_rejects_body_over_max_frame_len() {
111 let body = vec![0u8; MAX_FRAME_BODY_LEN as usize + 1];
115 let err = Frame::build(
116 FrameType::Request,
117 Flags::new(false, crate::Priority::Interactive, false),
118 1,
119 0,
120 7,
121 body,
122 )
123 .expect_err("body over the cap must be rejected");
124 assert!(matches!(
125 err,
126 FrameBuildError::BodyExceedsMax { max, .. } if max == MAX_FRAME_BODY_LEN
127 ));
128 }
129
130 #[test]
131 fn build_accepts_body_at_max_frame_len() {
132 let body = vec![0u8; MAX_FRAME_BODY_LEN as usize];
133 let frame = Frame::build(
134 FrameType::Request,
135 Flags::new(false, crate::Priority::Interactive, false),
136 1,
137 0,
138 7,
139 body,
140 )
141 .expect("body exactly at the cap is allowed");
142 assert_eq!(frame.header.len, MAX_FRAME_BODY_LEN);
143 }
144}