Skip to main content

FileWriterCore

Struct FileWriterCore 

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

Writes the Hurray file container into bytes a driver sends onward.

Each tensor, and the footer, is submitted as one operation; the core emits the descriptor, the alignment padding and each payload in turn, and says when the item is written. The footer index is accumulated as it goes, so nothing has to be re-read and no offset is ever patched.

§Examples

use std::io::Write;

use hurray_core::{
    BufferHandle, DeviceTag, ElementType, LayoutDescriptor, Shape, SyncMode,
    TensorDescriptor, MIN_BUFFER_ALIGNMENT,
};
use hurray_io::file::FileWriterCore;
use hurray_io::stream::WriteStep;

let handle =
    BufferHandle::new(64, MIN_BUFFER_ALIGNMENT, DeviceTag::Cpu, SyncMode::ProducerSynced)?;
let descriptor = TensorDescriptor::new(
    1, 0, ElementType::Float32, Shape::new(vec![4u64, 4])?, 0,
    LayoutDescriptor::RowMajor, vec![handle], None, None, None, None,
)?;
let payload = [7u8; 64];
// Bound, not a temporary: the operation borrows the payloads until the item is
// written, which is ADR-041 § 3's lifetime rule showing up in the type system.
let buffers: [&[u8]; 1] = [&payload];

/// Drives one operation to completion over any `io::Write`.
fn drive(mut op: hurray_io::file::FileWriteOp<'_>, sink: &mut Vec<u8>) -> hurray_io::Result<()> {
    while let WriteStep::Output { .. } = op.step()? {
        let src = op.output_src();
        sink.write_all(src).map_err(hurray_io::Error::Io)?;
        let n = src.len();
        op.report_written(n)?;
    }
    Ok(())
}

let mut file = Vec::new();
let mut core = FileWriterCore::new();
drive(core.header()?, &mut file)?;
drive(core.tensor("embeddings", &descriptor, &buffers)?, &mut file)?;
drive(core.finish(vec![])?, &mut file)?;

assert_eq!(&file[0..8], b"HRRYFILE");
assert_eq!(&file[file.len() - 4..], b"HRRY");

Implementations§

Source§

impl FileWriterCore

Source

pub fn new() -> Self

Creates a core with default options: 4096-byte data alignment, unsorted index.

§Examples

See the type-level example.

Source

pub fn with_options(options: FileWriterOptions) -> Result<Self>

Creates a core with custom options.

§Errors

Error::InvalidHeader — data_buffer_alignment is not a power of two in [4096, 2097152].

§Examples
use hurray_io::file::{FileWriterCore, FileWriterOptions};

let core = FileWriterCore::with_options(FileWriterOptions {
    data_buffer_alignment: 8192,
    sorted_index: true,
})?;
assert!(!core.is_unusable());
Source

pub fn header(&mut self) -> Result<FileWriteOp<'_>>

Emits the 64-byte file header.

Drive this before the first tensor: a core with no header written refuses tensor and finish.

§Errors
§Examples

See the type-level example.

Source

pub fn tensor<'a>( &'a mut self, name: &str, descriptor: &TensorDescriptor, buffers: &'a [&'a [u8]], ) -> Result<FileWriteOp<'a>>

Submits one tensor: its descriptor, its alignment padding, and its payloads.

The returned operation borrows buffers until it reports WriteStep::ItemWritten; the core holds no pointer into them afterwards (§ 3). The tensor’s index entry is recorded at that same point.

§Errors
§Examples

See the type-level example.

Source

pub fn finish(&mut self, kv: Vec<(String, KvValue)>) -> Result<FileWriteOp<'_>>

Submits the footer: the KV section, the index, and the 40-byte trailer.

§Errors
§Examples

See the type-level example.

Source

pub fn is_unusable(&self) -> bool

Whether a write put an unknown number of bytes on the sink, leaving the file torn.

§Examples
use hurray_io::file::FileWriterCore;

assert!(!FileWriterCore::new().is_unusable());
Source

pub fn poison(&mut self, reason: Unusable)

Retires the core because the output can no longer be completed.

For a unit larger than one item — a composite group, whose head is already on the sink when a member fails. A FileWriteOp cannot express that: the failure may come from submission, with no operation in hand.

Public because the driver that needs it may live in another crate. ADR-041 § 1 puts drivers at the edge, and a group spanning several operations is the driver’s unit, not the core’s — so a binding outside hurray-io writing composites needs the same tool FileWriter uses, exactly as WriteOp::mark_unusable is public for the single-operation case.

§Examples
use hurray_io::file::FileWriterCore;
use hurray_io::stream::Unusable;

let mut core = FileWriterCore::new();
core.poison(Unusable::IncompleteOutput);
assert!(core.is_unusable());

Trait Implementations§

Source§

impl Debug for FileWriterCore

Source§

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

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

impl Default for FileWriterCore

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

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> 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, 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.