Module rustler::types::binary

source ·
Expand description

Safe wrappers around Erlang binaries.

Rustler provides three binary types: Binary, NewBinary and OwnedBinary. All represent a contiguous region u8s, and they all use the Erlang allocator. The primary difference between them is their ownership semantics.

The owned in OwnedBinary refers to the fact that it owns the binary it wraps. The owner of an OwnedBinary is free to modify its contents. Ownership lasts until it is dropped or consumed by converting it into a regular Binary. An OwnedBinary cannot be copied or cloned and is thus always moved.

The Binary type is an immutable shared-reference to a binary. Binarys are cheap to copy: all copies of a Binary point to the original Binary’s data. Additionally, a Binary’s lifetime is tied to that of the NIF’s Env, preventing outstanding references to the data after a NIF returns.

NewBinary is a way of creating a Binary without going via OwnedBinary. This can improve performance, since NewBinarys can be allocated on the heap if they are small. Unlike OwnedBinary, NewBinarys lifetime is tied to that of the NIF’s Env. NewBinary must be converted to a Binary or directly to a Term before it can be passed to Erlang.

§Examples

Constructing an OwnedBinary:

{
    let mut bin = OwnedBinary::new(5).expect("allocation failed");
    bin.as_mut_slice().copy_from_slice("hello".as_bytes());
} // <- `bin` is dropped here

The following NIF takes a binary as its only parameter and returns a new binary where each element is exclusive-or’ed with a constant:

#[rustler::nif]
fn xor_example<'a>(env: Env<'a>, bin: Binary<'a>) -> NifResult<Binary<'a>> {
    let mut owned: OwnedBinary = bin.to_owned().ok_or(Error::Term(Box::new("no mem")))?;
    for byte in owned.as_mut_slice() {
        *byte ^= 0xAA;
    }

    // Ownership of `owned`'s data is transferred to `env` on the
    // following line, so no additional heap allocations are incurred.
    Ok(Binary::from_owned(owned, env))
}

The contents of a newly-allocated OwnedBinary is not initialized to any particular value. If your usage of the binary requires the it’s data to be zeroed, for example, then you must explicit zero it. In this example, we manually zeroize the binary before passing it as slice to a third party function.

#[rustler::nif]
fn wrapper_for_some_<'a>(env: Env<'a>) -> NifResult<Binary<'a>> {
    let mut owned = OwnedBinary::new(100).ok_or(Error::Term(Box::new("no mem")))?;
    for byte in owned.as_mut_slice() {
        *byte = 0;
    }

    // Some third party API which requires the slice to be all zeros on entry.
    some_third_party_api(owned.as_mut_slice());

    // The imaginary API call presumedly filled in our binary with meaningful
    // data, so let's return it.
    Ok(Binary::from_owned(owned, env))
}

Structs§

  • An immutable smart-pointer to an Erlang binary.
  • An newly-created, mutable Erlang binary.
  • An mutable smart-pointer to an Erlang binary.