Skip to main content

Kernel

Trait Kernel 

Source
pub trait Kernel:
    Send
    + Sync
    + KernelInternals {
Show 53 methods // Required methods fn engine(&self) -> Engine; fn set_inputs(&mut self, coords: &[u64]); fn set_input(&mut self, name: &str, value: Value) -> Result<(), WriteError>; fn set_cursor( &mut self, name: &str, partition: &Partition, ) -> Result<(), WriteError>; fn eval(&mut self); fn pull(&mut self, name: &str) -> Value; fn input_names(&self) -> Vec<String>; fn output_names(&self) -> Vec<String>; fn output_type(&self, name: &str) -> Option<PortType>; fn externs(&self) -> Vec<(String, PortType)>; fn cursor_schemas(&self) -> &[SourceSchema]; fn plan(&self) -> EnginePlan; fn input_value(&self, name: &str) -> Option<Value>; fn const_inits(&self) -> &[ConstInit]; fn init_input_at( &mut self, index: usize, value: Value, ) -> Result<(), WriteError>; fn traversals(&self) -> &[Traversal]; fn traverse(&mut self, index: usize) -> Result<TraversalStream, String>; fn invalidate_all(&mut self); fn shared_cells(&self) -> Vec<SharedCellEntry>; fn attach_shared_cell( &mut self, name: &str, cell: SharedCell, ) -> Result<(), String>; fn into_program(self: Box<Self>) -> Arc<dyn KernelProgram> ⓘ; fn ledger(&self) -> &Arc<CompileLedger> ⓘ; fn resources(&self) -> &ResourceScope; fn canonical_hash(&self) -> [u8; 32]; fn coord_count(&self) -> usize; fn input_value_at(&self, index: usize) -> Option<Value>; fn input_default_at(&self, index: usize) -> Option<Value>; fn input_is_cell_bound(&self, index: usize) -> bool; fn reset_inputs(&mut self); fn fork(&self) -> Box<dyn Kernel>; fn publish_broadcasts(&mut self); fn commit_write_throughs(&mut self) -> Result<(), String>; fn input_type_origin(&self, name: &str) -> Option<TypeOrigin>; fn program_id(&self) -> ProgramId; // Provided methods fn input_index(&self, name: &str) -> Option<usize> { ... } fn set_input_at( &mut self, index: usize, value: Value, ) -> Result<(), WriteError> { ... } fn output_index(&self, name: &str) -> Option<usize> { ... } fn pull_at(&mut self, index: usize) -> Value { ... } fn init(&mut self) -> Result<(), KernelError> { ... } fn traverse_all(&mut self) -> Result<Vec<TraversalStream>, String> { ... } fn output_cell(&self, _name: &str) -> Option<SharedCell> { ... } fn output_modifier(&self, _name: &str) -> BindingModifier { ... } fn cells_in_scope(&self) -> Vec<SharedCellEntry> { ... } fn set_transit_cells(&mut self, _cells: Vec<SharedCellEntry>) { ... } fn scope_coordinates(&self) -> &[ScopeCoord] { ... } fn extend_scope_coordinates(&mut self, _outer: &[ScopeCoord]) { ... } fn input_port_type(&self, _name: &str) -> Option<PortType> { ... } fn bind_input_cell(&mut self, _name: &str, _cell: SharedCell) -> bool { ... } fn instance_hash(&self, ancestors: &[&dyn Kernel]) -> [u8; 32] { ... } fn is_equivalent_to(&self, other: &dyn Kernel) -> bool { ... } fn is_subset_of(&self, parent: &dyn Kernel) -> bool { ... } fn as_interpreter(&self) -> Option<&PolydatKernel> { ... } fn as_interpreter_mut(&mut self) -> Option<&mut PolydatKernel> { ... }
}
Expand description

A kernel on any engine: the interpreter, the closure tier, the hybrid kernel, or pure native code. Every engine accepts every program the interpreter accepts, or refuses it at construction with a reason, and computes the same values for the same inputs; the choice of engine changes how fast a program runs and nothing else. This trait is the surface a host drives an engine through without knowing which one it has.

The interpreter kernel and the compiled kernels also keep their inherent methods (raw slot readers, eval(&[u64]), engine_counts) as engine-specific extras; where a name is shared, the inherent method is the one a call on the concrete type reaches, and the trait’s is reached through dyn Kernel or Kernel::pull(&mut k, …).

Required Methods§

Source

fn engine(&self) -> Engine

The engine this kernel runs on.

Source

fn set_inputs(&mut self, coords: &[u64])

Set the coordinate inputs for the next evaluation.

Source

fn set_input(&mut self, name: &str, value: Value) -> Result<(), WriteError>

Set an extern by name. One rule on every engine: the value must satisfy the declared port type (a carrier’s bit-stuffed forms included) or be None, which clears the extern; a value of another type is refused at the write, never healed. A coordinate is set with Self::set_inputs, not here. An unknown name is an error naming the known ones.

Source

fn set_cursor( &mut self, name: &str, partition: &Partition, ) -> Result<(), WriteError>

Narrow a cursor to one partition: its Ext slot and its six scalar projections are set.

Source

fn eval(&mut self)

Evaluate every output for the inputs set so far.

Source

fn pull(&mut self, name: &str) -> Value

The named output for the inputs set so far, evaluating what it needs and no more: the output’s cone, on all four engines (pure native code, though one function, runs only the fusion units of the output’s cone; engines.md §1). A side channel in the cone fires when the output is pulled; a failing node fails when pulled, with the same attributed message on every engine: the node’s name, the outputs it feeds, the program’s context, and its inputs. The value is owned; a handle is never returned to the host, and a slot that holds None reads as None.

Source

fn input_names(&self) -> Vec<String>

Every input by name, the coordinates first.

Source

fn output_names(&self) -> Vec<String>

Every named output.

Source

fn output_type(&self, name: &str) -> Option<PortType>

The declared port type of a named output.

Source

fn externs(&self) -> Vec<(String, PortType)>

The externs by name and declared type.

Source

fn cursor_schemas(&self) -> &[SourceSchema]

The cursors the program declares, with the partitions the compiler resolved where it could.

Source

fn plan(&self) -> EnginePlan

What this kernel’s engine decided for the program: how much of it runs as native segments, as closure steps, and on the interpreter. The one planning detail a kernel exposes.

Source

fn input_value(&self, name: &str) -> Option<Value>

The value of a named input as the kernel holds it now, an extern or a coordinate; None for a name that is not an input.

Source

fn const_inits(&self) -> &[ConstInit]

The const bindings this kernel initializes, in the order Self::init evaluates them: a const that reads another comes after it.

Source

fn init_input_at( &mut self, index: usize, value: Value, ) -> Result<(), WriteError>

Write an input as part of initialization. It is Self::set_input_at except that a const’s slot is accepted, which is how Self::init stores each const’s value.

Source

fn traversals(&self) -> &[Traversal]

The traversals the program declares, in document order.

Source

fn traverse(&mut self, index: usize) -> Result<TraversalStream, String>

Open the traversal at index against this kernel’s current values (for_traversal.md §3.6): the comprehension’s sources see the wires they reference as this kernel holds them now, and the cascaded wires are snapshotted into every activation. Every engine opens traversals (engines.md §3.6).

Source

fn invalidate_all(&mut self)

Begin the next cycle with nothing current, so every step, a side channel included, runs again when pulled. The runtime model makes a cycle whose inputs did not move cost nothing; this is how a host runs such a cycle anyway, as the polydat binary does when every input is fixed.

Source

fn shared_cells(&self) -> Vec<SharedCellEntry>

The cells this kernel’s shared bindings are bound to (scope model §6): one register per binding, which every kernel holding the cell reads and writes.

Source

fn attach_shared_cell( &mut self, name: &str, cell: SharedCell, ) -> Result<(), String>

Bind the shared binding name to cell, so this kernel and every other holder of the cell read and write one register: a write on any of them is what the others read next, and a dependent output is recomputed. A name that is not a shared binding is an error naming the ones that are.

Source

fn into_program(self: Box<Self>) -> Arc<dyn KernelProgram> ⓘ

The program this kernel runs, shareable across threads: each thread creates its own kernel from it with KernelProgram::create_kernel.

What this kernel was set to does not travel with it. A kernel created from the program starts at the program: every extern at its declared default and every shared binding with a cell of its own, whatever this kernel had been written to before it became one. That holds on every engine.

The reason is that an extern is per-kernel state, in the same family as the coordinates: both are writes into declared slots of a running kernel, and neither is part of the compiled program. A host that wants a value fixed for the program fixes it before compiling, with transform::assign_values or an extern default in the source; a host that wants every thread to see one register attaches a cell with Self::attach_shared_cell.

Source

fn ledger(&self) -> &Arc<CompileLedger> ⓘ

The compile ledger of the program tree this kernel belongs to: what compiling it and everything opened from it has built.

Source

fn resources(&self) -> &ResourceScope

The resource scope of the program tree this kernel belongs to: the slot for the host’s ResourceAccessor that every node of the tree looks resources up through. A host that did not hand one to the compile (CompileOptions::resources) installs its accessor here, once; kernels created from or forked off this one, subscopes built under it, and its traversal bodies share the scope.

Source

fn canonical_hash(&self) -> [u8; 32]

The canonical hash of this kernel’s program (scope_model.md §8): equal for one program built on any of the four engines, and for every kernel created from or forked off it, and a function of what the program computes rather than of its source text. What a host keys a checkpoint on.

Source

fn coord_count(&self) -> usize

How many of the inputs are coordinates: they come first in input_names, and set_inputs writes them.

Source

fn input_value_at(&self, index: usize) -> Option<Value>

The value input index holds now: a coordinate’s pending or current value, an extern’s current value. None past the end.

Source

fn input_default_at(&self, index: usize) -> Option<Value>

The value input index starts with: an extern’s declared default, U64(0) for a coordinate. None past the end.

Source

fn input_is_cell_bound(&self, index: usize) -> bool

Whether input index is bound to a shared cell, so that its value is the cell’s and a reset leaves it alone.

Source

fn reset_inputs(&mut self)

Every input that is not a coordinate and not bound to a cell back at its default, and whatever depends on a changed one not current. What a host does at a boundary where values written for the last stretch must not leak into the next.

Source

fn fork(&self) -> Box<dyn Kernel>

A new kernel over the same program with this kernel’s state: its inputs, its current outputs, and its cells, which stay shared (a cell is the scope’s register, not a value it holds), transit cells included. Callable concurrently on a kernel shared across threads (native_scope_trees.md §4).

Source

fn publish_broadcasts(&mut self)

Pull every output a descendant bound to by cell, so the descendant reads the current value. Nothing happens on a kernel nothing is bound under. A failing output is left for the pull that needs it to report.

Source

fn commit_write_throughs(&mut self) -> Result<(), String>

Commit the Rule 2 write-throughs: pull each synthetic __write_<name> output and write it through the cell of the shared binding it exports to. No-op for a kernel without them.

Source

fn input_type_origin(&self, name: &str) -> Option<TypeOrigin>

How input name’s type was established: written by the author, or inferred by the compiler and so open to CompileOptions::input_variance (input_variance.md §3). A host that compiles many scopes at Info reports each open input once from here rather than from every compile’s log.

Source

fn program_id(&self) -> ProgramId

The identity of this kernel’s program: equal for kernels created from one program and for forks, different for any two programs, the same program compiled twice included. What a host seals a plan of pre-resolved indices against.

Provided Methods§

Source

fn input_index(&self, name: &str) -> Option<usize>

The index of a named input among Self::input_names, the coordinates first: what Self::set_input_at takes.

Source

fn set_input_at(&mut self, index: usize, value: Value) -> Result<(), WriteError>

Self::set_input by index, for a host that binds the same inputs every cycle: the name is resolved once, with Self::input_index, and no lookup runs per write.

Source

fn output_index(&self, name: &str) -> Option<usize>

The index of a named output among Self::output_names: what Self::pull_at takes.

Source

fn pull_at(&mut self, index: usize) -> Value

Self::pull by index, for a host that reads the same outputs every cycle: the name is resolved once, with Self::output_index, and no lookup runs per pull.

Source

fn init(&mut self) -> Result<(), KernelError>

Initialize the kernel: evaluate every const binding once, in dependency order, and store its value for the rest of the kernel’s life.

Every way a kernel comes into existence initializes it: a build, a kernel created from a shared program, a child bound under a parent (after the parent’s values are bound), and a traversal activation (after its tuple is bound). A host calls it again when it wants the consts recomputed from the inputs as they are now, for example after setting externs a const reads. Inputs keep their values; only the consts change.

A const whose expression yields None takes the value the binder copied from the enclosing scope, so the outer binding stays visible. A const whose expression fails makes initialization fail, naming the const; a slow one makes initialization slow.

A shared register with a computed starting value is seeded here too, in the same order, while nothing has written the register: a kernel attached to a register another scope declared, and one initialized again, leave it as it is.

Source

fn traverse_all(&mut self) -> Result<Vec<TraversalStream>, String>

Open every traversal, in document order.

Source

fn output_cell(&self, _name: &str) -> Option<SharedCell>

The broadcast cell for a computed output, created on the first ask: a descendant that binds its matching input slot to this cell reads the value each of this kernel’s pulls publishes through it, rather than a copy taken once when the descendant was built (cross_fiber_invalidation.md §3.1).

None when the name is not an output of this kernel. All four engines have broadcast cells: the interpreter seeds one per output at construction, and the closure tier, native, and pure native make them on demand, so a compiled program with no descendant bound to it allocates none (engines.md §3.6).

Source

fn output_modifier(&self, _name: &str) -> BindingModifier

The binding modifier a named output was declared with — const, shared, final, or none. A binder reads it to decide how a descendant takes the output: a const is effectively fixed for the scope’s life and is value-copied, where a computed output is bound to its broadcast cell (scope_model.md §4).

NONE for a name this kernel does not declare.

Source

fn cells_in_scope(&self) -> Vec<SharedCellEntry>

Every cell a descendant of this kernel could bind to: the ones its own shared slots hold, plus the ones it carries forward for a descendant without holding a slot for them itself. The second kind is why an ancestral shared reaches a grandchild whose parent’s program never names it.

Self::shared_cells is the first kind alone.

Source

fn set_transit_cells(&mut self, _cells: Vec<SharedCellEntry>)

Carry cells forward for this kernel’s descendants. The binder writes what the parent had and this kernel holds no slot for.

Source

fn scope_coordinates(&self) -> &[ScopeCoord]

This kernel’s place in the comprehension nest its scope was built under, outermost last: a child’s path is its own followed by its parent’s. Empty for a root, which is every kernel a host compiles rather than binds, so the compiled engines answer empty until one is bound under a parent.

Source

fn extend_scope_coordinates(&mut self, _outer: &[ScopeCoord])

Append outer to this kernel’s own scope-coordinate path, which the binder does once the child’s inputs are in. A no-op on an engine that keeps no path.

Source

fn input_port_type(&self, _name: &str) -> Option<PortType>

The declared type of a named input slot, coordinates included. The binder reads it to adapt a value the parent supplies into the type the child’s slot declares.

Source

fn bind_input_cell(&mut self, _name: &str, _cell: SharedCell) -> bool

Bind the named input slot to cell, whether or not the slot was built as a shared register, and answer whether it was bound.

This is what a parent does to a child, not what a host does to two kernels. A child declares its imports extern; it is the parent binding it that decides one of them reads a register rather than a copied value. Self::attach_shared_cell is the host’s operation and refuses a slot that is not already a register on both sides, which is the right answer for joining two kernels and the wrong one for building a child.

Source

fn instance_hash(&self, ancestors: &[&dyn Kernel]) -> [u8; 32]

The instance hash of this kernel’s program under ancestors, innermost first (scope_model.md §8.2): what PolydatProgram::instance_hash gives for the same programs, whichever engines the kernels are on.

Source

fn is_equivalent_to(&self, other: &dyn Kernel) -> bool

Whether other runs the same program (scope_model.md §8.3): their canonical hashes are equal, whichever engines the two are on.

Source

fn is_subset_of(&self, parent: &dyn Kernel) -> bool

Whether this kernel’s program adds nothing parent’s does not already supply (scope_model.md §8.3): it is equivalent to parent, or it outputs nothing but its own inputs and every input it declares parent declares too. The answer PolydatProgram::is_subset_of gives for the same programs, on any engines.

Source

fn as_interpreter(&self) -> Option<&PolydatKernel>

The interpreter’s kernel, when this is one: what a caller that needs the interpreter’s own extras (Metadata, Dataflow, its program and state) reaches them through. None on a compiled engine.

Source

fn as_interpreter_mut(&mut self) -> Option<&mut PolydatKernel>

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§