Expand description
Safe wrappers around Erlang binaries.
Rustler provides three binary types: Binary
, NewBinary
and
OwnedBinary
. All represent a contiguous region u8
s, 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. Binary
s 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 NewBinary
s can be allocated on the
heap if they are small. Unlike OwnedBinary
, NewBinary
s 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.