Trait spacetimedb_table::read_column::ReadColumn
source · pub unsafe trait ReadColumn: Sized {
// Required methods
fn is_compatible_type(ty: &AlgebraicTypeLayout) -> bool;
unsafe fn unchecked_read_column(
row_ref: RowRef<'_>,
layout: &ProductTypeElementLayout,
) -> Self;
// Provided method
fn read_column(row_ref: RowRef<'_>, idx: usize) -> Result<Self, TypeError> { ... }
}
Expand description
Types which can be stored in a column of a row, and can be extracted directly from a row.
§Safety
The implementor must define is_compatible_type
to return true
only for AlgebraicTypeLayout
s
for which unchecked_read_column
is safe.
The provided read_column
method uses is_compatible_type
to detect type errors,
and calls unchecked_read_column
if is_compatible_type
returns true.
Required Methods§
sourcefn is_compatible_type(ty: &AlgebraicTypeLayout) -> bool
fn is_compatible_type(ty: &AlgebraicTypeLayout) -> bool
Is ty
compatible with Self
?
The definition of “compatible” here is left to the implementor,
to be defined by Self::is_compatible_type
.
For most types,“compatibility” will mean that each Rust type which implements ReadColumn
has exactly one corresponding AlgebraicTypeLayout
which represents it,
and the column in table.row_layout
must be of that type.
Notable exceptions are AlgebraicValue
, ProductValue
and SumValue
.
Any ProductTypeLayout
is compatible with ProductValue
,
any SumTypeLayout
is compatible with SumValue
,
and any AlgebraicTypeLayout
at all is compatible with AlgebraicValue
.
sourceunsafe fn unchecked_read_column(
row_ref: RowRef<'_>,
layout: &ProductTypeElementLayout,
) -> Self
unsafe fn unchecked_read_column( row_ref: RowRef<'_>, layout: &ProductTypeElementLayout, ) -> Self
Extract a value of type Self
from the row pointed to by row_ref
which is stored in the column defined by layout
.
§Safety
layout
must appear as a column in the table.row_layout.product().elements
,
not to a nested field of a column which is a product or sum value.
That column must have the same layout as layout
.
This restriction may be loosened in the future.
Assuming that the row_ref
refers to a properly-aligned row,
adding the layout.offset
must result in a properly-aligned value of that compatible type.
layout.ty
must be compatible with Self
.
The definition of “compatible” here is left to the implementor,
to be defined by Self::is_compatible_type
.
For most types,“compatibility” will mean that each Rust type which implements ReadColumn
has exactly one corresponding AlgebraicTypeLayout
which represents it,
and the column in table.row_layout
must be of that type.
Notable exceptions are AlgebraicValue
, ProductValue
and SumValue
.
Any ProductTypeLayout
is compatible with ProductValue
,
any SumTypeLayout
is compatible with SumValue
,
and any AlgebraicTypeLayout
at all is compatible with AlgebraicValue
.
§Notes for implementors
Implementors may depend on all of the above safety requirements,
and on the validity of the row_ref
.
Assuming all of the above safety requirements are met and the row_ref
refers to a valid row,
this method must never invoke Undefined Behavior.
Implementors should carefully study the BFLATN format.
Currently BFLATN lacks a normative specification,
so implementors should read the definitions in [layout.rs
], [bflatn_to.rs
] and [bflatn_from.rs
].
A few highlights are included here:
-
Variable-length columns, i.e.
AlgebraicType::String
,AlgebraicType::Array
andAlgebraicType::Map
are stored within the row as [crate::var_len::VarLenRef
s], which refer to an intrusive linked list of 62-byte “granules”, allocated separately in a space starting from the end of the page. Strings are stored as UTF-8 bytes; all other var-len types are stored as BSATN-encoded bytes. -
Fixed-length columns, i.e. all types not listed above as variable-length, are stored inline at a known offset. Their layout generally matches the C ABI on an x86_64 Linux machine, with the notable exception of sum types, since the C ABI doesn’t define a layout for sums.
-
Fixed-length columns are stored in order, with padding between to ensure proper alignment.
-
Primitive (non-compound) fixed-length types, i.e. integers, floats and booleans, have alignment equal to their size.
-
Integers are stored little-endian.
-
Floats are stored by bitwise converting to integers as per IEEE-754, then storing those integers little-endian.
-
Booleans are stored as
u8
, i.e. bytes, restricted to the values0
and1
. -
Products store their elements in order, with padding between to ensure proper alignment.
-
The first element of a product has offset 0.
-
The alignment of a product is the maximum alignment of its elements, or 1 for the empty product.
-
The size of a product is the number of bytes required to store its elements, including padding, plus trailing padding bytes so that the size is a multiple of the alignment.
-
Sums store their payload at offset 0, followed by a 1-byte tag.
-
The alignment of a sum is the maximum alignment of its variants’ payloads.
-
The size of a sum is the maximum size of its variants’ payloads, plus 1 (the tag), plus trailing padding bytes so that the size is a multiple of the alignment.
-
The offset of a sum’s tag bit is the maximum size of its variants’ payloads.