pub struct ObjectStack { /* private fields */ }
Expand description
A high-level stack-based object builder that uses StackArena
for memory management.
ObjectStack
provides a more user-friendly interface on top of StackArena
for
building and managing objects in a stack-like fashion. It supports incremental
object construction through the extend
and finish
methods, as well as
direct formatting through the std::fmt::Write
trait.
§Features
- Push objects onto the stack with move or copy semantics
- Push byte slices onto the stack
- Build objects incrementally using
extend
andfinish
methods - Implements
std::fmt::Write
for string formatting directly into objects - Stack-like (LIFO) allocation and deallocation pattern
- Memory-efficient with minimal overhead
- Automatic memory management with chunk reuse
§Use Cases
ObjectStack
is particularly useful for:
- String building and text processing
- Constructing complex objects incrementally
- Serialization operations
- Any scenario where objects need to be built in stages
§Examples
use stack_arena::ObjectStack;
use std::fmt::Write;
let mut stack = ObjectStack::new();
// Push bytes onto the stack
stack.push_bytes(b"hello");
// Push a value with move semantics
let string = String::from("world");
stack.push(string); // string is moved
// Push a value with copy semantics
let value = 42;
stack.push_copy(&value);
// Build an object incrementally
stack.extend("incremental ");
write!(&mut stack, "from {}", "Rust").unwrap();
let ptr = stack.finish();
// Access the object
let message = unsafe { std::str::from_utf8_unchecked(ptr.as_ref()) };
assert_eq!(message, "incremental from Rust");
// Pop the object when done
stack.pop();
Implementations§
Source§impl ObjectStack
impl ObjectStack
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty ObjectStack
with a default initial capacity.
The initial chunk size is 1024 bytes, managed by the underlying StackArena
.
§Examples
use stack_arena::ObjectStack;
let stack = ObjectStack::new();
assert!(stack.is_empty());
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Returns the number of objects currently on the stack.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
assert_eq!(stack.len(), 0);
stack.push_bytes(b"hello");
assert_eq!(stack.len(), 1);
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns true
if the stack contains no objects.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
assert!(stack.is_empty());
stack.push_bytes(b"hello");
assert!(!stack.is_empty());
Sourcepub fn push_bytes<P: AsRef<[u8]>>(&mut self, object: P) -> NonNull<[u8]>
pub fn push_bytes<P: AsRef<[u8]>>(&mut self, object: P) -> NonNull<[u8]>
Pushes a byte slice onto the stack.
This method allocates memory for the byte slice, copies the data, and returns a pointer to the allocated memory.
§Parameters
object
- The data to push onto the stack, which can be any type that can be converted to a byte slice.
§Returns
A non-null pointer to the allocated memory containing the data.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
let ptr = stack.push_bytes(b"hello world");
// The pointer is valid until the object is popped or freed
Sourcepub fn push_copy<T>(&mut self, object: &T) -> NonNull<T>
pub fn push_copy<T>(&mut self, object: &T) -> NonNull<T>
Pushes a copy of a value onto the stack.
This method takes a reference to a value that implements the Copy
trait,
makes a bitwise copy of it, and pushes it onto the stack.
§Parameters
object
- A reference to the value to copy onto the stack.
§Returns
A non-null pointer to the allocated memory containing the copied value.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
// Copy a primitive value
let value = 42;
let ptr = stack.push_copy(&value);
// Copy a struct that implements Copy
#[derive(Copy, Clone)]
struct Point { x: i32, y: i32 }
let point = Point { x: 10, y: 20 };
let point_ptr = stack.push_copy(&point);
Sourcepub fn push<T>(&mut self, object: T) -> NonNull<T>where
T: Sized,
pub fn push<T>(&mut self, object: T) -> NonNull<T>where
T: Sized,
Pushes a value onto the stack with move semantics.
This method takes ownership of the value, moves it onto the stack, and returns a pointer to the allocated memory.
§Important Safety Notes
- For types that implement
Drop
, the destructor will not be called automatically when the object is popped or the stack is dropped. You must calldrop_in_place
explicitly when you’re done with the object. - Modifying the object through the returned pointer (e.g., pushing more bytes onto
a
String
) is undefined behavior if it would change the object’s size or layout. - The memory layout is fixed after allocation and cannot be resized.
§Parameters
object
- The value to move onto the stack.
§Returns
A non-null pointer to the allocated memory containing the moved value.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
// Move a String onto the stack
let string = String::from("hello world");
let ptr = stack.push(string);
// string is moved and no longer accessible
// Use the string...
unsafe {
let s = ptr.as_ref();
assert_eq!(s, "hello world");
}
// When done, explicitly drop it
unsafe {
stack.drop_in_place(ptr);
}
// Move a custom struct onto the stack
struct Person {
name: String,
age: u32,
}
let person = Person {
name: String::from("Alice"),
age: 30,
};
let person_ptr = stack.push(person);
// person is moved and no longer accessible
// Don't forget to drop it when done
unsafe {
stack.drop_in_place(person_ptr);
}
Sourcepub unsafe fn drop_in_place<T>(&mut self, ptr: NonNull<T>)
pub unsafe fn drop_in_place<T>(&mut self, ptr: NonNull<T>)
Drops a value in place without deallocating its memory.
This method calls the destructor for a value previously pushed onto the stack
with push
. It’s useful for types that implement Drop
and need cleanup.
The memory itself is not freed until the object is popped or the stack is dropped.
§User Responsibility
It is the user’s responsibility to call this method for any values that implement
Drop
. Failure to do so may result in resource leaks (e.g., unclosed files,
unfreed memory from heap allocations inside the object).
§Safety
This method is unsafe because:
- The pointer must have been obtained from
push<T>
with the same typeT
- The value must not have been previously dropped
- The memory must not be accessed after calling this method
§Examples
use stack_arena::ObjectStack;
use std::fs::File;
let mut stack = ObjectStack::new();
// Push a value that needs dropping
let string = String::from("hello world");
let ptr = stack.push(string);
// Use the string...
// When done, drop it in place
unsafe {
stack.drop_in_place(ptr);
}
// The memory is still allocated but the string is dropped
Sourcepub fn pop(&mut self)
pub fn pop(&mut self)
Removes the most recently pushed object from the stack.
This method follows the LIFO (Last-In-First-Out) principle. After popping, any pointers to the popped object become invalid.
§Panics
Panics if the stack is empty or if there is a partial object
being built (i.e., if extend
has been called but finish
has not).
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
stack.push_bytes(b"hello");
stack.push_bytes(b"world");
assert_eq!(stack.len(), 2);
stack.pop();
assert_eq!(stack.len(), 1);
Sourcepub fn extend<P: AsRef<[u8]>>(&mut self, value: P)
pub fn extend<P: AsRef<[u8]>>(&mut self, value: P)
Extends the current object being built with additional data.
This method is used for incrementally building objects. Multiple calls to
extend
can be made before finalizing the object with finish
. This method
only supports extending the last allocation (following LIFO pattern),
as it uses the underlying arena’s grow functionality.
§Parameters
value
- The data to append to the current object, which can be any type that can be converted to a byte slice.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
stack.extend("Hello, ");
stack.extend("world!");
let ptr = stack.finish();
// ptr now points to "Hello, world!"
Sourcepub fn finish(&mut self) -> NonNull<[u8]>
pub fn finish(&mut self) -> NonNull<[u8]>
Finalizes the current object being built and adds it to the stack.
This method should be called after one or more calls to extend
to
finalize the object and make it available on the stack.
§Returns
A non-null pointer to the finalized object.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
stack.extend("Hello");
stack.extend(" world");
let ptr = stack.finish();
// ptr now points to "Hello world"
Sourcepub fn rollback(&mut self, data: &[u8])
pub fn rollback(&mut self, data: &[u8])
Rolls back to a specific object, freeing it and all objects allocated after it.
This method allows for rolling back to a specific point in the allocation history by providing a reference to an object on the stack.
§Parameters
data
- A reference to the object to free, along with all objects allocated after it.
§Examples
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
stack.push_bytes(b"first");
let second = stack.push_bytes(b"second");
stack.push_bytes(b"third");
// Free "second" and "third"
stack.rollback(unsafe { second.as_ref() });
assert_eq!(stack.len(), 1); // Only "first" remains
Trait Implementations§
Source§impl Debug for ObjectStack
impl Debug for ObjectStack
Source§impl Write for ObjectStack
Implementation of the std::fmt::Write
trait for ObjectStack
.
impl Write for ObjectStack
Implementation of the std::fmt::Write
trait for ObjectStack
.
This allows using the write!
macro and other formatting utilities
to write formatted text directly into the object being built.
§Examples
use std::fmt::Write;
use stack_arena::ObjectStack;
let mut stack = ObjectStack::new();
write!(&mut stack, "Hello, {}!", "world").unwrap();
let formatted = stack.finish();
// formatted now points to "Hello, world!"