Buffers are GPU memory regions managed via Rustler ResourceArc references. When the Elixir term holding a buffer is garbage collected, the underlying GPU memory is automatically freed.

Creating Buffers

All buffers are created from a flat list of values with a shape and type:

# 1D float vector
{:ok, buf} = ExCubecl.buffer([1.0, 2.0, 3.0, 4.0], [4], :f32)

# 2D matrix
{:ok, matrix} = ExCubecl.buffer([1.0, 2.0, 3.0, 4.0], [2, 2], :f32)

# 3D tensor (e.g. image: height x width x channels)
{:ok, image} = ExCubecl.buffer(List.duplicate(0.0, 1080 * 1920 * 3), [1080, 1920, 3], :f32)

# Integer buffer
{:ok, int_buf} = ExCubecl.buffer([10, 20, 30], [3], :s32)

# Byte buffer (e.g. raw pixel data)
{:ok, bytes} = ExCubecl.buffer([0, 128, 255], [3], :u8)

Supported types: :f32, :f64, :s32, :s64, :u32, :u8.

Reading Data

# Returns {:ok, binary}
{:ok, data} = ExCubecl.read(buf)

# Raises on error
data = ExCubecl.read!(buf)

Inspection

{:ok, [2, 2]} = ExCubecl.shape(buf)    # dimensions
{:ok, "f32"} = ExCubecl.dtype(buf)     # element type string
{:ok, 16} = ExCubecl.size(buf)         # total bytes

Automatic Memory Management

Buffers are managed via Rustler's ResourceArc mechanism. When the Elixir term holding a buffer reference is garbage collected, Rust's Drop is automatically called to free the underlying GPU memory. No manual ExCubecl.free/1 call is needed or available — the old free/1 function has been removed in favor of automatic cleanup.

buf = ExCubecl.buffer!([1.0, 2.0], [2], :f32)
data = ExCubecl.read!(buf)
# Buffer is automatically freed when `buf` is garbage collected

Internal Representation

Internally, buffers are Rustler resource references (ResourceArc<Buffer>) managed by the Rust NIF layer. The Elixir side holds an opaque reference term. All data lives in Rust memory, not in the BEAM heap. Memory is automatically released when the reference is garbage collected by the BEAM.