Nodes
This page covers the Node struct in more depth. For the basics, see A minimal pipeline — Nodes.
NodeInput and NodeOutput traits
These traits handle the mechanics of loading from and saving to dataset tuples:
pub trait NodeInput {
type Args;
fn load_data(&self, on_event: ...) -> Result<Self::Args, PondError>;
}
pub trait NodeOutput {
type Output;
fn save_data(&self, output: Self::Output, on_event: ...) -> Result<(), PondError>;
}
They are implemented for tuples of dataset references (up to 10 elements) via macros. During execution, load_data fires BeforeLoad/AfterLoad events for each dataset, and save_data fires BeforeSave/AfterSave events — these drive the hook system.
CompatibleOutput
The CompatibleOutput trait is what allows node functions to return either bare tuples or Result<tuple, E>:
// Bare tuple — infallible node
func: |x: i32| (x * 2,),
// Result — fallible node
func: |x: i32| -> Result<(i32,), MyError> { Ok((x * 2,)) },
The bound F::Output: CompatibleOutput<Output::Output> on the Node struct catches type mismatches at node construction time, before the pipeline error type E is known. This means you get a compile error immediately if the function’s return type doesn’t match the output datasets.
IntoNodeResult
When a node is called at runtime, IntoNodeResult normalizes the function’s return value into Result<O, E>:
- A bare tuple
ObecomesOk(O) - A
Result<O, E>is passed through as-is
This is what allows runners to handle both fallible and infallible nodes uniformly.
Side-effect nodes
Nodes with no outputs are useful for logging, sending notifications, or other side effects:
Node {
name: "log_summary",
func: |summary: f64| {
println!("Summary: {summary}");
},
input: (&cat.summary,),
output: (),
}
A node with output: () does not save any datasets. The function’s return value (unit ()) is discarded.
Similarly, a node with input: () takes no arguments and produces outputs from scratch.