Skip to main content

sim_list_cell/
backend.rs

1//! Library registration for the cons-cell list backend: the [`ConsBackend`]
2//! `ListBackend` implementation, the [`ConsListLib`] manifest, and the
3//! [`install_cons_list_lib`] entry point.
4
5use std::sync::Arc;
6
7use sim_kernel::{
8    AbiVersion, Cx, Dependency, Error, Export, Lib, LibManifest, LibTarget, Linker, ListBackend,
9    Result, Symbol, Value, Version,
10};
11
12use crate::ConsList;
13
14/// The `cons` [`ListBackend`]: constructs [`ConsList`] objects for the
15/// runtime's list-construction and `cons` operations.
16pub struct ConsBackend;
17
18impl ListBackend for ConsBackend {
19    fn name(&self) -> &str {
20        "cons"
21    }
22
23    fn new_list(&self, cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
24        cx.factory().opaque(ConsList::from_vec(items))
25    }
26
27    fn new_cons(&self, cx: &mut Cx, car: Value, cdr: Value) -> Result<Value> {
28        match cdr.object().downcast_ref::<ConsList>() {
29            Some(cons) => cx
30                .factory()
31                .opaque(Arc::new(ConsList::cell(car, Arc::new(cons.clone())))),
32            None => {
33                // A non-`ConsList` tail is kept lazily rather than materialized,
34                // so consing onto a lazy or unbounded list does not realize its
35                // spine.
36                if cdr.object().as_list().is_none() {
37                    return Err(Error::TypeMismatch {
38                        expected: "list",
39                        found: "non-list",
40                    });
41                }
42                cx.factory()
43                    .opaque(Arc::new(ConsList::cell_foreign(car, cdr)))
44            }
45        }
46    }
47}
48
49/// The loadable [`Lib`] manifest for the cons-cell list backend, registered
50/// under the `list/cons` id by [`install_cons_list_lib`].
51pub struct ConsListLib;
52
53impl Lib for ConsListLib {
54    // Empty-manifest boilerplate is intentionally local: unlike the table
55    // backends (which share sim_table_core::backend_manifest), the list crates
56    // have no shared list-core owner yet, so a table-crate dep would be wrong.
57    fn manifest(&self) -> LibManifest {
58        LibManifest {
59            id: Symbol::qualified("list", "cons"),
60            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
61            abi: AbiVersion { major: 0, minor: 1 },
62            target: LibTarget::HostRegistered,
63            requires: Vec::<Dependency>::new(),
64            capabilities: Vec::new(),
65            exports: Vec::<Export>::new(),
66        }
67    }
68
69    fn load(&self, _cx: &mut sim_kernel::LoadCx, _linker: &mut Linker<'_>) -> Result<()> {
70        Ok(())
71    }
72}
73
74/// Registers the [`ConsBackend`] in the list registry and loads
75/// [`ConsListLib`], making cons-cell lists available to `cx`.
76///
77/// Idempotent: returns early if the `list/cons` lib is already present.
78pub fn install_cons_list_lib(cx: &mut Cx) -> Result<()> {
79    if cx
80        .registry()
81        .lib(&Symbol::qualified("list", "cons"))
82        .is_some()
83    {
84        return Ok(());
85    }
86    cx.list_registry_mut().register(Arc::new(ConsBackend));
87    cx.load_lib(&ConsListLib).map(|_| ())
88}