pub struct FileWriter<W> { /* private fields */ }Expand description
Writes a Hurray file in a single forward pass without seeks.
The file format is:
[ File header ] 64 bytes
[ Tensor region ] descriptor → pad → buffers → pad (repeated)
[ KV section ] optional, written by finish()
[ Index section ] written by finish()
[ Trailer ] 40 bytes§Note on HAS_KV_METADATA
This writer sets HAS_KV_METADATA = 0 in the file header because KV
content is not known until finish is called and a
streaming writer cannot seek back to patch the header. The trailer’s
kv_offset field is the canonical indicator of KV presence; FileReader
uses that field rather than the header flag.
§Examples
use hurray_core::{
BufferHandle, DeviceTag, ElementType, LayoutDescriptor, Shape,
SyncMode, TensorDescriptor, MIN_BUFFER_ALIGNMENT,
};
use hurray_io::file::{FileWriter, KvValue};
let handle = BufferHandle::new(64, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced)?;
let shape = Shape::new(vec![4u64, 4]).unwrap();
let desc = TensorDescriptor::new(
1, 0, ElementType::Float32, shape, 0,
LayoutDescriptor::RowMajor, vec![handle], None, None, None, None,
)?;
let data = vec![0u8; 64];
let file = tokio::fs::File::create("model.hrry").await?;
let mut writer = FileWriter::new(file).await?;
writer.write_tensor("embeddings", &desc, &[&data]).await?;
writer.finish(vec![
("model".to_string(), KvValue::String("llama-3".to_string())),
]).await?;Implementations§
Source§impl<W: AsyncWrite + Unpin> FileWriter<W>
impl<W: AsyncWrite + Unpin> FileWriter<W>
Sourcepub async fn new(inner: W) -> Result<Self>
pub async fn new(inner: W) -> Result<Self>
Creates a writer with default options (4096-byte buffer alignment, unsorted index).
Sourcepub async fn with_options(inner: W, options: FileWriterOptions) -> Result<Self>
pub async fn with_options(inner: W, options: FileWriterOptions) -> Result<Self>
Creates a writer with custom options.
Sourcepub async fn write_tensor(
&mut self,
name: &str,
desc: &TensorDescriptor,
buffers: &[&[u8]],
) -> Result<()>
pub async fn write_tensor( &mut self, name: &str, desc: &TensorDescriptor, buffers: &[&[u8]], ) -> Result<()>
Encodes and writes one tensor.
§Errors
Error::TensorNameEmpty/Error::TensorNameTooLong— invalid nameError::DuplicateTensorName— name already written to this fileError::MultiBufferLengthMismatch— wrong buffer countError::BufferSizeMismatch— buffer length ≠ handlebyte_sizeError::Core— descriptor encoding failedError::Io— underlying write error
Sourcepub async fn write_composite(
&mut self,
head_name: &str,
head: &TensorDescriptor,
members: &[FileCompositeNode<'_>],
) -> Result<()>
pub async fn write_composite( &mut self, head_name: &str, head: &TensorDescriptor, members: &[FileCompositeNode<'_>], ) -> Result<()>
Writes a composite tensor: its head, then every member’s descriptor and data, contiguously and in order (ADR-027 § Binding).
Every tensor — the head and each member — gets its own footer-index entry, so all
are individually addressable by name via read_tensor.
Membership is recoverable by read_composite
from the head’s member_count plus file-offset adjacency (the members are the tensors
written immediately after the head). Nested composites are written recursively.
The whole group is validated up front — reusing [CompositeValidator] for member
count and per-rule constraints (partition exact-cover, overlay ordering) — before any
tensor is written.
§Errors
Error::Core— the head is not a valid composite head, or validation failed- the name/buffer errors of
write_tensorfor the head or any member Error::Io— underlying write error
§Examples
use hurray_core::{
layout::{CompositeLayout, CompositionRule, LayoutDescriptor},
ElementType, Shape, TensorDescriptor,
};
use hurray_io::file::{FileCompositeNode, FileWriter};
let head = TensorDescriptor::new(
1, 0, ElementType::Float32, Shape::new(vec![8u64, 8]).unwrap(), 0,
LayoutDescriptor::Composite(CompositeLayout::new(CompositionRule::Partition, 2).unwrap()),
vec![], None, None, None, None,
)?;
let file = tokio::fs::File::create("model.hrry").await?;
let mut writer = FileWriter::new(file).await?;
writer.write_composite("weight", &head, &members).await?;
writer.finish(vec![]).await?;