procwire_client/protocol/
frame.rs1use bytes::Bytes;
21
22use super::wire_format::{flags, Header, HEADER_SIZE};
23
24#[derive(Debug, Clone)]
26pub struct Frame {
27 pub header: Header,
29 pub payload: Bytes,
31}
32
33impl Frame {
34 pub fn new(header: Header, payload: Bytes) -> Self {
36 Self { header, payload }
37 }
38
39 pub fn from_parts(header: Header, payload: &[u8]) -> Self {
41 Self {
42 header,
43 payload: Bytes::copy_from_slice(payload),
44 }
45 }
46
47 #[inline]
49 pub fn payload(&self) -> &[u8] {
50 &self.payload
51 }
52
53 #[inline]
55 pub fn payload_bytes(&self) -> Bytes {
56 self.payload.clone()
57 }
58
59 #[inline]
61 pub fn payload_len(&self) -> usize {
62 self.payload.len()
63 }
64
65 #[inline]
67 pub fn method_id(&self) -> u16 {
68 self.header.method_id
69 }
70
71 #[inline]
73 pub fn flags(&self) -> u8 {
74 self.header.flags
75 }
76
77 #[inline]
79 pub fn request_id(&self) -> u32 {
80 self.header.request_id
81 }
82
83 #[inline]
85 pub fn is_response(&self) -> bool {
86 flags::has_flag(self.header.flags, flags::IS_RESPONSE)
87 }
88
89 #[inline]
91 pub fn is_error(&self) -> bool {
92 flags::has_flag(self.header.flags, flags::IS_ERROR)
93 }
94
95 #[inline]
97 pub fn is_stream(&self) -> bool {
98 flags::has_flag(self.header.flags, flags::IS_STREAM)
99 }
100
101 #[inline]
103 pub fn is_stream_end(&self) -> bool {
104 flags::has_flag(self.header.flags, flags::STREAM_END)
105 }
106
107 #[inline]
109 pub fn is_ack(&self) -> bool {
110 flags::has_flag(self.header.flags, flags::IS_ACK)
111 }
112
113 #[inline]
115 pub fn is_to_parent(&self) -> bool {
116 flags::has_flag(self.header.flags, flags::DIRECTION_TO_PARENT)
117 }
118
119 #[inline]
121 pub fn is_event(&self) -> bool {
122 self.header.request_id == 0 && !self.is_response()
123 }
124
125 #[inline]
127 pub fn is_abort(&self) -> bool {
128 self.header.is_abort()
129 }
130}
131
132pub fn build_frame(header: &Header, payload: &[u8]) -> Vec<u8> {
147 let mut buf = Vec::with_capacity(HEADER_SIZE + payload.len());
148 buf.extend_from_slice(&header.encode());
149 buf.extend_from_slice(payload);
150 buf
151}
152
153pub fn build_frame_parts<'a>(header: &Header, payload: &'a [u8]) -> ([u8; HEADER_SIZE], &'a [u8]) {
171 (header.encode(), payload)
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_frame_creation() {
180 let header = Header::new(1, flags::RESPONSE, 42, 5);
181 let payload = Bytes::from_static(b"hello");
182 let frame = Frame::new(header, payload);
183
184 assert_eq!(frame.method_id(), 1);
185 assert_eq!(frame.flags(), flags::RESPONSE);
186 assert_eq!(frame.request_id(), 42);
187 assert_eq!(frame.payload(), b"hello");
188 assert_eq!(frame.payload_len(), 5);
189 }
190
191 #[test]
192 fn test_frame_from_parts() {
193 let header = Header::new(2, 0, 100, 4);
194 let frame = Frame::from_parts(header, b"test");
195
196 assert_eq!(frame.method_id(), 2);
197 assert_eq!(frame.payload(), b"test");
198 }
199
200 #[test]
201 fn test_frame_empty_payload() {
202 let header = Header::new(1, 0, 1, 0);
203 let frame = Frame::new(header, Bytes::new());
204
205 assert_eq!(frame.payload_len(), 0);
206 assert!(frame.payload().is_empty());
207 }
208
209 #[test]
210 fn test_frame_flag_accessors() {
211 let response_frame = Frame::new(Header::new(1, flags::RESPONSE, 1, 0), Bytes::new());
213 assert!(response_frame.is_response());
214 assert!(response_frame.is_to_parent());
215 assert!(!response_frame.is_error());
216 assert!(!response_frame.is_stream());
217
218 let error_frame = Frame::new(Header::new(1, flags::ERROR_RESPONSE, 1, 0), Bytes::new());
220 assert!(error_frame.is_response());
221 assert!(error_frame.is_error());
222
223 let stream_frame = Frame::new(Header::new(1, flags::STREAM_CHUNK, 1, 0), Bytes::new());
225 assert!(stream_frame.is_stream());
226 assert!(!stream_frame.is_stream_end());
227
228 let stream_end_frame = Frame::new(
230 Header::new(1, flags::STREAM_END_RESPONSE, 1, 0),
231 Bytes::new(),
232 );
233 assert!(stream_end_frame.is_stream());
234 assert!(stream_end_frame.is_stream_end());
235
236 let ack_frame = Frame::new(Header::new(1, flags::ACK_RESPONSE, 1, 0), Bytes::new());
238 assert!(ack_frame.is_ack());
239 }
240
241 #[test]
242 fn test_frame_is_event() {
243 let event_frame = Frame::new(
245 Header::new(1, flags::DIRECTION_TO_PARENT, 0, 0),
246 Bytes::new(),
247 );
248 assert!(event_frame.is_event());
249
250 let response_frame = Frame::new(Header::new(1, flags::RESPONSE, 0, 0), Bytes::new());
252 assert!(!response_frame.is_event());
253
254 let request_frame = Frame::new(Header::new(1, 0, 42, 0), Bytes::new());
256 assert!(!request_frame.is_event());
257 }
258
259 #[test]
260 fn test_frame_is_abort() {
261 use super::super::wire_format::ABORT_METHOD_ID;
262
263 let abort_frame = Frame::new(Header::new(ABORT_METHOD_ID, 0, 0, 0), Bytes::new());
264 assert!(abort_frame.is_abort());
265
266 let normal_frame = Frame::new(Header::new(1, 0, 1, 0), Bytes::new());
267 assert!(!normal_frame.is_abort());
268 }
269
270 #[test]
271 fn test_payload_bytes_zero_copy() {
272 let original = Bytes::from_static(b"test data");
273 let frame = Frame::new(Header::new(1, 0, 1, 9), original.clone());
274
275 let cloned = frame.payload_bytes();
277 assert_eq!(cloned, original);
278
279 assert_eq!(cloned.as_ptr(), original.as_ptr());
281 }
282
283 #[test]
284 fn test_build_frame() {
285 let header = Header::new(1, flags::RESPONSE, 42, 5);
286 let bytes = build_frame(&header, b"hello");
287
288 assert_eq!(bytes.len(), HEADER_SIZE + 5);
289
290 let parsed_header = Header::decode(&bytes[..HEADER_SIZE]).unwrap();
292 assert_eq!(parsed_header, header);
293 assert_eq!(&bytes[HEADER_SIZE..], b"hello");
294 }
295
296 #[test]
297 fn test_build_frame_empty_payload() {
298 let header = Header::new(1, 0, 1, 0);
299 let bytes = build_frame(&header, b"");
300
301 assert_eq!(bytes.len(), HEADER_SIZE);
302 }
303
304 #[test]
305 fn test_build_frame_parts() {
306 let header = Header::new(1, flags::RESPONSE, 42, 5);
307 let payload = b"hello";
308 let (header_bytes, payload_ref) = build_frame_parts(&header, payload);
309
310 assert_eq!(header_bytes.len(), HEADER_SIZE);
311 assert_eq!(payload_ref, b"hello");
312
313 let parsed = Header::decode(&header_bytes).unwrap();
315 assert_eq!(parsed, header);
316 }
317
318 #[test]
319 fn test_build_frame_roundtrip() {
320 use super::super::FrameBuffer;
321
322 let header = Header::new(123, flags::STREAM_CHUNK, 456, 10);
323 let payload = b"0123456789";
324 let bytes = build_frame(&header, payload);
325
326 let mut buffer = FrameBuffer::new();
327 let frames = buffer.push(&bytes).unwrap();
328
329 assert_eq!(frames.len(), 1);
330 let frame = &frames[0];
331 assert_eq!(frame.method_id(), 123);
332 assert_eq!(frame.request_id(), 456);
333 assert_eq!(frame.payload(), payload);
334 assert!(frame.is_stream());
335 }
336}