sim-nest 0.1.5

The SIM constellation umbrella facade: one crate that re-exports the runtime kernel, codecs, number domains, and libraries behind features.
Documentation
#[cfg(feature = "numbers-exotic")]
use crate::runtime::install_core_runtime;
#[cfg(feature = "numbers-exotic")]
use sim_kernel::{Args, Expr, Symbol};
#[cfg(feature = "numbers-exotic")]
use sim_kernel::{DefaultFactory, EagerPolicy};
#[cfg(feature = "numbers-exotic")]
use std::sync::Arc;

#[cfg(feature = "numbers-exotic")]
fn runtime() -> sim_kernel::Cx {
    let mut cx = sim_kernel::Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    cx
}

#[cfg(feature = "numbers-exotic")]
#[test]
fn continued_fraction_browse_reports_endless_tail() {
    let mut cx = runtime();
    let value = cx
        .registry()
        .value_by_symbol(&Symbol::new("cf-pi"))
        .unwrap()
        .clone();
    let table = value.object().as_table(&mut cx).unwrap();
    let Expr::Map(entries) = table.object().as_expr(&mut cx).unwrap() else {
        panic!("expected browse table");
    };
    let tail = entries
        .into_iter()
        .find_map(|(key, value)| match key {
            Expr::Symbol(symbol) if symbol == Symbol::new("tail") => Some(value),
            _ => None,
        })
        .unwrap();
    assert_eq!(tail, Expr::String("endless".to_owned()));
}

#[cfg(feature = "numbers-exotic")]
#[test]
fn take_reads_cf_pi_without_forcing_beyond_requested_coefficients() {
    let mut cx = runtime();
    let value = cx
        .call_function(
            &Symbol::new("take"),
            Args::new(vec![
                cx.registry()
                    .value_by_symbol(&Symbol::new("cf-pi"))
                    .unwrap()
                    .clone(),
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "f64"), "5".to_owned())
                    .unwrap(),
            ]),
        )
        .unwrap();
    assert_eq!(
        value.object().as_expr(&mut cx).unwrap(),
        Expr::List(vec![
            Expr::Number(sim_kernel::NumberLiteral {
                domain: Symbol::qualified("numbers", "i64"),
                canonical: "3".to_owned(),
            }),
            Expr::Number(sim_kernel::NumberLiteral {
                domain: Symbol::qualified("numbers", "i64"),
                canonical: "7".to_owned(),
            }),
            Expr::Number(sim_kernel::NumberLiteral {
                domain: Symbol::qualified("numbers", "i64"),
                canonical: "15".to_owned(),
            }),
            Expr::Number(sim_kernel::NumberLiteral {
                domain: Symbol::qualified("numbers", "i64"),
                canonical: "1".to_owned(),
            }),
            Expr::Number(sim_kernel::NumberLiteral {
                domain: Symbol::qualified("numbers", "i64"),
                canonical: "292".to_owned(),
            }),
        ])
    );
}

#[cfg(all(
    feature = "numbers-exotic",
    feature = "numbers-f64",
    not(feature = "numbers-cas")
))]
#[test]
fn continued_fraction_adds_as_f64_without_cas() {
    let mut cx = runtime();
    let value = cx
        .call_function(
            &Symbol::qualified("math", "add"),
            Args::new(vec![
                cx.registry()
                    .value_by_symbol(&Symbol::new("cf-sqrt2"))
                    .unwrap()
                    .clone(),
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "f64"), "1".to_owned())
                    .unwrap(),
            ]),
        )
        .unwrap();
    let Expr::Number(number) = value.object().as_expr(&mut cx).unwrap() else {
        panic!("expected numeric literal");
    };
    assert_eq!(number.domain, Symbol::qualified("numbers", "f64"));
    let approx = number.canonical.parse::<f64>().unwrap();
    assert!((approx - (std::f64::consts::SQRT_2 + 1.0)).abs() < 1e-12);
}