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    fn manifest(&self) -> LibManifest {
55        LibManifest {
56            id: Symbol::qualified("list", "cons"),
57            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
58            abi: AbiVersion { major: 0, minor: 1 },
59            target: LibTarget::HostRegistered,
60            requires: Vec::<Dependency>::new(),
61            capabilities: Vec::new(),
62            exports: Vec::<Export>::new(),
63        }
64    }
65
66    fn load(&self, _cx: &mut sim_kernel::LoadCx, _linker: &mut Linker<'_>) -> Result<()> {
67        Ok(())
68    }
69}
70
71/// Registers the [`ConsBackend`] in the list registry and loads
72/// [`ConsListLib`], making cons-cell lists available to `cx`.
73///
74/// Idempotent: returns early if the `list/cons` lib is already present.
75pub fn install_cons_list_lib(cx: &mut Cx) -> Result<()> {
76    if cx
77        .registry()
78        .lib(&Symbol::qualified("list", "cons"))
79        .is_some()
80    {
81        return Ok(());
82    }
83    cx.list_registry_mut().register(Arc::new(ConsBackend));
84    cx.load_lib(&ConsListLib).map(|_| ())
85}