Expand description
Stable columnar boundary for WASM, FFI, and GPU consumers.
The Model layer is already struct-of-arrays, but its
public fields are Rust types (Vec<String>, Option<char>, Element,
Arc, borrowed views) that cannot cross a wasm-bindgen or C ABI boundary,
or be uploaded to a GPU, as they are. This module is the contract for doing
so. It adds no dependencies: bindings crates (wasm-bindgen, PyO3, a C
header) and renderers (bevy, wgpu) build on it.
§What crosses the boundary
- Numeric columns — contiguous
u8/i8/u32/i32/f32slices (ColumnData), each with a stable name (Column). Bytes are little-endian (ColumnData::le_bytes). - String columns — dictionary-encoded (
StringDictionary): oneu32code per row plus a UTF-8 value buffer and offsets. - Optional values — encoded in place with sentinels
(
NO_ALT_LOC,NO_INS_CODE,NO_FORMAL_CHARGE,MISSING_SEQ_ID), never as a separate validity bitmap. - Handles —
AtomHandle,ResidueHandle,ChainHandle:u32row indices into a topology snapshot, navigated with checked lookups. - Errors —
BoundaryError, with a stable numericcodeinstead of panics. - GPU uploads —
GpuBuffer: bytes plus aBufferLayout(scalar type, components, stride, count).
§Ownership, borrowing, and invalidation
| Data | Source | Copy or borrow | Valid until |
|---|---|---|---|
x, y, z, occupancy, b_iso, confidence | FrameColumns | borrow of the model’s conformation | the model is dropped or its conformation mutated |
| sequence ids, segment offsets, bonds | TopologyColumns | borrow of the pinned hierarchy | the snapshot is dropped |
| element, alt_loc, charge, ins_code, group, dictionaries | TopologyColumns | owned, encoded once per hierarchy | the snapshot is dropped |
| interleaved positions, bond line indices | GpuBuffer | owned copy | never (independent of the model) |
Inside Rust the borrow checker enforces the “valid until” column. Across
FFI it is the caller’s obligation: a raw pointer from
ColumnData::as_ptr is valid exactly as long as the Rust borrow it came
from.
A TopologyColumns snapshot keeps its Arc<AtomicHierarchy> alive and
therefore immutable (Arc::make_mut will clone rather than mutate). A
topology edit thus produces a new hierarchy, and pairing a frame with the
old snapshot fails with StaleTopology
rather than exporting mismatched columns. All frames of a trajectory share
one hierarchy, so one snapshot serves every frame.
§wasm-bindgen
A zero-copy JS typed-array view over a borrowed column (e.g.
js_sys::Float32Array::view) points into wasm linear memory and is
detached by any allocation that grows that memory, including
allocations made later by ferritin itself. Use views only for an immediate
copy or upload within the same call; copy (Float32Array::from) anything
JS keeps.
§Example
let topology = TopologyColumns::from_model(&model)?; // once per hierarchy
let frame = topology.frame(&model)?; // per frame, zero-copy
upload(frame.positions(PositionLayout::Padded4)); // owned, 16-byte stride
upload(GpuBuffer::from_column(column)?); // borrowed scalar column
upload(topology.bond_line_indices()); // owned [a, b] pairsStructs§
- Atom
Handle - Handle to one atom row.
- Boundary
Error - An error raised while exporting columns across the WASM/FFI/GPU boundary.
- Buffer
Layout - Memory layout of one GPU buffer.
- Chain
Handle - Handle to one chain row.
- Column
- A named column, as listed by
TopologyColumns::columnsandFrameColumns::columns. - Frame
Columns - Borrowed per-frame columns: coordinates and per-atom scalars.
- GpuBuffer
- Bytes ready to upload, with their layout.
- Residue
Handle - Handle to one residue row.
- String
Dictionary - A dictionary-encoded string column.
- Topology
Columns - Boundary-ready, frame-independent topology columns.
Enums§
- Boundary
Error Kind - Category of a
BoundaryError. - Column
Data - A borrowed, contiguous, typed numeric column.
- Position
Layout - How to interleave atom positions for upload.
- Scalar
Type - Scalar element type of an exported column.
Constants§
- NO_
ALT_ LOC atom.alt_locvalue for atoms without an alternate-location indicator.- NO_
FORMAL_ CHARGE atom.formal_chargevalue for atoms without a recorded formal charge.- NO_
INS_ CODE residue.ins_codevalue for residues without an insertion code.- RESIDUE_
GROUP_ NON_ POLYMER residue.groupvalue for non-polymer residues.- RESIDUE_
GROUP_ POLYMER residue.groupvalue for polymer residues.