Skip to main content

BufferHandle

Struct BufferHandle 

Source
pub struct BufferHandle { /* private fields */ }
Expand description

A declaration of a buffer’s size, alignment, device location, and sync mode.

A BufferHandle is the in-memory representation of the 16-byte buffer handle entry in the tensor descriptor’s buffer table (see docs/spec/metadata.md § Buffer Table). It carries the metadata needed to locate and access a buffer but does not itself hold a pointer — the actual memory address is communicated out-of-band via the interchange protocol or the C ABI (see docs/impl/c-ffi.md).

§Wire layout (ADR-018 § 3, ADR-020)

OffsetFieldTypeSize
0byte_sizeuint64 LE8
8alignmentuint32 LE4
12device_taguint81
13sync_modeuint81
14memory_classuint81
15_reserveduint81

§Alignment rules

  • alignment MUST be a power of two.
  • For non-empty buffers (byte_size > 0): alignment MUST be at least MIN_BUFFER_ALIGNMENT (64 bytes).
  • For empty buffers (byte_size == 0): any power-of-two alignment is valid, including 1. A reader MUST NOT dereference the pointer of an empty buffer.

See docs/spec/buffer-protocol.md § Alignment for the normative rules.

§Examples

use hurray_core::{BufferHandle, DeviceTag, MemoryClass, SyncMode, MIN_BUFFER_ALIGNMENT};

// Non-empty CPU buffer, minimum SIMD alignment, default Standard class.
let handle = BufferHandle::new(1024, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
assert_eq!(handle.byte_size(), 1024);
assert_eq!(handle.alignment(), 64);
assert_eq!(handle.device_tag(), DeviceTag::Cpu);
assert_eq!(handle.sync_mode(), SyncMode::ProducerSynced);
assert_eq!(handle.memory_class(), MemoryClass::Standard);
assert!(!handle.is_empty());

// CUDA buffer with Unified memory class.
let unified = BufferHandle::with_memory_class(
    4096, 4096, DeviceTag::Cuda, SyncMode::ProducerSynced, MemoryClass::Unified,
).unwrap();
assert_eq!(unified.memory_class(), MemoryClass::Unified);

// Empty buffer — alignment 1 is valid.
let empty = BufferHandle::empty(DeviceTag::Cuda);
assert!(empty.is_empty());
assert_eq!(empty.alignment(), 1);

Implementations§

Source§

impl BufferHandle

Source

pub fn new( byte_size: u64, alignment: u32, device_tag: DeviceTag, sync_mode: SyncMode, ) -> Result<Self>

Creates a new BufferHandle with the given size, alignment, device, and sync mode.

§Errors
§Examples
use hurray_core::{BufferHandle, DeviceTag, Error, SyncMode, MIN_BUFFER_ALIGNMENT};

// Valid: non-empty CPU buffer with minimum SIMD alignment.
assert!(BufferHandle::new(512, 64, DeviceTag::Cpu, SyncMode::ProducerSynced).is_ok());

// Valid: CUDA buffer with Event sync.
assert!(BufferHandle::new(512, 64, DeviceTag::Cuda, SyncMode::Event).is_ok());

// Valid: empty buffer with alignment 1.
assert!(BufferHandle::new(0, 1, DeviceTag::Cpu, SyncMode::ProducerSynced).is_ok());

// Error: alignment is not a power of two.
assert!(matches!(
    BufferHandle::new(512, 3, DeviceTag::Cpu, SyncMode::ProducerSynced),
    Err(Error::AlignmentNotPowerOfTwo { alignment: 3 })
));

// Error: non-empty buffer with alignment below the 64-byte minimum.
assert!(matches!(
    BufferHandle::new(512, 32, DeviceTag::Cpu, SyncMode::ProducerSynced),
    Err(Error::AlignmentBelowMinimum { alignment: 32, minimum: 64 })
));

// Error: CPU buffer with non-ProducerSynced mode.
assert!(matches!(
    BufferHandle::new(512, 64, DeviceTag::Cpu, SyncMode::Event),
    Err(Error::InvalidSyncMode(0x01))
));
Source

pub fn with_memory_class( byte_size: u64, alignment: u32, device_tag: DeviceTag, sync_mode: SyncMode, memory_class: MemoryClass, ) -> Result<Self>

Creates a new BufferHandle with an explicit memory class.

Identical to BufferHandle::new but accepts a MemoryClass value. Use this constructor when the buffer’s memory class is not MemoryClass::Standard (e.g., CUDA managed memory, Metal shared storage, or peer-to-peer memory).

§Errors
§Examples
use hurray_core::{BufferHandle, DeviceTag, MemoryClass, SyncMode};

// CUDA unified (managed) memory buffer.
let handle = BufferHandle::with_memory_class(
    4096, 4096, DeviceTag::Cuda, SyncMode::ProducerSynced, MemoryClass::Unified,
).unwrap();
assert_eq!(handle.memory_class(), MemoryClass::Unified);

// CPU host-pinned buffer.
let pinned = BufferHandle::with_memory_class(
    512, 64, DeviceTag::Cpu, SyncMode::ProducerSynced, MemoryClass::HostPinned,
).unwrap();
assert_eq!(pinned.memory_class(), MemoryClass::HostPinned);
Source

pub fn empty(device_tag: DeviceTag) -> Self

Creates an empty BufferHandle (zero bytes) on the given device.

The alignment is set to 1 — the minimum valid power-of-two for an empty buffer — and sync_mode is always SyncMode::ProducerSynced. This constructor is infallible.

§Examples
use hurray_core::{BufferHandle, DeviceTag, SyncMode};

let handle = BufferHandle::empty(DeviceTag::Cpu);
assert!(handle.is_empty());
assert_eq!(handle.byte_size(), 0);
assert_eq!(handle.alignment(), 1);
assert_eq!(handle.device_tag(), DeviceTag::Cpu);
assert_eq!(handle.sync_mode(), SyncMode::ProducerSynced);
Source

pub fn byte_size(self) -> u64

Returns the size of the buffer in bytes.

A value of 0 denotes an empty buffer whose backing pointer MUST NOT be dereferenced.

§Examples
use hurray_core::{BufferHandle, DeviceTag, SyncMode};

let handle = BufferHandle::new(4096, 4096, DeviceTag::Cuda, SyncMode::Event).unwrap();
assert_eq!(handle.byte_size(), 4096);
Source

pub fn alignment(self) -> u32

Returns the minimum alignment of the buffer’s base address in bytes.

Always a power of two. For non-empty buffers, always at least MIN_BUFFER_ALIGNMENT.

§Examples
use hurray_core::{BufferHandle, DeviceTag, SyncMode, PAGE_ALIGNMENT};

let handle = BufferHandle::new(8192, PAGE_ALIGNMENT, DeviceTag::Cuda, SyncMode::Event).unwrap();
assert_eq!(handle.alignment(), 4096);
Source

pub fn device_tag(self) -> DeviceTag

Returns the DeviceTag identifying the memory space this buffer resides in.

§Examples
use hurray_core::{BufferHandle, DeviceTag, SyncMode};

let handle = BufferHandle::new(256, 64, DeviceTag::Metal, SyncMode::Event).unwrap();
assert_eq!(handle.device_tag(), DeviceTag::Metal);
Source

pub fn sync_mode(self) -> SyncMode

Returns the SyncMode describing the producer–consumer ordering guarantee for this buffer.

§Examples
use hurray_core::{BufferHandle, DeviceTag, SyncMode};

let handle = BufferHandle::new(1024, 64, DeviceTag::Cuda, SyncMode::ConsumerStream).unwrap();
assert_eq!(handle.sync_mode(), SyncMode::ConsumerStream);

// CPU buffers are always ProducerSynced.
let cpu = BufferHandle::new(1024, 64, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
assert_eq!(cpu.sync_mode(), SyncMode::ProducerSynced);
Source

pub fn memory_class(self) -> MemoryClass

Returns the MemoryClass describing how this buffer is accessible.

§Examples
use hurray_core::{BufferHandle, DeviceTag, MemoryClass, SyncMode};

// new() defaults to Standard.
let handle = BufferHandle::new(1024, 64, DeviceTag::Cuda, SyncMode::ProducerSynced).unwrap();
assert_eq!(handle.memory_class(), MemoryClass::Standard);

// with_memory_class() sets an explicit class.
let unified = BufferHandle::with_memory_class(
    1024, 64, DeviceTag::Cuda, SyncMode::ProducerSynced, MemoryClass::Unified,
).unwrap();
assert_eq!(unified.memory_class(), MemoryClass::Unified);
Source

pub fn is_empty(self) -> bool

Returns true if this buffer has zero bytes (byte_size == 0).

Readers MUST NOT dereference the pointer of an empty buffer. In C ABI contexts an empty buffer MAY be represented by a null pointer.

§Examples
use hurray_core::{BufferHandle, DeviceTag, SyncMode};

assert!(BufferHandle::empty(DeviceTag::Cpu).is_empty());
assert!(!BufferHandle::new(1, 64, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap().is_empty());

Trait Implementations§

Source§

impl Clone for BufferHandle

Source§

fn clone(&self) -> BufferHandle

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for BufferHandle

Source§

impl Debug for BufferHandle

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for BufferHandle

Source§

impl Hash for BufferHandle

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for BufferHandle

Source§

fn eq(&self, other: &BufferHandle) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for BufferHandle

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.