# pipeline-dsl

The **static** front-end of the [`pipeline`](https://github.com/dkumsh/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**
> (`&T` reads, `&mut T` writes); the macro enforces single-writer, detects
> missing producers, topologically sorts, and emits crisp compile-time errors.

## Setup

Two dependencies — the macros (this crate) and the value layer
([`pipeline-core`], imported as `pipeline`):

```toml
[dependencies]
pipeline-core = "0.3"   # the value layer, used as `pipeline::...`
pipeline-dsl  = "0.3"   # the #[pipeline] / #[stage] macros
```

## Quick start

```rust
use pipeline_dsl::{pipeline, stage};

#[derive(Default)]
struct Db { count: i32 }
#[derive(Default)]
struct Cache { total: i32 }

#[pipeline(name = "App", context = "db, cache")]
mod app {
    use super::*;

    #[stage]
    pub fn tick(db: &mut Db) { db.count += 1; }

    #[stage]
    pub fn sum(cache: &mut Cache, db: &Db) {
        cache.total += db.count; // reads db (after tick), writes cache
    }
}

fn main() -> Result<(), pipeline::Error> {
    let mut app = App::new();
    let (mut db, mut cache) = (Db::default(), Cache::default());
    app.compute(&mut db, &mut cache)?; // stages run in dependency order
    Ok(())
}
```

Runtime value types (`Vector`, `Value`, `Buckets`, `Reset`) come from
`pipeline` (the `pipeline-core` crate). Code generated by `#[pipeline]`
references `pipeline::…` paths, so **a crate using the macro must depend on
`pipeline-core` directly.**

## Attribute summary

- `#[pipeline(name="…", args="…", context="…", external="…", error="…", controlflow_break="…")]`
  — declares the pipeline container; `args`/`context`/`external` describe inputs.
- `#[stage]` — marks a function as a stage. Parameter attributes: `#[rename = "field"]`,
  `#[skip_reset]`, `#[unused]`.

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`].

[`pipeline-core`]: https://crates.io/crates/pipeline-core
[`pipeline-dsl`]: https://crates.io/crates/pipeline-dsl
[`pipeline-graph`]: https://crates.io/crates/pipeline-graph

## License

MIT OR Apache-2.0.
