rapace_core/
frame.rs

1//! Frame types for sending and receiving.
2
3use crate::MsgDescHot;
4
5/// Owned frame for sending or storage.
6#[derive(Debug, Clone)]
7pub struct Frame {
8    /// The frame descriptor.
9    pub desc: MsgDescHot,
10    /// Optional payload (None if inline or empty).
11    pub payload: Option<Vec<u8>>,
12}
13
14impl Frame {
15    /// Create a new frame with the given descriptor.
16    pub fn new(desc: MsgDescHot) -> Self {
17        Self {
18            desc,
19            payload: None,
20        }
21    }
22
23    /// Create a frame with inline payload.
24    pub fn with_inline_payload(mut desc: MsgDescHot, payload: &[u8]) -> Option<Self> {
25        if payload.len() > crate::INLINE_PAYLOAD_SIZE {
26            return None;
27        }
28        desc.payload_slot = crate::INLINE_PAYLOAD_SLOT;
29        desc.payload_generation = 0;
30        desc.payload_offset = 0;
31        desc.payload_len = payload.len() as u32;
32        desc.inline_payload[..payload.len()].copy_from_slice(payload);
33        Some(Self {
34            desc,
35            payload: None,
36        })
37    }
38
39    /// Create a frame with external payload.
40    ///
41    /// Note: For owned frames with external payload, we use a sentinel slot value (0)
42    /// to distinguish from inline. The actual slot is only meaningful for SHM transport.
43    pub fn with_payload(mut desc: MsgDescHot, payload: Vec<u8>) -> Self {
44        // Mark as non-inline by setting slot to 0 (or any non-MAX value)
45        // This is a sentinel for "payload is in the Frame::payload field"
46        desc.payload_slot = 0;
47        desc.payload_len = payload.len() as u32;
48        Self {
49            desc,
50            payload: Some(payload),
51        }
52    }
53
54    /// Get the payload bytes.
55    pub fn payload(&self) -> &[u8] {
56        if self.desc.is_inline() {
57            self.desc.inline_payload()
58        } else {
59            self.payload.as_deref().unwrap_or(&[])
60        }
61    }
62}
63
64/// Borrowed view of a frame for zero-copy receive.
65///
66/// Lifetime is tied to the receive call that produced it.
67/// Caller must process or copy before calling recv_frame again.
68#[derive(Debug)]
69pub struct FrameView<'a> {
70    /// Reference to the frame descriptor.
71    pub desc: &'a MsgDescHot,
72    /// Reference to the payload bytes.
73    pub payload: &'a [u8],
74}
75
76impl<'a> FrameView<'a> {
77    /// Create a new frame view.
78    pub fn new(desc: &'a MsgDescHot, payload: &'a [u8]) -> Self {
79        Self { desc, payload }
80    }
81
82    /// Convert to an owned Frame (copies payload if needed).
83    pub fn to_owned(&self) -> Frame {
84        if self.desc.is_inline() {
85            Frame {
86                desc: *self.desc,
87                payload: None,
88            }
89        } else {
90            Frame {
91                desc: *self.desc,
92                payload: Some(self.payload.to_vec()),
93            }
94        }
95    }
96}