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§
Sourcefn op_name(&self) -> &'static str
fn op_name(&self) -> &'static str
Stable identifier for the operation (e.g. "blur",
"scatter-dabs"). Matches the op field in the style JSON.
Sourcefn inputs(&self) -> &[PortSpec]
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.
Sourcefn output(&self, input_kinds: &[Option<PortKind>]) -> PortKind
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.
Sourcefn eval(
&self,
ctx: &EvalCtx<'_>,
inputs: &[Option<PortValue>],
) -> Result<PortValue, EvalError>
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.
Sourcefn param_hash(&self, hasher: &mut Xxh3)
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§
Sourcefn validate_kinds(
&self,
_input_kinds: &[Option<PortKind>],
) -> Result<(), String>
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.
Sourcefn coord_space(&self) -> CoordSpace
fn coord_space(&self) -> CoordSpace
Coordinate space the node operates in. Defaults to inheriting from inputs.
Sourcefn required_pad(&self, downstream: u32) -> u32
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.
Sourcefn influence_pad(&self, ctx: &InfluenceCtx<'_>) -> u32
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.
Sourcefn ink_reach(&self, _assets: &dyn AssetLoader) -> Option<InkReach>
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.
Sourcefn asset_inputs(&self) -> Vec<String>
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.
Sourcefn param_refs(&self) -> Vec<String>
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".