Skip to main content

Node

Trait Node 

Source
pub trait Node: Send + Sync {
    // Required methods
    fn op_name(&self) -> &'static str;
    fn inputs(&self) -> &[PortSpec];
    fn output(&self, input_kinds: &[Option<PortKind>]) -> PortKind;
    fn eval(
        &self,
        ctx: &EvalCtx<'_>,
        inputs: &[Option<PortValue>],
    ) -> Result<PortValue, EvalError>;
    fn param_hash(&self, hasher: &mut Xxh3);

    // Provided methods
    fn validate_kinds(
        &self,
        _input_kinds: &[Option<PortKind>],
    ) -> Result<(), String> { ... }
    fn coord_space(&self) -> CoordSpace { ... }
    fn required_pad(&self, downstream: u32) -> u32 { ... }
    fn influence_pad(&self, ctx: &InfluenceCtx<'_>) -> u32 { ... }
    fn ink_reach(&self, _assets: &dyn AssetLoader) -> Option<InkReach> { ... }
    fn asset_inputs(&self) -> Vec<String> { ... }
    fn param_refs(&self) -> Vec<String> { ... }
}
Expand description

One operation in the DAG. Stored as Box<dyn Node> inside crate::Graph; the graph never mutates a node after construction.

Required Methods§

Source

fn op_name(&self) -> &'static str

Stable identifier for the operation (e.g. "blur", "scatter-dabs"). Matches the op field in the style JSON.

Source

fn inputs(&self) -> &[PortSpec]

Declared input ports in positional order. The style JSON connects each port by name; eval receives values in this same positional order.

Source

fn output(&self, input_kinds: &[Option<PortKind>]) -> PortKind

The kind of value this node produces.

input_kinds carries the resolved PortKind of each input port, in the same positional order as Node::inputs. Entries are Some for connected ports (including optional ones) and None for unconnected optional ports.

Most nodes return a constant; polymorphic nodes (e.g. blur accepting both Raster and Sprite) inspect input_kinds and mirror the upstream kind. The graph builder resolves nodes in topological order, so upstream kinds are always known when this is called.

Source

fn eval( &self, ctx: &EvalCtx<'_>, inputs: &[Option<PortValue>], ) -> Result<PortValue, EvalError>

Produce this node’s output given resolved inputs. inputs has one entry per declared port, in the order returned by Node::inputs; unconnected optional ports are None.

Source

fn param_hash(&self, hasher: &mut Xxh3)

Stable content hash of this node’s own parameters (not inputs). Used as part of the cache key. Implementations should feed every configuration value that influences output into the hasher.

Provided Methods§

Source

fn validate_kinds( &self, _input_kinds: &[Option<PortKind>], ) -> Result<(), String>

Reject a combination of upstream kinds this node cannot serve, with a message explaining why.

Node::output has to answer with some kind, so a node whose requirement spans several ports — switch with a runtime select, which can only promise one output kind if both of its inputs share one — says so here instead. Called once per node at build time, right after the upstream kinds are resolved and before output.

Source

fn coord_space(&self) -> CoordSpace

Coordinate space the node operates in. Defaults to inheriting from inputs.

Source

fn required_pad(&self, downstream: u32) -> u32

How much canvas padding this node requires upstream given the padding requested by downstream consumers. Blur-like ops grow the value; most pass it through unchanged.

Source

fn influence_pad(&self, ctx: &InfluenceCtx<'_>) -> u32

How far outside the canvas this node’s input geometry can still end up mattering, given the distance already claimed downstream.

This is the mirror of Node::required_pad, and deliberately a separate number. required_pad asks how much canvas a node needs because it reads neighbouring pixels; a brush stroke reads nothing, so it declares none and the canvas stays small. But a stroke writes a dab’s radius away from its vertex, and a wave displaces a vertex by its amplitude before that — so geometry sitting outside the canvas can still put ink inside it. Answering “how far outside?” is what lets a source drop geometry it can prove is invisible, which is the difference between a deeply overzoomed tile costing its ancestor’s whole extent and costing its own.

Raster ops inherit their read distance, since ink pulled inward by a blur matters as much as ink painted there. Ops that displace or grow geometry add their own reach. Return u32::MAX to say the reach cannot be bounded, which keeps every upstream feature.

Like required_pad, this must be a worst case over the values a field can take, not the value this render happens to use.

Source

fn ink_reach(&self, _assets: &dyn AssetLoader) -> Option<InkReach>

How far from a stroke’s path this node’s output can lay ink, for the op that consumes it. Only a brush answers: how wide a dab reaches is a property of the brush, not of the op holding it, and the op receives it through a port it cannot inspect until eval. The graph hands it to the consumer as InfluenceCtx::brush.

None from a node that is a brush means its reach could not be established, which leaves the consumer unbounded.

Source

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

Named asset bindings this node samples via the AssetLoader. The evaluator folds each binding’s AssetLoader::hash into this node’s cache key, so changes in bound data invalidate caches automatically. Like declaring uniforms in a shader.

Default: no bindings.

Source

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

Named document params this node reads from EvalCtx::params at eval time (fields built from $param references). The evaluator folds each referenced param’s runtime value into this node’s cache key, so overriding a param invalidates exactly the nodes that read it — and nothing else.

Default: no param reads.

Dyn Compatibility§

This trait is dyn compatible.

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

Implementors§