pub struct TensorDescriptor {
pub version_major: u8,
pub version_minor: u8,
pub element_type: ElementType,
pub shape: Shape,
pub byte_offset: u64,
pub layout: LayoutDescriptor,
pub buffers: Vec<BufferHandle>,
pub quantization: Option<Vec<u8>>,
pub shard: Option<ShardDescriptor>,
pub statistics: Option<Statistics>,
pub extension_type: Option<ExtensionTypeDescriptor>,
pub composite_member: Option<CompositeMemberDescriptor>,
}Expand description
The top-level tensor descriptor carrying all metadata required to interpret a tensor’s data buffer.
Construct via TensorDescriptor::new, encode to bytes with
TensorDescriptor::encode, and decode from bytes with
TensorDescriptor::decode.
Derives PartialEq but NOT Eq — the statistics field may contain f64
values, and NaN semantics make Eq unsound for those fields.
§Examples
use hurray_core::{
BufferHandle, DeviceTag, ElementType, Shape, SyncMode, MIN_BUFFER_ALIGNMENT,
descriptor::TensorDescriptor,
layout::LayoutDescriptor,
};
let shape = Shape::new(vec![3u64, 4]).unwrap();
let buffer = BufferHandle::new(192, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
let desc = TensorDescriptor::new(
1, 0,
ElementType::Float32,
shape,
0,
LayoutDescriptor::RowMajor,
vec![buffer],
None, None, None, None,
).unwrap();
assert_eq!(desc.version_major, 1);
assert_eq!(desc.element_type, ElementType::Float32);
assert_eq!(desc.shape.rank(), 2);Fields§
§version_major: u8Major format version stored in the wire header.
version_minor: u8Minor format version stored in the wire header.
element_type: ElementTypeElement type tag for this tensor’s data.
shape: ShapeTensor shape (rank and dimension sizes).
byte_offset: u64Byte offset from the start of buffer 0 to logical element [0,…,0].
layout: LayoutDescriptorMemory layout descriptor.
buffers: Vec<BufferHandle>Buffer handles (at least one required).
quantization: Option<Vec<u8>>Raw quantization payload (opaque quantization_descriptor bytes).
When present the bytes are stored verbatim; typed decode is not performed in this layer (design decision: typed quantization decode is deferred to a higher layer that has schema context).
shard: Option<ShardDescriptor>Shard annotation (this tensor is a sub-region of a larger parent).
statistics: Option<Statistics>Advisory statistics about the tensor’s data buffer.
extension_type: Option<ExtensionTypeDescriptor>Extension type descriptor (present iff type_tag is in 0xF0–0xFE).
composite_member: Option<CompositeMemberDescriptor>Composite Member section (this tensor’s role within an enclosing overlay
composite). None by default; set via TensorDescriptor::with_composite_member.
Not a TensorDescriptor::new parameter — a composite head declares
member_count before its members exist, so member-role assignment is
necessarily a post-construction, opt-in step (see ADR-027).
Implementations§
Source§impl TensorDescriptor
impl TensorDescriptor
Sourcepub fn new(
version_major: u8,
version_minor: u8,
element_type: ElementType,
shape: Shape,
byte_offset: u64,
layout: LayoutDescriptor,
buffers: Vec<BufferHandle>,
quantization: Option<Vec<u8>>,
shard: Option<ShardDesc>,
statistics: Option<Stats>,
extension_type: Option<ExtDesc>,
) -> Result<Self>
pub fn new( version_major: u8, version_minor: u8, element_type: ElementType, shape: Shape, byte_offset: u64, layout: LayoutDescriptor, buffers: Vec<BufferHandle>, quantization: Option<Vec<u8>>, shard: Option<ShardDesc>, statistics: Option<Stats>, extension_type: Option<ExtDesc>, ) -> Result<Self>
Creates a new TensorDescriptor, validating invariants.
§Errors
Error::EmptyBufferTable—buffersis empty (andlayoutis not the composite head,layout_tag = 0x0B, for which an empty buffer table is the only valid table — seeError::CompositeHeadHasBuffers).Error::CompositeHeadHasBuffers—layoutis the composite head butbuffersis non-empty.Error::CompositeHeadHasByteOffset—layoutis the composite head butbyte_offset != 0.Error::CompositeHeadHasQuantization—layoutis the composite head butquantizationisSome.Error::ExtensionTypeFlagMismatch—extension_typeisSomebutelement_type.tag()is not in0xF0–0xFE, or vice-versa.Error::InvalidShape—shard.parent_shape.len() != shape.rank().Error::InvalidLayout— a block-paged or CSF layout carries asharddescriptor (spec § Sharding).Error::InvalidQuantization— a block-paged layout carries aquantizationdescriptor incompatible with the paged layout (spec § Quantization Compatibility).
§Examples
use hurray_core::{
BufferHandle, DeviceTag, ElementType, Shape, SyncMode, MIN_BUFFER_ALIGNMENT,
descriptor::TensorDescriptor,
layout::LayoutDescriptor,
};
let shape = Shape::new(vec![2u64, 3]).unwrap();
let buffer = BufferHandle::new(64, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
let desc = TensorDescriptor::new(
1, 0, ElementType::Float32, shape, 0,
LayoutDescriptor::RowMajor, vec![buffer],
None, None, None, None,
).unwrap();
assert_eq!(desc.buffers.len(), 1);Sourcepub fn with_composite_member(self, cm: CompositeMemberDesc) -> Self
pub fn with_composite_member(self, cm: CompositeMemberDesc) -> Self
Attaches a CompositeMemberDesc (this tensor’s role within an enclosing
overlay composite), returning self for chaining.
Opt-in and separate from TensorDescriptor::new because a composite head
declares member_count before its members exist (see ADR-027 § D2); member
role assignment is necessarily a step applied after a member descriptor is
otherwise fully built.
The one local cross-field invariant that applies regardless of composition
context — a composite head (layout_tag = 0x0B) MUST NOT itself carry a
Composite Member section — cannot be rejected here without breaking the
infallible Self return type this builder is specified to have; it is
re-validated at TensorDescriptor::encode / TensorDescriptor::decode
time instead, so the invariant still holds for every descriptor that
round-trips through the wire format.
§Examples
use hurray_core::{
BufferHandle, DeviceTag, ElementType, Shape, SyncMode, MIN_BUFFER_ALIGNMENT,
descriptor::{CompositeMemberDescriptor, MemberRole, TensorDescriptor},
layout::LayoutDescriptor,
};
let shape = Shape::new(vec![4u64]).unwrap();
let buffer = BufferHandle::new(64, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
let member = TensorDescriptor::new(
1, 0, ElementType::Float32, shape, 0,
LayoutDescriptor::RowMajor, vec![buffer],
None, None, None, None,
)
.unwrap()
.with_composite_member(CompositeMemberDescriptor::new(MemberRole::Base));
assert!(member.flags().has_composite_member());Sourcepub fn flags(&self) -> DescriptorFlags
pub fn flags(&self) -> DescriptorFlags
Derives the DescriptorFlags bitmask from which optional sections are present.
§Examples
use hurray_core::{
BufferHandle, DeviceTag, ElementType, Shape, SyncMode, MIN_BUFFER_ALIGNMENT,
descriptor::{TensorDescriptor, DescriptorFlags},
layout::LayoutDescriptor,
};
let shape = Shape::new(vec![4u64]).unwrap();
let buffer = BufferHandle::new(64, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
let desc = TensorDescriptor::new(
1, 0, ElementType::Float32, shape, 0,
LayoutDescriptor::RowMajor, vec![buffer],
None, None, None, None,
).unwrap();
assert_eq!(desc.flags().0, 0);Sourcepub fn encode(&self) -> Result<Vec<u8>>
pub fn encode(&self) -> Result<Vec<u8>>
Encodes this descriptor to its wire representation.
§Errors
Returns Error::DescriptorLengthMismatch if the encoded length exceeds
u32::MAX (practically impossible for well-formed descriptors).
§Examples
use hurray_core::{
BufferHandle, DeviceTag, ElementType, Shape, SyncMode, MIN_BUFFER_ALIGNMENT,
descriptor::TensorDescriptor,
layout::LayoutDescriptor,
};
let shape = Shape::new(vec![3u64, 4]).unwrap();
let buffer = BufferHandle::new(192, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
let desc = TensorDescriptor::new(
1, 0, ElementType::Float32, shape, 0,
LayoutDescriptor::RowMajor, vec![buffer],
None, None, None, None,
).unwrap();
let bytes = desc.encode().unwrap();
assert_eq!(bytes.len(), 61); // spec § Worked ExampleSourcepub fn decode(bytes: &[u8]) -> Result<Self>
pub fn decode(bytes: &[u8]) -> Result<Self>
Decodes a TensorDescriptor from its wire representation.
§Errors
Returns a variant of Error for any malformed field:
Error::InvalidMagic— magic bytes are not"HRRY".Error::UnsupportedDescriptorVersion—version_major > 1.Error::DescriptorTooShort—descriptor_length < 20.Error::DescriptorTruncated— byte slice ends before a field is complete.Error::ReservedDescriptorFlagBitsSet— reserved flag bits are set.Error::EmptyBufferTable—buffer_count == 0.Error::DescriptorLengthMismatch— consumed bytes ≠descriptor_length.
§Examples
use hurray_core::{
BufferHandle, DeviceTag, ElementType, Shape, SyncMode, MIN_BUFFER_ALIGNMENT,
descriptor::TensorDescriptor,
layout::LayoutDescriptor,
};
let shape = Shape::new(vec![3u64, 4]).unwrap();
let buffer = BufferHandle::new(192, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced).unwrap();
let desc = TensorDescriptor::new(
1, 0, ElementType::Float32, shape, 0,
LayoutDescriptor::RowMajor, vec![buffer],
None, None, None, None,
).unwrap();
let bytes = desc.encode().unwrap();
let decoded = TensorDescriptor::decode(&bytes).unwrap();
assert_eq!(decoded, desc);Trait Implementations§
Source§impl Clone for TensorDescriptor
impl Clone for TensorDescriptor
Source§fn clone(&self) -> TensorDescriptor
fn clone(&self) -> TensorDescriptor
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for TensorDescriptor
impl Debug for TensorDescriptor
Source§impl PartialEq for TensorDescriptor
impl PartialEq for TensorDescriptor
Source§fn eq(&self, other: &TensorDescriptor) -> bool
fn eq(&self, other: &TensorDescriptor) -> bool
self and other values to be equal, and is used by ==.