pub unsafe trait OutputSink: 'static + Sized {
type Params: 'static;
type Rows<'a>: ViewLen + FillDefault
where Self: 'a;
type Row<'a>
where Self: 'a;
type WriteToken: 'static;
// Required methods
fn storage_dtype(params: &Self::Params) -> DType;
fn with_capacity(rows: usize, params: &Self::Params) -> VortexResult<Self>;
fn rows(&mut self) -> Self::Rows<'_>;
unsafe fn row_unchecked<'a>(
rows: &'a mut Self::Rows<'_>,
index: usize,
) -> Self::Row<'a>;
unsafe fn finish(self) -> VortexResult<ArrayRef>;
// Provided method
fn initialize_skipped_rows(rows: &mut Self::Rows<'_>) { ... }
}Expand description
A column allocated once per batch that a row closure writes into, one row at a time.
A sink owns batch-wide state that an independent owned value cannot express, such as
uninitialized storage or a row handle covering more than one element. The executor passes each
row slot into an Fn closure.
A sink describes only how rows are physically written. An output dtype derived from the
function options or argument dtypes is declared by RowVisitor::with_output_dtype, which
labels the column this sink builds.
Rows arrive in increasing index order. Ordinary execution visits 0..row_count exactly once.
Skip-invalid execution runs initialize_skipped_rows first and then visits only valid rows.
§Errors
Lifecycle methods report only incidental failures such as allocation. A semantic error that
depends on input values must come from the row callback through a fallible SinkResult,
or RowFn::INFALLIBLE cannot protect optimizations such as dictionary push-down.
§Safety
An implementation must uphold all of these requirements:
- Every index below
ViewLen::lenforRowsmust identify one distinct row owned by this sink. - A borrowed
Rowsview must retain its length and index-to-row mapping until it is dropped. Calls torow_uncheckedand safe uses of a returnedRowmust preserve both properties. initialize_skipped_rowsis the only exception to this stability requirement. The executor checks the length again after the initializer. The initializer must initialize every row.- A row must either be initialized before the callback or require a
WriteTokenthat safe code cannot produce without initializing that exact row. Evidence for an uninitialized row must not be safely forgeable, reusable, or substitutable. Selfand every borrowedRowsview must remain safe to drop if decoding, preparation, skipped-row initialization, or a row callback returns an error or unwinds. The executor can abandon a sink after any prefix of rows.finishmust be sound once every visited callback returned its required token and, for a skip-invalid traversal,initialize_skipped_rowsran successfully first.- Violating these requirements can cause undefined behavior.
Required Associated Types§
Sourcetype Params: 'static
type Params: 'static
Physical parameters required to construct this sink before the row loop.
This type describes only physical storage. A logical output dtype belongs on
RowVisitor::with_output_dtype.
Sourcetype Rows<'a>: ViewLen + FillDefault
where
Self: 'a
type Rows<'a>: ViewLen + FillDefault where Self: 'a
A loop-local view of all output rows.
Borrowed once before execution so the sink’s buffer descriptor and shape become loop
invariants rather than being re-read through &mut Self for every row. The FillDefault
bound lets the default initialize_skipped_rows
zero-initialize the rows; storage that is fully initialized at construction can wrap itself
in Preinitialized to make that a no-op.
Sourcetype Row<'a>
where
Self: 'a
type Row<'a> where Self: 'a
The place a row closure writes one row through, borrowed from the sink.
Sourcetype WriteToken: 'static
type WriteToken: 'static
Proof that a successful row closure left its row handle initialized.
Use () for initialized row handles. A sink exposing uninitialized storage uses a token
returned after initialization. If a sink uses the token to justify unsafe code, safe code
must not be able to construct one without establishing the invariant.
Required Methods§
Sourcefn storage_dtype(params: &Self::Params) -> DType
fn storage_dtype(params: &Self::Params) -> DType
The dtype of the column this sink builds.
Must be non-nullable: batch execution derives nullability from the inputs, widens the result, and masks the null rows.
Sourcefn with_capacity(rows: usize, params: &Self::Params) -> VortexResult<Self>
fn with_capacity(rows: usize, params: &Self::Params) -> VortexResult<Self>
Allocate a sink for rows rows.
Sourceunsafe fn row_unchecked<'a>(
rows: &'a mut Self::Rows<'_>,
index: usize,
) -> Self::Row<'a>
unsafe fn row_unchecked<'a>( rows: &'a mut Self::Rows<'_>, index: usize, ) -> Self::Row<'a>
Hand out the place to write row index. Must be O(1): it is called in the row loop.
§Safety
index must be less than ViewLen::len for rows.
Sourceunsafe fn finish(self) -> VortexResult<ArrayRef>
unsafe fn finish(self) -> VortexResult<ArrayRef>
Finish into the built column, whose dtype must be this sink’s
storage_dtype for the parameters passed to
with_capacity. Called once per batch.
§Safety
The executor must have completed every row callback successfully, and each callback must
have returned this sink’s WriteToken. When rows are skipped,
initialize_skipped_rows must have run before traversal.
Provided Methods§
Sourcefn initialize_skipped_rows(rows: &mut Self::Rows<'_>)
fn initialize_skipped_rows(rows: &mut Self::Rows<'_>)
Initialize every output position before skip-invalid execution.
This must make every row safe to finish. The values are placeholders only: callbacks overwrite valid rows, and batch execution masks skipped rows before the output is observable, so any well-formed value works. Sink storage is non-nullable, so nulls do not exist at this level.
The default implementation zero-initializes the rows through FillDefault, which
Rows provides: a plain slice of Default elements fills itself, a custom
row view implements the filling for its own storage, and rows that are fully initialized at
construction wrap themselves in Preinitialized to skip it.
Override this method only when one batch-wide pass over the rows is the wrong operation.
Dense execution never calls this method because it visits every row.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".