Byte buffers (&[u8])
A function argument typed &[u8] (or [ByRef] bytes in UDL) lets
Rust borrow a foreign-owned byte buffer for the duration of the
FFI call — no copy is made. This is useful for large payloads
(images, network frames, audio buffers) that would otherwise be
duplicated on every call.
For owned bytes, or for any case the constraints below disallow,
use Vec<u8> / bytes instead.
Usage
In Rust, declare the parameter as a borrow in the usual way:
#[uniffi::export]
pub fn parse_frame(data: &[u8]) -> Frame {
// `data` borrows the foreign buffer; valid for this call only.
...
}
In UDL, mark the parameter [ByRef] bytes:
namespace example {
Frame parse_frame([ByRef] bytes data);
};
Constraints
- Direction.
&[u8]only flows foreign → Rust. A function may take it as an argument; it cannot be returned, used in a callback result, or used as a trait-method return value. - Argument position only.
&[u8]cannot be nested inside a record, sequence, map,Option, orResult. The borrow lives only as long as the FFI call, so structures that could outlive the call are rejected. - Lifetime. The slice is valid only inside the body of the Rust
function. Don't store it, don't hand it to a spawned task, and
don't capture it in async work that outlives the call. If you need
the data afterwards, copy it (
data.to_vec()).
Foreign-language types
Each binding maps [ByRef] bytes to a natural zero-copy type:
| Binding | Foreign type | Note |
|---|---|---|
| Kotlin | java.nio.ByteBuffer |
Must be a direct buffer (ByteBuffer.allocateDirect(...)). |
| Swift | Data |
The call runs inside Data.withUnsafeBytes. |
| Python | bytes |
The bytes object's stable internal pointer is used. |
Passing a non-direct ByteBuffer from Kotlin raises an
IllegalArgumentException at the call site, matching JNA's
getDirectBufferPointer requirement.