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-i64")]
use std::sync::Arc;

#[cfg(feature = "numbers-i64")]
use sim_kernel::{Args, DefaultFactory, Expr, NoopEvalPolicy, NumberLiteral, Symbol};

#[cfg(feature = "numbers-i64")]
use crate::runtime::install_core_runtime;

#[cfg(all(feature = "numbers-bool", feature = "numbers-fixed"))]
use super::support::table_value;

#[cfg(all(feature = "numbers-bool", feature = "numbers-fixed"))]
#[test]
fn bool_domain_browse_exposes_value_shape() {
    let mut cx = sim_kernel::Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    let domain = cx
        .resolve_number_domain(&Symbol::qualified("numbers", "bool"))
        .unwrap()
        .clone();
    let domain_table = domain.object().as_table(&mut cx).unwrap();
    let domain_expr = domain_table.object().as_expr(&mut cx).unwrap();
    assert_eq!(
        table_value(&domain_expr, &Symbol::new("value-shape")),
        Some(&Expr::Symbol(Symbol::qualified(
            "numbers/bool",
            "value-shape"
        )))
    );
}

#[cfg(all(feature = "numbers-bool", feature = "numbers-fixed"))]
#[test]
fn bool_arithmetic_and_promotion_dispatches() {
    let mut cx = sim_kernel::Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    let bool_sum = cx
        .call_function(
            &Symbol::qualified("math", "add"),
            Args::new(vec![
                cx.factory().bool(true).unwrap(),
                cx.factory().bool(false).unwrap(),
            ]),
        )
        .unwrap();
    assert_eq!(
        bool_sum.object().as_expr(&mut cx).unwrap(),
        Expr::Bool(true)
    );

    let bool_product = cx
        .call_function(
            &Symbol::qualified("math", "mul"),
            Args::new(vec![
                cx.factory().bool(true).unwrap(),
                cx.factory().bool(true).unwrap(),
            ]),
        )
        .unwrap();
    assert_eq!(
        bool_product.object().as_expr(&mut cx).unwrap(),
        Expr::Bool(true)
    );

    let promoted = cx
        .call_function(
            &Symbol::qualified("math", "add"),
            Args::new(vec![
                cx.factory().bool(true).unwrap(),
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "1".to_owned())
                    .unwrap(),
            ]),
        )
        .unwrap();
    assert_eq!(
        promoted.object().as_expr(&mut cx).unwrap(),
        Expr::Number(NumberLiteral {
            domain: Symbol::qualified("numbers", "i64"),
            canonical: "2".to_owned()
        })
    );
}

#[cfg(all(feature = "numbers-i64", not(feature = "numbers-rational")))]
#[test]
fn i64_division_stays_integer_without_rational() {
    let mut cx = sim_kernel::Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    let value = cx
        .call_function(
            &Symbol::qualified("math", "div"),
            Args::new(vec![
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "1".to_owned())
                    .unwrap(),
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "2".to_owned())
                    .unwrap(),
            ]),
        )
        .unwrap();
    assert_eq!(
        value.object().as_expr(&mut cx).unwrap(),
        Expr::Number(NumberLiteral {
            domain: Symbol::qualified("numbers", "i64"),
            canonical: "0".to_owned()
        })
    );
}

#[cfg(all(feature = "numbers-i64", feature = "numbers-rational"))]
#[test]
fn i64_division_prefers_rational_when_installed() {
    let mut cx = sim_kernel::Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    let value = cx
        .call_function(
            &Symbol::qualified("math", "div"),
            Args::new(vec![
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "1".to_owned())
                    .unwrap(),
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "2".to_owned())
                    .unwrap(),
            ]),
        )
        .unwrap();
    assert_eq!(
        value.object().as_expr(&mut cx).unwrap(),
        Expr::Number(NumberLiteral {
            domain: Symbol::qualified("numbers", "rational"),
            canonical: "1/2".to_owned()
        })
    );
}

#[cfg(all(feature = "numbers-bigint", feature = "numbers-i64"))]
#[test]
fn overflowing_i64_multiplication_yields_bigint() {
    let mut cx = sim_kernel::Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    let value = cx
        .call_function(
            &Symbol::qualified("math", "mul"),
            Args::new(vec![
                cx.factory()
                    .number_literal(
                        Symbol::qualified("numbers", "i64"),
                        "1000000000000".to_owned(),
                    )
                    .unwrap(),
                cx.factory()
                    .number_literal(
                        Symbol::qualified("numbers", "i64"),
                        "1000000000000".to_owned(),
                    )
                    .unwrap(),
            ]),
        )
        .unwrap();
    assert_eq!(
        value.object().as_expr(&mut cx).unwrap(),
        Expr::Number(NumberLiteral {
            domain: Symbol::qualified("numbers", "bigint"),
            canonical: "1000000000000000000000000".to_owned()
        })
    );
}

#[cfg(all(feature = "numbers-bigint", feature = "numbers-i64"))]
#[test]
fn i64_pow_overflow_promotes_to_bigint() {
    let mut cx = sim_kernel::Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    let power = cx
        .call_function(
            &Symbol::qualified("math", "pow"),
            Args::new(vec![
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "2".to_owned())
                    .unwrap(),
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "200".to_owned())
                    .unwrap(),
            ]),
        )
        .unwrap();
    let value = cx
        .call_function(
            &Symbol::qualified("math", "add"),
            Args::new(vec![
                cx.factory()
                    .number_literal(Symbol::qualified("numbers", "i64"), "1".to_owned())
                    .unwrap(),
                power,
            ]),
        )
        .unwrap();
    let Expr::Number(number) = value.object().as_expr(&mut cx).unwrap() else {
        panic!("expected bigint result");
    };
    assert_eq!(number.domain, Symbol::qualified("numbers", "bigint"));
    assert!(
        number
            .canonical
            .starts_with("1606938044258990275541962092341162602522202993782792835301377")
    );
}