Skip to main content

sim_value/
build.rs

1//! Constructors for kernel `Expr` data.
2//!
3//! These are the one home for "make a symbol / number / string / map".
4//! Float canonicalization matches Rust's `f64` `Display` (which already drops a
5//! trailing `.0`), so values built here are byte-identical to a direct
6//! `number(f64)` construction.
7
8use sim_kernel::{Expr, NumberLiteral, Symbol};
9
10/// An unqualified symbol value: `Expr::Symbol(Symbol::new(name))`.
11pub fn sym(name: &str) -> Expr {
12    Expr::Symbol(Symbol::new(name))
13}
14
15/// A qualified symbol value: `Expr::Symbol(Symbol::qualified(ns, name))`.
16pub fn qsym(ns: &str, name: &str) -> Expr {
17    Expr::Symbol(Symbol::qualified(ns, name))
18}
19
20/// A bare keyword `Symbol` (NOT wrapped in `Expr`). This is the one home for the
21/// `fn field(name) -> Symbol` / `Symbol::new(name)` wrappers that test and codec
22/// crates re-grew; use [`sym`] when an `Expr` is wanted.
23pub fn keyword(name: &str) -> Symbol {
24    Symbol::new(name)
25}
26
27/// An `i64`-domain number value.
28pub fn int(value: i64) -> Expr {
29    num("i64", &value.to_string())
30}
31
32/// An `i64`-domain number value from an unsigned integer.
33pub fn uint(value: u64) -> Expr {
34    num("i64", &value.to_string())
35}
36
37/// An `f64`-domain number value with a canonical literal.
38pub fn float(value: f64) -> Expr {
39    num("f64", &format!("{value}"))
40}
41
42/// A number value in `domain` with the given `canonical` literal.
43pub fn num(domain: &str, canonical: &str) -> Expr {
44    Expr::Number(NumberLiteral {
45        domain: Symbol::new(domain),
46        canonical: canonical.to_owned(),
47    })
48}
49
50/// A number value whose domain may be namespace-qualified. `num_q(None, name,
51/// canonical)` is identical to [`num`]; `num_q(Some(ns), name, canonical)`
52/// emits a qualified domain symbol (for example `numbers/f64`). Use this when a
53/// caller must preserve an existing qualified number domain rather than the
54/// unqualified spelling produced by [`float`] or [`num`].
55pub fn num_q(ns: Option<&str>, name: &str, canonical: &str) -> Expr {
56    let domain = match ns {
57        Some(ns) => Symbol::qualified(ns, name),
58        None => Symbol::new(name),
59    };
60    Expr::Number(NumberLiteral {
61        domain,
62        canonical: canonical.to_owned(),
63    })
64}
65
66/// A string value.
67pub fn text(value: impl Into<String>) -> Expr {
68    Expr::String(value.into())
69}
70
71/// A list value.
72pub fn list(items: Vec<Expr>) -> Expr {
73    Expr::List(items)
74}
75
76/// A vector value.
77pub fn vector(items: Vec<Expr>) -> Expr {
78    Expr::Vector(items)
79}
80
81/// A single map entry with a bare-symbol key: `(sym(name), value)`. This is the
82/// one home for the `fn entry(name, value)` tuple builder used by domain crates
83/// (topology, agent, reflection).
84pub fn entry(name: &str, value: Expr) -> (Expr, Expr) {
85    (sym(name), value)
86}
87
88/// A map value from string-keyed entries (keys become unqualified symbols).
89pub fn map(entries: Vec<(&str, Expr)>) -> Expr {
90    Expr::Map(
91        entries
92            .into_iter()
93            .map(|(key, value)| (sym(key), value))
94            .collect(),
95    )
96}