Struct DynamicBuffer

Source
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

Source

pub fn new() -> DynamicBuffer

Constructs an empty DynamicBuffer with the default allocation increment of one byte.

Source

pub fn with_increment(alloc_increment: usize) -> DynamicBuffer

Constructs an empty DynamicBuffer with a custom allocation increment.

Source

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]);
Source

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]);
Source

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

Source§

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

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

impl Index<usize> for DynamicBuffer

Source§

type Output = u8

The returned type after indexing.
Source§

fn index(&self, index: usize) -> &Self::Output

Performs the indexing (container[index]) operation. Read more
Source§

impl IndexMut<usize> for DynamicBuffer

Source§

fn index_mut(&mut self, index: usize) -> &mut Self::Output

Performs the mutable indexing (container[index]) operation. Read more
Source§

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>

Write N at offset I with context Ctx Read more
Source§

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,

Write 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>,

Write n into self at offset, with the ctx. Updates the offset.
Source§

impl TryIntoCtx<(), DynamicBuffer> for &[u8]

Source§

type Error = Error

Source§

fn try_into_ctx( self, into: &mut DynamicBuffer, _: (), ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &f32

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &f64

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &i128

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &i16

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &i32

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &i64

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &i8

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &u128

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &u16

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &u32

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &u64

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for &u8

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for f32

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for f64

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for i128

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for i16

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for i32

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for i64

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for i8

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for u128

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for u16

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for u32

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for u64

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

Source§

impl TryIntoCtx<Endian, DynamicBuffer> for u8

Source§

type Error = Error

Source§

fn try_into_ctx( self, buf: &mut DynamicBuffer, ctx: Endian, ) -> Result<usize, Self::Error>

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, 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.