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}