`ops/*.yaml` plus `build.rs` has been the class-1 plugin format since the declarative nodes landed — it was simply resolved at build time. Nothing about a declaration requires the compiler: everything it produces is data plus a WGSL string, and the composer already assembles WGSL at run time from whatever operations are active. So this is not a new mechanism. It is the existing one, loaded later (FR-PLG-2). `DeclaredOp` implements `Operation` from an owned `Declaration` — one interpreter over many declarations, where `build.rs` emits generated code per node. The generated path stays, as FR-PLG-2 says it should: a generated `match` is faster than an interpreted one, the built-ins' declared `tests:` have to run under `cargo test`, and generated source is inspectable in a way an interpreter's state is not. **The reader is now one file, read by both.** `src/declared/decl.rs` and `src/declared/expr.rs` are `#[path]`-included by `build.rs` as well as being modules of the crate, and they produce a neutral `Declaration` that names no Rust type. The build script's job is reduced to *rendering* that declaration as Rust; `DeclaredOp` converts the same declaration into descriptors and `Expr::eval` walks the same tree the renderer writes out. There is one grammar, one set of validations and one set of error messages, so "a plugin is the same kind of thing as a built-in" is structural rather than aspirational. What remains genuinely written twice is the pair of backends — an arithmetic node rendered as Rust here and evaluated there — and that is what the parity test stands between. `tests/declared_parity.rs` parses every built-in declaration at run time and asserts the composed WGSL is byte-for-byte what the generated implementation produces, with the uniform block bit-for-bit identical, at both ends of every parameter's range and at four interior points; then again over the whole develop chain with the declared nodes swapped in, which is what covers uniform slot ordering and helper de-duplication between operations. A third test asserts the declared and hand-written nodes partition `ops/` between them, so coverage cannot shrink silently. Bit-for-bit rather than within a tolerance, because a tolerance is where a real divergence hides. The one thing that had to be got right for that to hold is number literals: `expr::as_f32` rounds a decimal exactly once, through the same shortest-round-trip text the compiler is handed, rather than rounding an `f64` a second time. Not in scope, and deliberately untagged: load-time WGSL validation (FR-PLG-11), id namespacing, a plugin directory read at startup, and pass nodes (FR-PLG-2a). Those are separate work, and tagging them from here would be the overstatement the spec's own §7 warns about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
40 lines
1.7 KiB
TOML
40 lines
1.7 KiB
TOML
[package]
|
|
name = "dr-pipeline"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
rust-version.workspace = true
|
|
license.workspace = true
|
|
|
|
# No GPU dependency, deliberately. This crate describes operations and
|
|
# generates their WGSL; dr-gpu compiles and runs it. Keeping wgpu out means
|
|
# the descriptor and codegen logic is testable without a device (ARCH §6.5a).
|
|
[dependencies]
|
|
dr-types.workspace = true
|
|
log.workspace = true
|
|
|
|
# A dependency of the library, not only of the build script, since FR-PLG-2:
|
|
# `src/declared/` reads the same declaration format at *load* time, so that an
|
|
# operation found in a file at startup is the same kind of thing as one found
|
|
# at compile time. The reader itself is one file shared by both.
|
|
serde_norway.workspace = true
|
|
|
|
# Nodes are declared in `ops/*.yaml` and compiled to Rust by `build.rs`
|
|
# (ARCH §5.7). The same reasoning as `ui/dr-ui`'s style.yaml: the declaration
|
|
# is the source of truth, the Rust is generated into OUT_DIR where it cannot
|
|
# be edited or committed by accident.
|
|
#
|
|
# serde_norway rather than serde_yaml for the reason recorded in the workspace
|
|
# manifest — it is the fork still receiving releases, and it preserves mapping
|
|
# order, which is what lets a node's parameters reach the panel in the order
|
|
# its author wrote them.
|
|
[build-dependencies]
|
|
serde_norway.workspace = true
|
|
|
|
[features]
|
|
default = []
|
|
# The detail stage's test consumer — a separable box blur that is not a develop
|
|
# operation and never appears in the panel. See `src/detail/probe.rs` for why an
|
|
# abstraction with no consumers gets a fake one, and `dr-gpu`'s dev-dependency
|
|
# for who turns this on. Off by default, so a shipping build does not contain it.
|
|
detail-probe = []
|