Skip to main content

marque_engine/
lib.rs

1// SPDX-FileCopyrightText: 2026 Knitli Inc.
2//
3// SPDX-License-Identifier: LicenseRef-MarqueLicense-1.0
4
5#![forbid(unsafe_code)]
6#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
7
8//! marque-engine — pipeline orchestration.
9//!
10//! Wires together: scanner → parser → validator → fixer → output.
11//! The pipeline is a chain of async streams; each stage is a `Stream` impl.
12//! CLI, WASM, and server are different Source/Sink configurations wired to the same middle.
13
14#[cfg(feature = "batch")]
15pub mod batch;
16pub mod clock;
17pub mod decoder;
18pub mod engine;
19pub mod errors;
20pub mod options;
21pub mod output;
22pub mod pipeline;
23pub mod recognizer;
24pub mod scheduler;
25
26#[cfg(feature = "batch")]
27pub use batch::{BatchEngine, BatchError, BatchOptions};
28pub use clock::{Clock, FixedClock, SystemClock};
29pub use decoder::{DecoderRecognizer, StrictOrDecoderRecognizer};
30pub use engine::{Engine, FixMode, InvalidThreshold};
31pub use errors::{EngineConstructionError, EngineError};
32pub use options::{FixOptions, LintOptions};
33pub use output::{FixResult, LintResult};
34pub use pipeline::{Sink, Source, SourceError, TextChunk};
35pub use recognizer::StrictRecognizer;
36
37/// Re-export of [`web_time::Instant`].
38///
39/// On native targets this is `std::time::Instant` verbatim
40/// (`web_time` `pub use`s the std type). On `wasm32-unknown-unknown`
41/// it's a `Performance.now()` / `Date.now()` polyfill — `std::time::
42/// Instant::now()` panics on that target. The engine's per-candidate
43/// deadline check (spec 005) calls `Instant::now()` whenever a
44/// caller-supplied deadline is set, so any embedder constructing a
45/// `LintOptions { deadline: Some(_) }` for the WASM target MUST use
46/// this `Instant` (or `web_time::Instant` directly) rather than
47/// `std::time::Instant`. CLI and server callers can keep using
48/// `std::time::Instant` because the two types are identical on
49/// native, and those binaries do not target wasm32-unknown-unknown.
50pub use web_time::Instant;
51
52/// Audit-record schema version emitted by this build.
53///
54/// Set at build time by `crates/engine/build.rs` (see `MARQUE_AUDIT_SCHEMA`),
55/// validated against the closed accept-list `["marque-mvp-1", "marque-mvp-2"]`.
56/// Defaults to `"marque-mvp-2"` (Phase D); a build can downgrade by exporting
57/// `MARQUE_AUDIT_SCHEMA=marque-mvp-1`. Re-exported through this crate so CLI
58/// and WASM emitters can populate the `schema` field without each owning a
59/// separate copy of the constant (whitepaper §980 / FR-014).
60///
61/// Per FR-014 the value is fixed for the lifetime of a build — a single
62/// binary emits exactly one schema, never a mix.
63pub const AUDIT_SCHEMA_VERSION: &str = env!("MARQUE_AUDIT_SCHEMA");
64
65/// `true` when this build emits Phase-D audit records (`marque-mvp-2`),
66/// `false` when emitting the legacy `marque-mvp-1` shape.
67///
68/// Evaluated at compile time from [`AUDIT_SCHEMA_VERSION`]; the comparison
69/// against a `&'static str` literal folds to a constant, so callers using
70/// `if AUDIT_SCHEMA_IS_V2 { ... } else { ... }` get dead-branch elimination
71/// at the matching schema's expense.
72pub const AUDIT_SCHEMA_IS_V2: bool = const_str_eq(AUDIT_SCHEMA_VERSION, "marque-mvp-2");
73
74const fn const_str_eq(a: &str, b: &str) -> bool {
75    let a = a.as_bytes();
76    let b = b.as_bytes();
77    if a.len() != b.len() {
78        return false;
79    }
80    let mut i = 0;
81    while i < a.len() {
82        if a[i] != b[i] {
83            return false;
84        }
85        i += 1;
86    }
87    true
88}
89
90/// Returns the default rule set for marque (CAPCO rules).
91///
92/// Both the CLI and WASM front ends use this to share one registration entry point.
93pub fn default_ruleset() -> Vec<Box<dyn marque_rules::RuleSet>> {
94    vec![Box::new(marque_capco::rules::CapcoRuleSet::new())]
95}
96
97/// Returns the default marking scheme for marque (CAPCO).
98///
99/// Callers pass this to [`Engine::new`] to get the standard CAPCO
100/// page-rewrite schedule. The scheme is stateless and cheap to
101/// construct on demand.
102pub fn default_scheme() -> marque_capco::scheme::CapcoScheme {
103    marque_capco::scheme::CapcoScheme::new()
104}