pub struct DynamicBuffer { /* private fields */ }
Expand description
A buffer designed for Pwrite
that dynamically expands to hold all types written into it.
Uses a standard Vec
under the hood.
§Use Cases
- You don’t know exactly how much you’re writing ahead of time.
- Your types change size depending on context parameters or specific values.
§Allocations
By default, this buffer expands every time one byte is written. The with_increment
constructor can be used to change how much the buffer expands to reduce overall number of allocations.
§Pwrite and TryIntoCtx
Types must implement TryIntoCtx
with a second generic parameter of DynamicBuffer
to be used.
use scroll::{ctx::TryIntoCtx, Error, LE, Pwrite};
use scroll_buffer::DynamicBuffer;
struct EvenOdd(u32);
impl TryIntoCtx<(), DynamicBuffer> for EvenOdd {
type Error = Error;
fn try_into_ctx(self, buf: &mut DynamicBuffer, _: ()) -> Result<usize, Self::Error> {
let offset = &mut 0;
if self.0 % 2 == 0 {
buf.gwrite_with(self.0, offset, LE)?;
} else {
buf.gwrite_with(self.0 as u64, offset, LE)?;
}
Ok(*offset)
}
}
let mut buf = DynamicBuffer::new();
let offset = buf.pwrite(EvenOdd(2), 0).unwrap();
assert_eq!(buf.get(), [2, 0, 0, 0]);
buf.pwrite(EvenOdd(3), offset).unwrap();
assert_eq!(buf.get()[offset..], [3, 0, 0, 0, 0, 0, 0, 0]);
§Why can’t I use types that already implement the default TryIntoCtx?
The default type parameters for TryIntoCtx
expose a mutable raw slice to write into.
This is great for pre-allocated buffers and types that have a static written size; however,
we cannot create a custom slice type that performs dynamic expansions under the hood.
As a result, we need to expose a separate writing type that can track offsets and calculate when to allocate.
However, if your TryIntoCtx
impls don’t use any special slice APIs and just use Pwrite
and/or
basic indexing, it’s extremely easy to migrate! Just add the DynamicBuffer
generic type.
Implementations§
Source§impl DynamicBuffer
impl DynamicBuffer
Sourcepub fn new() -> DynamicBuffer
pub fn new() -> DynamicBuffer
Constructs an empty DynamicBuffer
with the default allocation increment of one byte.
Sourcepub fn with_increment(alloc_increment: usize) -> DynamicBuffer
pub fn with_increment(alloc_increment: usize) -> DynamicBuffer
Constructs an empty DynamicBuffer
with a custom allocation increment.
Sourcepub fn get(&self) -> &[u8] ⓘ
pub fn get(&self) -> &[u8] ⓘ
Gets a slice of all written bytes. Does not include extra bytes allocated by a large increment.
use scroll::{LE, Pwrite};
use scroll_buffer::DynamicBuffer;
let mut buf = DynamicBuffer::new();
assert_eq!(buf.get(), []);
buf.pwrite_with(2u32, 0, LE).unwrap();
assert_eq!(buf.get(), [2, 0, 0, 0]);
Sourcepub fn into_vec(self) -> Vec<u8> ⓘ
pub fn into_vec(self) -> Vec<u8> ⓘ
Consumes the buffer and returns everything written to it, discarding any excess allocated zeroes.
use scroll::{LE, Pwrite};
use scroll_buffer::DynamicBuffer;
let mut buf = DynamicBuffer::with_increment(8);
buf.pwrite_with(2u32, 0, LE).unwrap();
assert_eq!(buf.into_vec(), vec![2, 0, 0, 0]);
Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Resets the buffer’s contents. Maintains already allocated capacity.
use scroll::{LE, Pwrite};
use scroll_buffer::DynamicBuffer;
let mut buf = DynamicBuffer::new();
buf.pwrite_with(2u16, 0, LE).unwrap();
assert_eq!(buf.get(), [2, 0]);
buf.clear();
assert_eq!(buf.get(), []);
// does not reallocate!
buf.pwrite_with(0xffu8, 0, LE).unwrap();
assert_eq!(buf.get(), [0xff]);
Trait Implementations§
Source§impl Debug for DynamicBuffer
impl Debug for DynamicBuffer
Source§impl Index<usize> for DynamicBuffer
impl Index<usize> for DynamicBuffer
Source§impl IndexMut<usize> for DynamicBuffer
impl IndexMut<usize> for DynamicBuffer
Source§impl<Ctx: Copy, E> Pwrite<Ctx, E> for DynamicBuffer
impl<Ctx: Copy, E> Pwrite<Ctx, E> for DynamicBuffer
Source§fn pwrite_with<N: TryIntoCtx<Ctx, Self, Error = E>>(
&mut self,
n: N,
offset: usize,
ctx: Ctx,
) -> Result<usize, E>
fn pwrite_with<N: TryIntoCtx<Ctx, Self, Error = E>>( &mut self, n: N, offset: usize, ctx: Ctx, ) -> Result<usize, E>
fn pwrite<N>(&mut self, n: N, offset: usize) -> Result<usize, E>where
N: TryIntoCtx<Ctx, Self, Error = E>,
Ctx: Default,
Source§fn gwrite<N>(&mut self, n: N, offset: &mut usize) -> Result<usize, E>where
N: TryIntoCtx<Ctx, Self, Error = E>,
Ctx: Default,
fn gwrite<N>(&mut self, n: N, offset: &mut usize) -> Result<usize, E>where
N: TryIntoCtx<Ctx, Self, Error = E>,
Ctx: Default,
n
into self
at offset
, with a default Ctx
. Updates the offset.Source§fn gwrite_with<N>(
&mut self,
n: N,
offset: &mut usize,
ctx: Ctx,
) -> Result<usize, E>where
N: TryIntoCtx<Ctx, Self, Error = E>,
fn gwrite_with<N>(
&mut self,
n: N,
offset: &mut usize,
ctx: Ctx,
) -> Result<usize, E>where
N: TryIntoCtx<Ctx, Self, Error = E>,
n
into self
at offset
, with the ctx
. Updates the offset.