Skip to main content

leodos_libcfs/cfe/sb/
send_buf.rs

1//! "Zero-copy" buffer management for sending messages.
2use core::mem;
3use core::slice;
4
5use crate::cfe::sb::msg::MessageMut;
6use crate::error::{CfsError, SbError};
7use crate::error::Result;
8use crate::ffi;
9
10/// An owned, writable "zero-copy" software bus message buffer.
11///
12/// This struct safely manages a memory buffer allocated directly from CFE's
13/// internal pool. You can get a writable view of it using `MessageMut::from()`
14/// and then send it with zero memory copies.
15///
16/// If the buffer is dropped without being sent, it is automatically released
17/// back to the CFE pool, preventing memory leaks.
18#[derive(Debug)]
19pub struct SendBuffer {
20    pub(crate) ptr: *mut ffi::CFE_SB_Buffer_t,
21    pub(crate) size: usize,
22}
23
24impl SendBuffer {
25    /// Allocates a new zero-copy send buffer of the specified size from the CFE SB pool.
26    pub fn new(size: usize) -> Result<Self> {
27        let ptr = unsafe { ffi::CFE_SB_AllocateMessageBuffer(size) };
28        if ptr.is_null() {
29            Err(CfsError::Sb(SbError::BufAllocErr))
30        } else {
31            Ok(Self { ptr, size })
32        }
33    }
34
35    /// Transmits the message in this buffer.
36    ///
37    /// This consumes the `SendBuffer`, transferring ownership of the
38    /// memory to CFE. After this call, the buffer is no longer
39    /// accessible from Rust.
40    ///
41    /// On failure, the caller still owns the buffer (state is
42    /// unchanged) and the `Drop` impl will release it.
43    ///
44    /// # Arguments
45    /// * `is_origination`: Set to `true` to have CFE automatically fill in fields like
46    ///   sequence count and timestamp. Set to `false` when forwarding a message.
47    pub fn send(self, is_origination: bool) -> Result<()> {
48        let status = unsafe { ffi::CFE_SB_TransmitBuffer(self.ptr, is_origination) };
49
50        if status == ffi::CFE_SUCCESS {
51            // CFE now owns the buffer. We call mem::forget to prevent our Drop logic
52            // from running to avoid a double-free.
53            mem::forget(self);
54            Ok(())
55        } else {
56            Err(CfsError::from(status))
57        }
58    }
59
60    /// Returns a read-only slice view of the buffer's contents.
61    pub fn view(&mut self) -> MessageMut<'_> {
62        MessageMut {
63            slice: unsafe { slice::from_raw_parts_mut(self.ptr as *mut u8, self.size) },
64        }
65    }
66
67    /// Returns the raw byte slice of the buffer's contents.
68    pub fn as_slice(&self) -> &[u8] {
69        unsafe { slice::from_raw_parts(self.ptr as *const u8, self.size) }
70    }
71
72    /// Returns the raw mutable byte slice of the buffer's contents.
73    pub fn as_mut_slice(&mut self) -> &mut [u8] {
74        unsafe { slice::from_raw_parts_mut(self.ptr as *mut u8, self.size) }
75    }
76}
77
78impl Drop for SendBuffer {
79    /// Automatically releases the buffer back to the CFE pool if it hasn't been sent.
80    fn drop(&mut self) {
81        // This is the cleanup path for when a SendBuffer is created but never sent.
82        let _ = unsafe { ffi::CFE_SB_ReleaseMessageBuffer(self.ptr) };
83    }
84}