Skip to main content

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