Skip to main content

kip/
lib.rs

1//! # kip — engineering expression evaluator (US imperial)
2//!
3//! kip is a pure, thread-safe evaluator for engineering expressions with exact
4//! rational arithmetic, partial (symbolic) evaluation, and a user-extensible unit
5//! registry anchored to **inch, lbf, second, Rankine** (plus angle and custom
6//! base dimensions).
7//!
8//! ## Force-based (gravitational) system
9//!
10//! kip uses a **force-based** dimensional system common in structural engineering:
11//! **Force** is a base dimension (anchor: `lbf`), and **mass** is derived
12//! (`slug = lbf·s²/ft`). There is no hidden *g*<sub>c</sub> constant in user-visible
13//! math. SI-trained users: do not expect mass to be fundamental here.
14//!
15//! ## Typical workflow
16//!
17//! 1. Build or load a [`Registry`] (`RegistryBuilder::from_seed`, [`RegistryBuilder::parse_defs`],
18//!    [`RegistryBuilder::load_packs`]).
19//! 2. [`parse`] an expression against that registry (optional [`Resolver`] for symbols).
20//! 3. [`eval`] to a [`Value`] — fully [`Quantity`] or [`eval::value::SymExpr`] residual.
21//! 4. Format with [`Quantity::display`] and [`FmtOptions`], or bind further with [`Value::bind`].
22//!
23//! ## Concurrency (P1)
24//!
25//! ASTs ([`Expr`]), registries ([`Registry`]), and evaluation are immutable and
26//! `Send + Sync`. Evaluation is a pure function — no globals, no locks.
27//! With the `parallel` feature: [`eval_batch`], [`eval_scenarios`], and intra-expression
28//! `rayon` splits above [`PARALLEL_THRESHOLD`] nodes.
29//!
30//! ## Code equations (P2)
31//!
32//! Namespaced calls such as `ACI.fr(fc: 4000 psi, lambda: 1.0)` require named arguments.
33//! Load pack TOML via [`RegistryBuilder::load_packs`] or [`load_packs`]; results carry
34//! [`EquationProvenance`] on [`Quantity`].
35//!
36//! ## Version 0.1.0
37//!
38//! Full grammar conformance (lexer → packs → parallel/fmt). See `CHANGELOG.md` and
39//! `VERSIONING.md` for release policy.
40
41#![warn(clippy::mod_module_files)]
42#![warn(missing_docs)]
43
44mod dim;
45mod diag;
46mod eval;
47mod fmt;
48mod lexer;
49mod packs;
50mod parser;
51mod quantity;
52mod registry;
53mod resolver;
54
55pub use diag::{Diag, Diagnostic, ErrorCode, Hint, LintCode, Severity, Span};
56pub use dim::{BaseDim, CustomDimId, Dimension};
57pub use eval::{eval, eval_checked, EvalOutcome, LintSink, Mag, Value};
58pub use eval::units::convert_quantity;
59pub use eval::value::{ConstraintSet, EquationProvenance, Quantity, SymBinaryOp, SymExpr, SymNode, SymUnaryOp, Symbol};
60pub use fmt::{format_quantity, FmtOptions};
61pub use lexer::{lex, lex_checked, LexOutcome, LexSpan, SpannedToken, Token};
62pub use parser::{parse, parse_checked, BinaryOp, Callee, CallArg, CmpOp, Expr, ExprKind, ExprNode, NodeId, ParseOutcome, UnaryOp};
63pub use quantity::{UnitExpr, UnitExponent};
64pub use registry::{Registry, RegistryBuilder};
65pub use resolver::{EmptyResolver, MapResolver, Resolver};
66pub use packs::equation::{EquationRecord, EquationRegistry};
67#[cfg(feature = "packs")]
68pub use packs::{load_packs, load_packs_into, DEMO_PACK_TOML};
69
70#[cfg(feature = "parallel")]
71pub use eval::{eval_batch, eval_scenarios, PARALLEL_THRESHOLD};
72
73/// Crate version string (matches `Cargo.toml`).
74pub const VERSION: &str = env!("CARGO_PKG_VERSION");
75
76#[cfg(test)]
77mod send_sync {
78    use super::*;
79    use std::sync::Arc;
80
81    const fn assert_send_sync<T: Send + Sync + ?Sized>() {}
82
83    #[test]
84    fn public_types_are_send_sync() {
85        assert_send_sync::<Dimension>();
86        assert_send_sync::<Quantity>();
87        assert_send_sync::<Value>();
88        assert_send_sync::<Diag>();
89        assert_send_sync::<Diagnostic>();
90        assert_send_sync::<Registry>();
91        assert_send_sync::<Expr>();
92        assert_send_sync::<Arc<Registry>>();
93        assert_send_sync::<Arc<Expr>>();
94        assert_send_sync::<SpannedToken>();
95        assert_send_sync::<Token>();
96        assert_send_sync::<dyn Resolver>();
97    }
98}