Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 O becomes Ok(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.