Struct ffi_support::ByteBuffer [−][src]
ByteBuffer is a struct that represents an array of bytes to be sent over the FFI boundaries. There are several cases when you might want to use this, but the primary one for us is for returning protobuf-encoded data to Swift and Java. The type is currently rather limited (implementing almost no functionality), however in the future it may be more expanded.
Caveats
Note that the order of the fields is len
(an i64) then data
(a *mut u8
), getting
this wrong on the other side of the FFI will cause memory corruption and crashes.
i64
is used for the length instead of u64
and usize
because JNA has interop
issues with both these types.
Drop
is not implemented
ByteBuffer does not implement Drop. This is intentional. Memory passed into it will
be leaked if it is not explicitly destroyed by calling ByteBuffer::destroy
, or
ByteBuffer::destroy_into_vec
. This is for two reasons:
-
In the future, we may allow it to be used for data that is not managed by the Rust allocator*, and
ByteBuffer
assuming it’s okay to automatically deallocate this data with the Rust allocator. -
Automatically running destructors in unsafe code is a frequent footgun (among many similar issues across many crates).
Note that calling destroy
manually is often not needed, as usually you should
be passing these to the function defined by define_bytebuffer_destructor!
from
the other side of the FFI.
Because this type is essentially only useful in unsafe or FFI code (and because
the most common usage pattern does not require manually managing the memory), it
does not implement Drop
.
* Note: in the case of multiple Rust shared libraries loaded at the same time,
there may be multiple instances of “the Rust allocator” (one per shared library),
in which case we’re referring to whichever instance is active for the code using
the ByteBuffer
. Note that this doesn’t occur on all platforms or build
configurations, but treating allocators in different shared libraries as fully
independent is always safe.
Layout/fields
This struct’s field are not pub
(mostly so that we can soundly implement Send
, but also so
that we can verify rust users are constructing them appropriately), the fields, their types, and
their order are very much a part of the public API of this type. Consumers on the other side
of the FFI will need to know its layout.
If this were a C struct, it would look like
struct ByteBuffer {
// Note: This should never be negative, but values above
// INT64_MAX / i64::MAX are not allowed.
int64_t len;
// Note: nullable!
uint8_t *data;
};
In rust, there are two fields, in this order: len: i64
, and data: *mut u8
.
For clarity, the fact that the data pointer is nullable means that Option<ByteBuffer>
is not
the same size as ByteBuffer, and additionally is not FFI-safe (the latter point is not
currently guaranteed anyway as of the time of writing this comment).
Description of fields
data
is a pointer to an array of len
bytes. Note that data can be a null pointer and therefore
should be checked.
The bytes array is allocated on the heap and must be freed on it as well. Critically, if there are multiple rust shared libraries using being used in the same application, it must be freed on the same heap that allocated it, or you will corrupt both heaps.
Typically, this object is managed on the other side of the FFI (on the “FFI consumer”), which
means you must expose a function to release the resources of data
which can be done easily
using the define_bytebuffer_destructor!
macro provided by this crate.
Implementations
impl ByteBuffer
[src]
pub fn new_with_size(size: usize) -> Self
[src]
Creates a ByteBuffer
of the requested size, zero-filled.
The contents of the vector will not be dropped. Instead, destroy
must
be called later to reclaim this memory or it will be leaked.
Caveats
This will panic if the buffer length (usize
) cannot fit into a i64
.
pub fn from_vec(bytes: Vec<u8>) -> Self
[src]
Creates a ByteBuffer
instance from a Vec
instance.
The contents of the vector will not be dropped. Instead, destroy
must
be called later to reclaim this memory or it will be leaked.
Caveats
This will panic if the buffer length (usize
) cannot fit into a i64
.
pub fn as_slice(&self) -> &[u8]
[src]
View the data inside this ByteBuffer
as a &[u8]
.
pub fn as_mut_slice(&mut self) -> &mut [u8]
[src]
View the data inside this ByteBuffer
as a &mut [u8]
.
pub fn into_vec(self) -> Vec<u8>
[src]
Name is confusing, please use destroy_into_vec
instead
Deprecated alias for ByteBuffer::destroy_into_vec
.
pub fn destroy_into_vec(self) -> Vec<u8>
[src]
Convert this ByteBuffer
into a VecVec<u8>
’s lifetime is done.
If this is undesirable, you can do bb.as_slice().to_vec()
to get a
Vec<u8>
containing a copy of this ByteBuffer
’s underlying data.
Caveats
This is safe so long as the buffer is empty, or the data was allocated
by Rust code, e.g. this is a ByteBuffer created by
ByteBuffer::from_vec
or Default::default
.
If the ByteBuffer were allocated by something other than the
current/local Rust global_allocator
, then calling destroy
is
fundamentally broken.
For example, if it were allocated externally by some other language’s runtime, or if it were allocated by the global allocator of some other Rust shared object in the same application, the behavior is undefined (and likely to cause problems).
Note that this currently can only happen if the ByteBuffer
is passed
to you via an extern "C"
function that you expose, as opposed to being
created locally.
pub fn destroy(self)
[src]
Reclaim memory stored in this ByteBuffer.
You typically should not call this manually, and instead expose a
function that does so via define_bytebuffer_destructor!
.
Caveats
This is safe so long as the buffer is empty, or the data was allocated
by Rust code, e.g. this is a ByteBuffer created by
ByteBuffer::from_vec
or Default::default
.
If the ByteBuffer were allocated by something other than the
current/local Rust global_allocator
, then calling destroy
is
fundamentally broken.
For example, if it were allocated externally by some other language’s runtime, or if it were allocated by the global allocator of some other Rust shared object in the same application, the behavior is undefined (and likely to cause problems).
Note that this currently can only happen if the ByteBuffer
is passed
to you via an extern "C"
function that you expose, as opposed to being
created locally.
Trait Implementations
impl Default for ByteBuffer
[src]
impl From<Vec<u8, Global>> for ByteBuffer
[src]
impl IntoFfi for ByteBuffer
[src]
type Value = ByteBuffer
This type must be: Read more
fn ffi_default() -> Self::Value
[src]
fn into_ffi_value(self) -> Self::Value
[src]
Auto Trait Implementations
impl RefUnwindSafe for ByteBuffer
impl !Send for ByteBuffer
impl !Sync for ByteBuffer
impl Unpin for ByteBuffer
impl UnwindSafe for ByteBuffer
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,