rapace_core/
frame.rs

1//! Unified frame representation.
2
3use crate::MsgDescHot;
4use bytes::Bytes;
5
6/// Payload storage for a frame.
7#[derive(Debug)]
8pub enum Payload {
9    /// Payload bytes live inside `MsgDescHot::inline_payload`.
10    Inline,
11    /// Payload bytes are owned as a heap allocation.
12    Owned(Vec<u8>),
13    /// Payload bytes are stored in a ref-counted buffer (cheap clone).
14    Bytes(Bytes),
15    /// Payload bytes backed by a buffer pool (returns to pool on drop).
16    ///
17    /// Placeholder for pooled buffers (see issue #46).
18    Pooled(PooledBuf),
19    /// Payload bytes backed by a shared-memory slot guard (frees slot on drop).
20    #[cfg(feature = "shm")]
21    Shm(crate::transport::shm::SlotGuard),
22}
23
24impl Payload {
25    /// Borrow the payload as a byte slice.
26    pub fn as_slice<'a>(&'a self, desc: &'a MsgDescHot) -> &'a [u8] {
27        match self {
28            Payload::Inline => desc.inline_payload(),
29            Payload::Owned(buf) => buf.as_slice(),
30            Payload::Bytes(buf) => buf.as_ref(),
31            Payload::Pooled(buf) => buf.as_ref(),
32            #[cfg(feature = "shm")]
33            Payload::Shm(guard) => guard.as_ref(),
34        }
35    }
36
37    /// Borrow the payload as a byte slice without needing a descriptor.
38    ///
39    /// Returns `None` for [`Payload::Inline`], since inline bytes live inside
40    /// `MsgDescHot`.
41    pub fn external_slice(&self) -> Option<&[u8]> {
42        match self {
43            Payload::Inline => None,
44            Payload::Owned(buf) => Some(buf.as_slice()),
45            Payload::Bytes(buf) => Some(buf.as_ref()),
46            Payload::Pooled(buf) => Some(buf.as_ref()),
47            #[cfg(feature = "shm")]
48            Payload::Shm(guard) => Some(guard.as_ref()),
49        }
50    }
51
52    /// Returns the payload length in bytes.
53    pub fn len(&self, desc: &MsgDescHot) -> usize {
54        if let Some(ext) = self.external_slice() {
55            ext.len()
56        } else {
57            desc.payload_len as usize
58        }
59    }
60
61    /// Returns true if this payload is stored inline.
62    pub fn is_inline(&self) -> bool {
63        matches!(self, Payload::Inline)
64    }
65}
66
67/// Placeholder pooled buffer type.
68#[derive(Debug)]
69pub struct PooledBuf(Bytes);
70
71impl AsRef<[u8]> for PooledBuf {
72    fn as_ref(&self) -> &[u8] {
73        self.0.as_ref()
74    }
75}
76
77/// Owned frame for sending, receiving, or routing.
78#[derive(Debug)]
79pub struct Frame {
80    /// The frame descriptor.
81    pub desc: MsgDescHot,
82    /// Payload storage for this frame.
83    pub payload: Payload,
84}
85
86impl Frame {
87    /// Create a new frame with no payload (inline empty).
88    pub fn new(desc: MsgDescHot) -> Self {
89        Self {
90            desc,
91            payload: Payload::Inline,
92        }
93    }
94
95    /// Create a frame with inline payload.
96    pub fn with_inline_payload(mut desc: MsgDescHot, payload: &[u8]) -> Option<Self> {
97        if payload.len() > crate::INLINE_PAYLOAD_SIZE {
98            return None;
99        }
100        desc.payload_slot = crate::INLINE_PAYLOAD_SLOT;
101        desc.payload_generation = 0;
102        desc.payload_offset = 0;
103        desc.payload_len = payload.len() as u32;
104        desc.inline_payload[..payload.len()].copy_from_slice(payload);
105        Some(Self {
106            desc,
107            payload: Payload::Inline,
108        })
109    }
110
111    /// Create a frame with an owned payload allocation.
112    pub fn with_payload(mut desc: MsgDescHot, payload: Vec<u8>) -> Self {
113        desc.payload_slot = 0;
114        desc.payload_generation = 0;
115        desc.payload_offset = 0;
116        desc.payload_len = payload.len() as u32;
117        Self {
118            desc,
119            payload: Payload::Owned(payload),
120        }
121    }
122
123    /// Create a frame with a ref-counted bytes buffer.
124    pub fn with_bytes(mut desc: MsgDescHot, payload: Bytes) -> Self {
125        desc.payload_slot = 0;
126        desc.payload_generation = 0;
127        desc.payload_offset = 0;
128        desc.payload_len = payload.len() as u32;
129        Self {
130            desc,
131            payload: Payload::Bytes(payload),
132        }
133    }
134
135    /// Borrow the payload as bytes.
136    pub fn payload_bytes(&self) -> &[u8] {
137        self.payload.as_slice(&self.desc)
138    }
139}