pipeline-dsl
The static front-end of the pipeline
family: write ordinary functions, annotate them, and let the #[pipeline] macro
derive a dependency DAG and a deterministically ordered compute().
Functions + names ⇒ DAG ⇒ deterministic compute. Edges are inferred from name-based parameter binding and mutability (
&Treads,&mut Twrites); the macro enforces single-writer, detects missing producers, topologically sorts, and emits crisp compile-time errors.
Setup
A single dependency — pipeline-dsl re-exports both the macros and the value
layer:
[]
= "0.7"
(Optionally also depend on pipeline-core to refer to the value types under
the shared pipeline:: name; they're the same re-exported types.)
Quick start
use ;
Runtime value types (Vector, Value, Buckets, Reset) are re-exported by
this crate, so you can name them as pipeline_dsl::Vector etc., and the code
generated by #[pipeline] resolves its runtime support through pipeline-dsl —
no second dependency required.
Attribute summary
#[pipeline(name="…", args="…", context="…", external="…", error="…", controlflow_break="…", constructor="…")]— declares the pipeline container;args/context/externaldescribe inputs.#[stage]— marks a function as a stage. Parameter attributes:#[rename = "field"],#[skip_reset],#[unused],#[state].
Parameter kinds
A stage parameter is one base kind (where its storage lives and who fills it):
| Kind | Owner | Reset/cycle | Stage access | Shared? |
|---|---|---|---|---|
args |
pipeline | none | &T |
many readers |
context |
caller | none | &T / &mut T |
many |
external (external="…") |
pipeline | dirty cleared | caller-fed | many readers |
internal Value<T>/Vector<T> |
pipeline | dirty cleared | one writer, N readers | yes |
#[state] |
pipeline | none | one stage, &mut T |
no (private) |
…optionally tweaked by a modifier: #[rename] (bind to a different field
name), #[skip_reset] (a slot that persists instead of resetting), #[unused]
(keep a parameter that's deliberately disconnected from the graph).
#[state] is the only off-graph kind: per-stage-private, persistent, plain T
the pipeline owns and exactly one stage mutates — for an accumulator, cache, or
scratch that must survive across cycles. It is never reset, never read by another
stage, and does not appear in dot() / html_diagram(). It requires &mut T;
sharing one state across two stages is an error (use a Value<T> slot instead).
In the dynamic
pipeline-graphfront-end there is no#[state]: stages are closures, so a stage simply captures its own persistent mutable state (with aCell/RefCellfor interior mutability).#[state]is the static front-end's equivalent, since its stages are freefns that can't capture.
Constructors
When every field is Default (the usual case), the macro generates
Pipeline::new(args…); if there are no args it also derives Default. Each
Default-initialized field is bounded by Default, so a field whose type isn't
Default produces a clear T: Default is not satisfied error rather than one
buried in generated code. In that case, pass constructor = "manual" and write
your own constructor:
See the repository for the full guide (binding rules, multiple contexts, generics, diagrams, diagnostics).
Safety
This front-end is fully checked at compile time and uses no unsafe —
mis-wiring (a missing producer, two writers, a cycle) is a compile error. The
dynamic pipeline-graph front-end trades those compile-time guarantees for
runtime flexibility, validating wiring at build() and using a small
encapsulated unsafe core. If a fixed graph fits your problem, this crate gives
you the stronger guarantees.
Related crates
Part of the pipeline family — a shared value layer with two front-ends:
| Crate | What it is |
|---|---|
pipeline-core |
the value layer (Value/Vector/Buckets + Reset), imported as pipeline |
pipeline-dsl |
static front-end: derive the graph at compile time with #[pipeline]/#[stage] |
pipeline-graph |
dynamic front-end: wire the graph at runtime (Graph, Input/Output) |
Need the graph wired at runtime (stages/implementations chosen dynamically)?
See pipeline-graph.
License
MIT OR Apache-2.0.