Skip to main content

sim_lib_cookbook/
seed_catalog.rs

1//! A [`LibCatalog`] over the crate-shipped seed domains.
2//!
3//! `sim-lib-cookbook` already depends on the seeded domain libs (to embed their
4//! recipe books), so exposing a catalog over them adds NO new dependency and no
5//! cycle: it is a convenience for hosts and for the COOKBOOK_7 spike, gated on
6//! the same `seed-recipes` feature. A production host assembles its own catalog
7//! from the full standard distribution at the facade level; this one covers the
8//! numbers domains, which is enough to demonstrate Category A (pure compute that
9//! only needs its lib loaded).
10//!
11//! A recipe resolves against this catalog by its `requires` name (`numbers/cas`,
12//! or the tail `cas`): the returned lib's own manifest id IS the cookbook name,
13//! so there is no separate name table to drift.
14
15use sim_kernel::{CodecId, Lib};
16
17use crate::catalog::LibCatalog;
18
19/// A catalog over the seeded numbers domains.
20pub struct SeededLibCatalog {
21    libs: Vec<Box<dyn Lib>>,
22}
23
24impl SeededLibCatalog {
25    /// Build a catalog over the seeded numbers domain libs.
26    ///
27    /// Each lib is a pure, deterministic number domain; loading one adds its ops
28    /// (construction, arithmetic, CAS diff/eval, tensor arithmetic) to the eval
29    /// `Cx` without any effect capability.
30    pub fn standard() -> Self {
31        let libs: Vec<Box<dyn Lib>> = vec![
32            Box::new(sim_lib_numbers_i64::I64NumbersLib::new()),
33            Box::new(sim_lib_numbers_arith::NumbersArithmeticLib::new()),
34            Box::new(sim_lib_numbers_bigint::BigIntNumbersLib::new()),
35            Box::new(sim_lib_numbers_bool::BoolNumbersLib::new()),
36            Box::new(sim_lib_numbers_f64::F64NumbersLib::new()),
37            Box::new(sim_lib_numbers_rational::RationalNumbersLib::new()),
38            Box::new(sim_lib_numbers_complex::ComplexNumbersLib::new()),
39            Box::new(sim_lib_numbers_func::FuncNumbersLib::new()),
40            Box::new(sim_lib_numbers_cas::CasNumbersLib::new()),
41            Box::new(sim_lib_numbers_tensor::TensorNumbersLib::new()),
42            // COOK8.07: tensor broadcast arithmetic, so `tensor-scale`
43            // (`(math/mul (vec 3 4) 2)`) loads via `requires` and runs
44            // host-independently rather than only through the boot prelude.
45            Box::new(sim_lib_numbers_tensor_bcast::TensorBroadcastLib::new()),
46            Box::new(sim_lib_discrete::DiscreteLib),
47            // COOK8.03 organs: the eval-policy special forms load on demand via a
48            // recipe's `requires` (`binding`/`control`/`sequence`/`pattern`), so
49            // `let`/`if`/`seq/*`/`match` recipes run without preloading them.
50            Box::new(sim_lib_binding::BindingLib),
51            Box::new(sim_lib_control::ControlLib),
52            Box::new(sim_lib_sequence::SequenceLib),
53            Box::new(sim_lib_pattern::PatternLib),
54            // COOK8.05 language codecs: loaded on demand so a recipe with
55            // `codec = "algol"`/`"scheme"` parses+evals its own surface. Each is
56            // bound to a distinct fixed CodecId that cannot collide with the boot
57            // `codec/lisp` (id 1); both lower an eval-position surface to a Term the
58            // general evaluator runs. Algol depends on `codec/lisp` (boot-loaded).
59            Box::new(sim_codec_algol::AlgolCodecLib::new(CodecId(201))),
60            Box::new(sim_lib_lang_scheme::SchemeCodecLib::new(CodecId(202))),
61            // COOK8.06 Category C: an offline MIDI render reduced to a
62            // deterministic frame digest (no device/clock/entropy).
63            Box::new(sim_lib_midi_core::MidiDigestLib),
64        ];
65        Self { libs }
66    }
67}
68
69impl LibCatalog for SeededLibCatalog {
70    fn resolve(&self, name: &str) -> Option<&dyn Lib> {
71        self.libs
72            .iter()
73            .find(|lib| {
74                let id = lib.manifest().id;
75                id.as_qualified_str() == name || id.name.as_ref() == name
76            })
77            .map(|lib| lib.as_ref())
78    }
79}