pub struct PluginRingBuffer<'a> { /* private fields */ }Expand description
A circular command buffer backed by a shared linear memory slice.
The buffer is intentionally not thread-safe; it is intended for single- producer/single-consumer use between the plugin guest and the host render thread. All hot-path reads return borrowed slices and perform no allocation.
§Examples
use martensite_plugin::{PluginPaintCmd, PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let mut rb = PluginRingBuffer::new(&mut backing);
let cmd = PluginPaintCmd {
cmd_type: 1,
flags: 0,
data_len: 4,
payload_offset: 0,
};
rb.produce(&cmd, &[1, 2, 3, 4]).unwrap();
let (read_cmd, payload) = rb.consume().unwrap();
assert_eq!(read_cmd.cmd_type, 1);
assert_eq!(payload, &[1, 2, 3, 4]);Implementations§
Source§impl<'a> PluginRingBuffer<'a>
impl<'a> PluginRingBuffer<'a>
Sourcepub fn new(data: &'a mut [u8]) -> Self
pub fn new(data: &'a mut [u8]) -> Self
Creates a ring buffer over the supplied shared memory slice.
The slice must be large enough for at least one command header plus a
small payload. The buffer starts empty and the cursors are held only
in this struct; use PluginRingBuffer::new_shared when the slice is
a region shared with another party (e.g. guest linear memory).
§Examples
use martensite_plugin::{PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let rb = PluginRingBuffer::new(&mut backing);
assert!(rb.is_empty());Creates a ring buffer over a shared memory region with a persisted cursor header.
The first SHARED_HEADER_SIZE bytes of data are interpreted as the
head/tail cursor block (little-endian u32 each); the rest is the
circular payload area. Cursors are read on construction and written
back after every produce/consume
so a peer sharing the same region sees consistent state. Corrupt
out-of-range cursors reset the buffer to empty.
§Examples
use martensite_plugin::ring_buffer::SHARED_HEADER_SIZE;
use martensite_plugin::{PluginPaintCmd, PluginRingBuffer};
// 8-byte cursor header + 64 bytes of payload area.
let mut region = vec![0u8; SHARED_HEADER_SIZE + 64];
let mut rb = PluginRingBuffer::new_shared(&mut region);
let cmd = PluginPaintCmd {
cmd_type: 1,
flags: 0,
data_len: 4,
payload_offset: 0,
};
rb.produce(&cmd, &[1, 2, 3, 4]).unwrap();
// The peer can observe `tail` in the header.
assert_eq!(u32::from_le_bytes(region[4..8].try_into().unwrap()), 16);Sourcepub fn capacity(&self) -> usize
pub fn capacity(&self) -> usize
Returns the total capacity of the buffer in bytes.
§Examples
use martensite_plugin::{PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let rb = PluginRingBuffer::new(&mut backing);
assert_eq!(rb.capacity(), DEFAULT_CAPACITY);Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Returns the number of bytes currently stored in the buffer.
§Examples
use martensite_plugin::{PluginPaintCmd, PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let mut rb = PluginRingBuffer::new(&mut backing);
assert_eq!(rb.len(), 0);
let cmd = PluginPaintCmd { cmd_type: 1, flags: 0, data_len: 0, payload_offset: 0 };
rb.produce(&cmd, &[]).unwrap();
assert_eq!(rb.len(), PluginPaintCmd::header_size());Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns true if the buffer contains no commands.
§Examples
use martensite_plugin::{PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let rb = PluginRingBuffer::new(&mut backing);
assert!(rb.is_empty());Sourcepub fn produce(
&mut self,
cmd: &PluginPaintCmd,
payload: &[u8],
) -> Result<(), RingBufferError>
pub fn produce( &mut self, cmd: &PluginPaintCmd, payload: &[u8], ) -> Result<(), RingBufferError>
Writes a command and its payload into the ring buffer.
The payload_offset field of cmd is ignored; it is overwritten with
the actual offset of the payload in the buffer. data_len must match
payload.len(). Records are never split across the buffer boundary.
§Errors
Returns RingBufferError::PayloadLengthMismatch if cmd.data_len does
not equal payload.len(), or RingBufferError::BufferFull if the
command does not fit.
§Examples
use martensite_plugin::{PluginPaintCmd, PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let mut rb = PluginRingBuffer::new(&mut backing);
let cmd = PluginPaintCmd {
cmd_type: 2,
flags: 0,
data_len: 6,
payload_offset: 0,
};
rb.produce(&cmd, &[9; 6]).unwrap();Sourcepub fn consume(&mut self) -> Option<(PluginPaintCmd, &[u8])>
pub fn consume(&mut self) -> Option<(PluginPaintCmd, &[u8])>
Reads and removes the next command from the ring buffer.
Returns None when the buffer is empty or the next record is malformed.
The returned payload is a borrowed view into the underlying shared
memory, so no allocation occurs on the readback hot path.
§Examples
use martensite_plugin::{PluginPaintCmd, PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let mut rb = PluginRingBuffer::new(&mut backing);
let cmd = PluginPaintCmd {
cmd_type: 0,
flags: 0,
data_len: 0,
payload_offset: 0,
};
rb.produce(&cmd, &[]).unwrap();
let (read_cmd, payload) = rb.consume().unwrap();
assert_eq!(payload.len(), 0);
assert_eq!(read_cmd.cmd_type, 0);Sourcepub fn drain<F>(&mut self, f: F)
pub fn drain<F>(&mut self, f: F)
Drains all currently available commands from the buffer, invoking the provided closure for each command and its borrowed payload.
This is the preferred host readback API because it keeps all reads zero-allocation and bounded.
§Examples
use martensite_plugin::{PluginPaintCmd, PluginRingBuffer, DEFAULT_CAPACITY};
let mut backing = vec![0u8; DEFAULT_CAPACITY];
let mut rb = PluginRingBuffer::new(&mut backing);
let cmd = PluginPaintCmd {
cmd_type: 1,
flags: 0,
data_len: 2,
payload_offset: 0,
};
rb.produce(&cmd, &[10, 20]).unwrap();
rb.produce(&cmd, &[30, 40]).unwrap();
let mut count = 0;
rb.drain(|_cmd, payload| {
count += 1;
assert_eq!(payload.len(), 2);
});
assert_eq!(count, 2);Auto Trait Implementations§
impl<'a> !UnwindSafe for PluginRingBuffer<'a>
impl<'a> Freeze for PluginRingBuffer<'a>
impl<'a> RefUnwindSafe for PluginRingBuffer<'a>
impl<'a> Send for PluginRingBuffer<'a>
impl<'a> Sync for PluginRingBuffer<'a>
impl<'a> Unpin for PluginRingBuffer<'a>
impl<'a> UnsafeUnpin for PluginRingBuffer<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> GetSetFdFlags for T
impl<T> GetSetFdFlags for T
Source§fn get_fd_flags(&self) -> Result<FdFlags, Error>where
T: AsFilelike,
fn get_fd_flags(&self) -> Result<FdFlags, Error>where
T: AsFilelike,
self file descriptor.Source§fn new_set_fd_flags(&self, fd_flags: FdFlags) -> Result<SetFdFlags<T>, Error>where
T: AsFilelike,
fn new_set_fd_flags(&self, fd_flags: FdFlags) -> Result<SetFdFlags<T>, Error>where
T: AsFilelike,
Source§fn set_fd_flags(&mut self, set_fd_flags: SetFdFlags<T>) -> Result<(), Error>where
T: Sized + AsFilelike,
fn set_fd_flags(&mut self, set_fd_flags: SetFdFlags<T>) -> Result<(), Error>where
T: Sized + AsFilelike,
self file descriptor. Read moreSource§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more