Skip to main content

sim_lib_numbers_codec/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3#![allow(deprecated)]
4
5//! The number-literal codec surface: helpers that build the `numeric-plugin-v1`
6//! descriptor symbols and table values advertising a numeric codec or method
7//! provider to the runtime.
8
9use sim_kernel::{Factory, Result, Symbol, Value};
10
11/// Build the descriptor symbol `group/name` advertising a numeric codec or
12/// method provider under the `numeric-plugin-v1` API.
13///
14/// # Examples
15///
16/// ```
17/// use sim_kernel::Symbol;
18/// use sim_lib_numbers_codec::numeric_plugin_descriptor_symbol;
19///
20/// assert_eq!(
21///     numeric_plugin_descriptor_symbol("numbers/quad", "simpson"),
22///     Symbol::qualified("numbers/quad", "simpson"),
23/// );
24/// ```
25pub fn numeric_plugin_descriptor_symbol(group: &str, name: &str) -> Symbol {
26    Symbol::qualified(group, name)
27}
28
29/// Build the `numeric-plugin-v1` descriptor table for `method`, recording its
30/// plugin `kind`, whether it is `adaptive`, and the `provider` domain that
31/// supplies it.
32pub fn numeric_plugin_descriptor_value(
33    factory: &dyn Factory,
34    method: Symbol,
35    kind: &str,
36    adaptive: bool,
37    provider: Symbol,
38) -> Result<Value> {
39    factory.table(vec![
40        (
41            Symbol::new("kind"),
42            factory.string("numeric-plugin".to_owned())?,
43        ),
44        (Symbol::new("method"), factory.symbol(method)?),
45        (Symbol::new("plugin-kind"), factory.string(kind.to_owned())?),
46        (Symbol::new("adaptive"), factory.bool(adaptive)?),
47        (Symbol::new("provider"), factory.symbol(provider)?),
48        (
49            Symbol::new("api"),
50            factory.string("numeric-plugin-v1".to_owned())?,
51        ),
52    ])
53}
54
55#[cfg(test)]
56mod tests {
57    use std::sync::Arc;
58
59    use sim_kernel::{DefaultFactory, Expr, NoopEvalPolicy};
60    use sim_lib_numbers_core::domains;
61
62    use super::{numeric_plugin_descriptor_symbol, numeric_plugin_descriptor_value};
63
64    #[test]
65    fn descriptor_symbol_uses_namespaced_group() {
66        assert_eq!(
67            numeric_plugin_descriptor_symbol("numbers/quad", "simpson"),
68            sim_kernel::Symbol::qualified("numbers/quad", "simpson")
69        );
70    }
71
72    #[test]
73    fn descriptor_value_has_stable_table_surface() {
74        let factory = DefaultFactory;
75        let mut cx = sim_kernel::Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
76        let value = numeric_plugin_descriptor_value(
77            &factory,
78            sim_kernel::Symbol::new("rkf45"),
79            "ode",
80            true,
81            domains::rk(),
82        )
83        .unwrap();
84        let Expr::Map(entries) = value.object().as_expr(&mut cx).unwrap() else {
85            panic!("descriptor should encode as a map");
86        };
87        assert!(entries.iter().any(|(key, value)| {
88            *key == Expr::Symbol(sim_kernel::Symbol::new("method"))
89                && *value == Expr::Symbol(sim_kernel::Symbol::new("rkf45"))
90        }));
91    }
92}