Skip to main content

RawStack

Struct RawStack 

Source
pub struct RawStack { /* private fields */ }
Expand description

A simple raw stack that stores values as raw bytes. Each value is naturally aligned given the base alignment of the stack, which is the maximum alignment of any value stored in the stack. Live values are owned until popped, explicitly released, or destroyed in reverse push order.

Implementations§

Source§

impl RawStack

Source

pub fn with_base_alignment(base_alignment: usize) -> Self

Creates a new RawStack with base alignment.

§Examples
use cel_runtime::raw_stack::RawStack;
let stack = RawStack::with_base_alignment(align_of::<u32>());
Source

pub fn len(&self) -> usize

Returns the number of bytes currently on the stack.

Source

pub fn push<T: 'static>(&mut self, value: T) -> bool

Pushes a value of type T onto the stack.

The stack owns the value until it is popped using the correct type or destroyed. T: 'static prevents owned destructors from retaining nonstatic borrows; borrowed inputs must instead use explicitly borrowed adapters.

§Type Parameters
  • T: The type of the value to push.
§Examples
use cel_runtime::raw_stack::RawStack;
let mut stack = RawStack::with_base_alignment(align_of::<u32>());
let _ = stack.push(42u32);

A value whose destructor borrows nonstatic data cannot enter this owning stack:

ⓘ
use cel_runtime::raw_stack::RawStack;

/// Borrows text that must remain live until destruction.
struct BorrowedDrop<'a>(&'a str);
impl Drop for BorrowedDrop<'_> {
    /// Reads the borrowed text during destruction.
    fn drop(&mut self) {
        assert!(!self.0.is_empty());
    }
}

let mut stack = RawStack::with_base_alignment(align_of::<BorrowedDrop<'static>>());
{
    let text = String::from("borrowed");
    stack.push(BorrowedDrop(&text));
}
drop(stack);
§Complexity

The function has an amortized O(1) time complexity.

Source

pub unsafe fn push_raw( &mut self, align: usize, size: usize, src: *const MaybeUninit<u8>, ) -> bool

Pushes size raw bytes from src, aligned to align, using the same padding/marker-byte bookkeeping as push.

src is typed as MaybeUninit<u8> rather than u8 because the bytes being copied may include a source value’s interior padding, which is itself uninitialized — reading it through a u8 pointer instead would be undefined behavior even though this function never inspects the bytes’ values.

  • Precondition: align is a power of two.
  • Postcondition: A raw-byte slot is registered; its bytes are not destroyed as a typed value unless upgraded with own_top.
  • Complexity: Amortized O(size) time and space.
§Safety

src must be valid for reads of size bytes, and must not overlap the stack’s internal buffer.

Source

pub unsafe fn reserve_and_write( &mut self, align: usize, size: usize, write: impl FnOnce(*mut u8), ) -> bool

Reserves aligned space for size bytes (using the same padding/marker bookkeeping as push) and calls write with a pointer to that space instead of copying from a source buffer.

  • Precondition: align is a power of two.
  • Postcondition: write is called exactly once, before this method returns, with a pointer to size freshly-reserved bytes.
  • Postcondition: Normal return registers a raw-byte slot; a panicking initializer registers no slot, leaving byte restoration to its caller.
  • Complexity: Amortized O(size) plus initializer costs.
§Safety

write must fully initialize all size bytes at the pointer it’s given before returning, except interior padding. If it panics, the caller must guard partially initialized resources.

Source

pub unsafe fn copy_from( &self, offset: usize, size: usize, dst: *mut MaybeUninit<u8>, )

Copies size bytes starting at absolute buffer offset offset into dst.

dst is typed as MaybeUninit<u8> rather than u8 because the bytes being copied may be a value’s interior padding, which is itself uninitialized — reading it through a u8 pointer instead would be undefined behavior even though this function never inspects the bytes’ values.

§Safety

offset..offset + size must be within the currently-initialized buffer; dst must be valid for writes of size bytes and must not overlap the stack’s internal buffer.

Source

pub unsafe fn drop_at(&mut self, offset: usize, run_drop: impl FnOnce(*mut u8))

Drops a value in place at absolute buffer offset offset, without altering the stack’s tracked length.

§Safety

offset must point to a live, valid value; run_drop must correctly run that value’s destructor given a pointer to its start. Its ownership entry must already have been removed with release_top.

Source

pub unsafe fn read_at<R>( &self, offset: usize, read: impl FnOnce(*const u8) -> R, ) -> R

Reads a value at absolute buffer offset offset, given a callback that receives a pointer to its bytes.

§Safety

offset must point to a live, valid, properly-aligned value for the type the caller will reinterpret it as; read must not retain the pointer beyond the call. This byte operation does not transfer ownership; a caller moving out a value must explicitly release its ownership entry before destruction or stack cleanup can occur.

Source

pub unsafe fn truncate_to(&mut self, new_len: usize, padding: bool)

Truncates the stack back to new_len, additionally stripping padding bytes that preceded the removed region (scanned the same way pop does).

§Safety

No live (undropped) value may exist at or above new_len; the caller must explicitly release all removed ownership entries first. This byte operation does not infer ownership transfer, including for zero-sized values.

Source

pub unsafe fn drop_sized( &mut self, size: usize, padding: bool, run_drop: impl FnOnce(*mut u8), )

Removes the top owner’s bytes and metadata, then destroys its value in place.

§Safety

The top size bytes (plus padding if padding is true) must be a live, valid value; run_drop must correctly run its destructor given a pointer to its start. The value must have a registered top ownership entry.

Source

pub unsafe fn repack( &mut self, ambient_start: usize, dest_base: usize, total_size: usize, src_offsets: &[usize], dest_offsets: &[usize], sizes: &[usize], ) -> bool

Repacks sizes.len() already-pushed values (currently at the absolute byte offsets in src_offsets) into one contiguous, self-contained region of total_size bytes starting at dest_base, placing element i at dest_base + dest_offsets[i]. Adjusts the tracked length to dest_base + total_size and returns whether leading padding was inserted between ambient_start and dest_base.

  • Precondition: src_offsets, dest_offsets, and sizes have equal length; dest_base >= ambient_start; the source ranges are currently valid, initialized bytes.

  • Complexity: O(n) in sizes.len().

§Safety

The offsets and sizes must correctly describe the actual bytes in the buffer; no two destination ranges may overlap. src_offsets and dest_offsets must be in the same relative element order (element i’s source and destination must both be the i-th non-overlapping range in their respective layouts) — this method does not reorder elements, only re-pads between them. Given that and dest_base >= ambient_start, each element’s destination start is guaranteed to be at or after every earlier element’s source end, which is what makes processing in reverse index order below safe against clobbering not-yet-read source bytes. The caller must release ownership entries for every moved value before repacking, then register the resulting representation separately. This byte operation never infers ownership transfer.

Source

pub unsafe fn pop<T>(&mut self, padding: bool) -> T

Pops a value of type T from the stack. Does not change the stack capacity.

§Safety

The type T must be the same type as the value on the top of the stack. padding must match its push result, and the value must have a registered ownership entry. Incorrect usage can lead to undefined behavior.

§Type Parameters
  • T: The type of the value to pop.
§Examples
use cel_runtime::raw_stack::RawStack;
let mut stack = RawStack::with_base_alignment(align_of::<u32>());
let padding = stack.push(100u32);
let value: u32 = unsafe { stack.pop(padding) };
Source

pub unsafe fn drop<T>(&mut self, padding: bool)

Pops a value of type T from the stack and drops it.

§Safety

The type T must be the same type as the value on the top of the stack. Incorrect usage can lead to undefined behavior.

Removes ownership and bytes before invoking the value’s destructor.

Trait Implementations§

Source§

impl Debug for RawStack

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for RawStack

Source§

fn drop(&mut self)

Destroys every live owner in reverse order.

  • Complexity: O(n) plus destructor costs for n live slots.
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.