polydat_core/lib.rs
1// Copyright 2024-2026 Jonathan Shook
2// SPDX-License-Identifier: Apache-2.0
3
4//! # polydat-core
5//!
6//! The Polydat runtime: the value model, the graph compiler, the
7//! execution engines, the kernels, the comprehension runtime, the node
8//! macro's support surface, the nodes the compiler synthesizes itself,
9//! and the numeric bodies the native lowerings share with the node
10//! library.
11//!
12//! A program declares typed inputs and a graph of named functions; the
13//! compiler produces a kernel whose named outputs are pulled on demand.
14//! The same inputs always yield the same outputs, on any thread, any
15//! host, and any engine, with no state carried between evaluations.
16//!
17//! Most programs depend on the `polydat` facade, which re-exports this
18//! crate together with the node library (`polydat-nodes`) and the
19//! language (`polydat-grammar`) at the paths they always had. Depend on
20//! `polydat-core` directly to assemble your own node set without the
21//! standard library linked, or to build a tool that needs the compiler
22//! and engines alone.
23//!
24//! ## Quick start
25//!
26//! The runtime compiles any program whose functions are linked. The
27//! standard functions such as `hash` live in `polydat-nodes` and
28//! register at link time, so a program that calls them needs that
29//! crate linked as well:
30//!
31//! ```rust,ignore
32//! use polydat_core::dsl::compile_polydat_with;
33//! use polydat_core::{Engine, Provenance};
34//!
35//! let mut kernel = compile_polydat_with(
36//! r#"
37//! input cycle: u64
38//! id := mod(hash(cycle), 1000)
39//! "#,
40//! Engine::Closures(Provenance::PushPull),
41//! )?;
42//!
43//! kernel.set_inputs(&[7]);
44//! assert!(kernel.pull("id").as_u64() < 1000);
45//! ```
46//!
47//! For programmatic construction, [`compile::assembly::PolydatAssembler`]
48//! wires boxed nodes by name and compiles the result the same way.
49//!
50//! ## Engines
51//!
52//! One program compiles to any of three engines and gives the same
53//! values on each; the host names one with [`Engine`], and
54//! [`Engine::default`] is the fastest the build has.
55//!
56//! - [`Engine::Interpreter`]: boxed nodes over typed value buffers,
57//! with as much of the graph fused into native cones as its
58//! [`JitMode`] allows.
59//! - [`Engine::Closures`]: one generated closure per node over a flat
60//! slot buffer.
61//! - [`Engine::Native`]: Cranelift machine code where a node has a
62//! lowering and the node's closure elsewhere. Needs the `jit`
63//! feature.
64//!
65//! [`Provenance`] chooses how much re-evaluation a changed input
66//! triggers; it is an optimization and never changes a result. Every
67//! engine accepts every program the interpreter accepts and drives it
68//! through the one [`Kernel`] trait.
69//!
70//! ## Program and state
71//!
72//! ```text
73//! inputs (u64 tuple, cursors, externs)
74//! │
75//! ▼
76//! ┌──────────────────────────────────┐
77//! │ KernelProgram immutable, Arc │ shared by every thread
78//! │ nodes · wiring · outputs · consts│
79//! └───────────────┬──────────────────┘
80//! │ create_kernel()
81//! ▼
82//! ┌──────────────────────────────────┐
83//! │ Kernel one per thread │ no locks, no shared writes
84//! │ slot buffers · provenance masks │
85//! └───────────────┬──────────────────┘
86//! ▼
87//! pull("id") → Value
88//! ```
89//!
90//! A [`KernelProgram`] is the compiled, immutable half, shared by
91//! reference; a [`Kernel`] is one thread's private state over it.
92//! Outputs are owned by their provenance: a value stands until an
93//! input that reaches it is written.
94//!
95//! ## Cargo features
96//!
97//! - **`jit`** (default): the native engine, on Cranelift.
98//! - **`vectordata`**: vector-dataset access nodes for ML/AI-oriented
99//! workloads.
100//!
101//! ## Modules
102//!
103//! - [`ast`]: the value model and node contract: [`ast::Value`],
104//! the [`ast::PolydatNode`] trait, [`ast::Port`].
105//! - [`dsl`]: compiling Polydat source:
106//! [`dsl::compile_polydat_with`] for a chosen engine,
107//! [`dsl::compile_polydat_kernel`] for the default, and
108//! [`dsl::compile_polydat`] for the interpreter kernel; the node
109//! registry, factories, and compile events.
110//! - [`compile`]: graph construction and the engines:
111//! [`compile::assembly`] (the assembler and adapter insertion),
112//! [`compile::fusion`], [`compile::closures`], [`compile::hybrid`]
113//! (the native engine's kernel), `compile::jit` (Cranelift lowering,
114//! feature-gated), [`compile::select`] (engine and provenance
115//! selection).
116//! - [`kernel`]: the runtime: the [`Kernel`] and [`KernelProgram`]
117//! traits, the interpreter's [`kernel::PolydatProgram`] and
118//! [`kernel::PolydatState`], shared cells, scopes, subcontexts,
119//! traversal activation.
120//! - [`iteration`]: comprehensions, cursors, partitions, and the
121//! coordinate algebra.
122//! - [`library`]: the nodes the compiler keeps: adapters
123//! ([`library::polyfill`]), assertions, constants, identity,
124//! formatting, tile rendering ([`library::tile_render`]), and the
125//! library-internal support ([`library::support`]). The node library
126//! proper is `polydat-nodes`.
127//! - [`numeric`]: the numeric bodies shared by the node library and the
128//! native lowerings.
129//! - [`tile`]: Polytile at the host boundary.
130//! - [`binder`], [`derive_support`], [`resource`], [`audit`]: the typed
131//! binding contracts, the `#[polydat_node]` macro's support surface,
132//! the host resource bridge, and the log sink.
133//! - [`viz`]: AST and graph visualization, re-exported from the grammar.
134//!
135//! The narrative documentation lives in the repository under
136//! `crates/polydat/docs/`, organized by the
137//! [documentation index](https://github.com/nosqlbench/polydat/blob/main/crates/polydat/docs/README.md);
138//! the [runtime model](https://github.com/nosqlbench/polydat/blob/main/crates/polydat/docs/design/runtime_model.md),
139//! the [graph compiler](https://github.com/nosqlbench/polydat/blob/main/crates/polydat/docs/design/graph_compiler.md),
140//! and the [engines](https://github.com/nosqlbench/polydat/blob/main/crates/polydat/docs/design/engines.md)
141//! design documents are the ones to read first.
142
143// Unit tests use round-number float literals (`3.14`, `1.57`,
144// `2.71`, …) as arbitrary fixture data. clippy's `approx_constant`
145// is a deny-by-default correctness lint that reads those as
146// fat-fingered `std::f*::consts::*` — true for production code,
147// noise for test data. Scope the allowance to `cfg(test)` so the
148// lint still guards real code.
149#![cfg_attr(test, allow(clippy::approx_constant))]
150#![warn(missing_docs)]
151
152// SRD-80 PR B.3 — let the `#[polydat_node]` macro's emitted
153// `polydat::...` paths resolve when the macro is invoked from
154// INSIDE the polydat crate itself (library nodes migrating to
155// the macro form). External callers don't need this — they
156// reference `polydat` via the regular crate-name lookup.
157extern crate self as polydat;
158
159pub mod ast;
160pub mod binder;
161pub mod compile;
162pub mod dsl;
163pub mod iteration;
164pub mod kernel;
165pub mod library;
166pub mod numeric;
167pub use polydat_grammar::viz;
168
169/// Polytile at the host boundary (SRD 114 §5.6): build a tile from
170/// template text, from structural JSON text, or from a parsed JSON
171/// value, then compile it with a program via
172/// [`tile::compile_polydat_with_tiles`].
173pub mod tile {
174 pub use crate::dsl::ast::{TileBodyKind, TileDef, TileOptions, TilePiece};
175 pub use crate::dsl::compile::{compile_polydat_kernel_with_tiles, compile_polydat_with_tiles};
176 pub use crate::dsl::lexer::Span;
177 pub use crate::dsl::tile::{parse_template, render_template};
178 pub use crate::dsl::tile_structural::{
179 ENCODINGS, template_text_from_value, tile_from_json_text, tile_from_json_value,
180 tile_from_text,
181 };
182}
183
184// SRD-104 — dependency-inverted resource-accessor bridge. A
185// type-erased trait + process-global install point by which a
186// kernel node reaches a live, host-owned resource by fingerprint,
187// without polydat depending on the host runtime.
188pub mod resource;
189
190// SRD-80 — proc-macro trait surface. The `polydat-derive`
191// crate emits paths like `polydat::derive_support::FromValue` /
192// `IntoValue` that resolve here.
193pub mod derive_support;
194
195// SRD-80 PR B.5 — `Const<T>` wrapper re-exported at crate root
196// for ergonomic use in `#[polydat_node]` function signatures.
197pub use derive_support::Const;
198
199/// How much of the interpreter's graph is fused into native cones:
200/// what `Engine::Interpreter` carries.
201pub use compile::cone::JitMode;
202/// The engine a host chooses and the one error of every constructor
203/// that takes it (docs/design/engine_parity.md, step 4).
204pub use compile::select::{Engine, EnginePlan, KernelError, Provenance};
205/// One kernel API for every engine.
206pub use kernel::{Kernel, KernelProgram};
207
208// SRD-82 §"Panic reporting: one full render" — host runtimes with
209// their own panic reporting declare it so the eval-panic hook
210// prints a short notice instead of the full diagnostic.
211pub use kernel::set_panic_reporting_downstream;
212
213// SRD-80 — re-export the `#[polydat_node]` attribute so
214// library callers can write `#[polydat::polydat_node]` without
215// a separate `use polydat_derive::polydat_node;` line.
216pub use polydat_derive::polydat_node;
217
218// SRD-80 — re-export `inventory` so the macro's emitted
219// `::polydat::inventory::submit!` path resolves at every call
220// site without users having to add `inventory` to their own
221// dependencies.
222pub use inventory;
223
224/// Re-exported for `#[polydat_node]`-generated Phase-2 buffer
225/// casts on `half::f16`-typed wires (the generated code spells
226/// `polydat::half::f16`, which `extern crate self as polydat`
227/// resolves inside this crate too).
228pub use half;
229
230/// SRD-104 — the resource-accessor bridge at the crate root so the
231/// host installs via `polydat::RESOURCE_ACCESSOR` and nodes resolve
232/// via `polydat::resource_lookup`, without reaching a deep module
233/// path (D6).
234pub use resource::{RESOURCE_ACCESSOR, ResourceAccessor, resource_lookup};
235
236/// Host-log sink bridge — the sanctioned public path for installing
237/// a leveled log sink into the kernel (`set_log_fn`) and for emitting
238/// through it (`warn` / `info` / …). The activity runner installs its
239/// `observer::log` here so polydat's cycle-time data-source audit lines
240/// land in `session.log`. This is the one public entry point for the
241/// audit channel; the implementation lives under `library::support`,
242/// which is library-internal and must not be reached directly.
243pub use library::support::audit;