Skip to main content

fv_compute/
lib.rs

1//! # fv-compute — the transform/compute contract
2//!
3//! A transform is a typed function over Arrow data with a declared
4//! [capability envelope](capability::CapabilityEnvelope), described by a [`TransformManifest`]
5//! (`transform.toml`) against **one** contract and executed by a pluggable [`TransformBackend`]
6//! chosen by the manifest's IMPL. This crate is the "define once" seam: the manifest schema and
7//! its validation (the publish gate), the envelope and binding enforcement, the Arrow-typed
8//! signature, the directory-per-transform [`registry`], and the dispatch traits the backends
9//! implement (`fv-compute-wasm`, `fv-compute-container`, or your own).
10//!
11//! It is a library any caller embeds — a pipeline runner, a materializer, an action runtime, a
12//! REPL — so a transform is reusable outside any one pipeline. `wit/transform.wit` is the same
13//! contract for WASM components; the container protocol mirrors it for processes.
14//!
15//! ```
16//! use fv_compute::{parse_and_validate, ImplKind};
17//! let m = parse_and_validate(r#"
18//!     id = "marginPct"
19//!     version = "1.0.0"
20//!     impl = "expression"
21//!     entry = "src/expr.fvx"
22//!     [[inputs]]
23//!     columns = [{ name = "revenue", type = "float64" }, { name = "cost", type = "float64" }]
24//!     [output]
25//!     columns = [{ name = "marginPct", type = "float64" }]
26//! "#).unwrap();
27//! assert_eq!(m.impl_kind, ImplKind::Expression);
28//! ```
29
30/// Every Rust code block in the README is compiled and run as a doctest.
31#[cfg(doctest)]
32#[doc = include_str!("../README.md")]
33pub struct ReadmeDoctests;
34
35pub mod capability;
36pub mod catalog;
37pub mod contract;
38pub mod manifest;
39pub mod registry;
40pub mod runtime;
41pub mod types;
42
43pub use capability::{Binding, CapabilityEnvelope, EnvelopeViolation, Hardware};
44pub use catalog::{catalog_json, descriptors, model_descriptors, models_json, FieldInfo, TransformDescriptor};
45pub use contract::{Compute, ComputeError, TransformBackend};
46pub use manifest::{
47    parse_and_validate, ContainerProtocol, ImplKind, Labels, LabelsRule, ManifestError, TransformManifest,
48};
49pub use registry::{
50    standard_registry, Backends, DirRoot, MemoryRoot, RawUnit, RegisteredTransform, Registry, RegistryBuilder,
51    RegistryError, RegistryIndex, Root,
52};
53pub use runtime::{Runtime, RuntimeBuilder};
54pub use types::{ColumnSpec, FvType, SchemaSpec};
55
56/// The version of the *contract itself* (independent of any transform's version). Bumped when the
57/// manifest shape / WIT interface changes incompatibly; lets a registry reject manifests authored
58/// against a future contract.
59pub const CONTRACT_VERSION: &str = "0.1.0";
60
61/// Build the transform-index catalogue from a `root[:root…]` spec (paths relative to the current
62/// directory): every registered manifest, as JSON, under the contract version. The published
63/// contract carries a snapshot of this document and consumers of the registry assert against it,
64/// so a registry change cannot silently diverge from the contract. (The `description` text is part
65/// of that snapshot; changing it is a contract change.)
66pub fn transform_index_payload(roots_spec: &str) -> serde_json::Value {
67    use crate::registry::{DirRoot, Registry};
68    let mut b = Registry::builder();
69    for (i, r) in roots_spec.split(':').filter(|s| !s.is_empty()).enumerate() {
70        let name = std::path::Path::new(r)
71            .file_name()
72            .map(|s| s.to_string_lossy().to_string())
73            .unwrap_or_else(|| format!("root{i}"));
74        b = b.root(DirRoot::new(name, std::path::PathBuf::from(r)));
75    }
76    let registry = b.build().expect("build transform registry");
77    let transforms: Vec<serde_json::Value> = registry
78        .iter()
79        .map(|t| serde_json::to_value(&t.manifest).unwrap())
80        .collect();
81    serde_json::json!({
82        "description": "Transform registry catalogue. SINGLE SOURCE = the fv-compute directory-per-transform registry (transforms/ + each business bundle). Generated by `fv-datafusion --emit-transform-index`; the TS pipeline builder reads this to offer registered transforms (container/wasm/expression/builtin) in its palette. Do not hand-edit.",
83        "contractVersion": CONTRACT_VERSION,
84        "transforms": transforms,
85    })
86}