Skip to main content

sim/classes/
lib_support.rs

1use std::sync::Arc;
2
3use sim_kernel::{
4    AbiVersion, Dependency, Export, Factory, Lib, LibManifest, LibTarget, Linker, LoadCx, Result,
5    Symbol, Value, Version,
6};
7
8use crate::{classes::model::NativeClass, shapes::shape_value};
9
10/// Lib that registers a host-defined [`NativeClass`], its constructor, optional
11/// constructor and instance shapes, and its member functions.
12pub struct NativeClassLib {
13    manifest: LibManifest,
14    class_symbol: Symbol,
15    class_value: Value,
16    constructor_symbol: Symbol,
17    constructor_value: Value,
18    constructor_shape_symbol: Option<Symbol>,
19    constructor_shape_value: Option<Value>,
20    instance_shape_symbol: Option<Symbol>,
21    instance_shape_value: Option<Value>,
22    member_values: Vec<(Symbol, Value)>,
23}
24
25impl NativeClassLib {
26    /// Builds the lib from a native class, lib symbol, and version string.
27    pub fn from_class(lib_symbol: Symbol, class: &NativeClass, version: impl Into<String>) -> Self {
28        let version = Version(version.into());
29        let constructor_shape_symbol = Some(Symbol::qualified(
30            class.symbol.to_string(),
31            "constructor-shape",
32        ));
33        let constructor_shape_value = class.constructor_shape_arc().map(|shape| {
34            shape_value(
35                Symbol::qualified(class.symbol.to_string(), "constructor-shape"),
36                shape,
37            )
38        });
39        let instance_shape_symbol = class
40            .instance_shape
41            .as_ref()
42            .map(|_| Symbol::qualified(class.symbol.to_string(), "instance-shape"));
43        let instance_shape_value = class.instance_shape.as_ref().map(|shape| {
44            shape_value(
45                Symbol::qualified(class.symbol.to_string(), "instance-shape"),
46                shape.clone(),
47            )
48        });
49
50        let mut exports = vec![
51            Export::Class {
52                symbol: class.symbol.clone(),
53                class_id: None,
54            },
55            Export::Function {
56                symbol: class.constructor.symbol.clone(),
57                function_id: None,
58            },
59        ];
60        if let Some(symbol) = &constructor_shape_symbol {
61            exports.push(Export::Shape {
62                symbol: symbol.clone(),
63                shape_id: None,
64            });
65        }
66        if let Some(symbol) = &instance_shape_symbol {
67            exports.push(Export::Shape {
68                symbol: symbol.clone(),
69                shape_id: None,
70            });
71        }
72        exports.extend(class.members.iter().map(|member| Export::Function {
73            symbol: member.symbol.clone(),
74            function_id: None,
75        }));
76
77        Self {
78            manifest: LibManifest {
79                id: lib_symbol,
80                version,
81                abi: AbiVersion { major: 0, minor: 1 },
82                target: LibTarget::HostRegistered,
83                requires: Vec::<Dependency>::new(),
84                capabilities: Vec::new(),
85                exports,
86            },
87            class_symbol: class.symbol.clone(),
88            class_value: sim_kernel::DefaultFactory
89                .opaque(Arc::new(class.clone()))
90                .expect("class should be boxable"),
91            constructor_symbol: class.constructor.symbol.clone(),
92            constructor_value: sim_kernel::DefaultFactory
93                .opaque(Arc::new(class.constructor.clone()))
94                .expect("constructor should be boxable"),
95            constructor_shape_symbol,
96            constructor_shape_value,
97            instance_shape_symbol,
98            instance_shape_value,
99            member_values: class
100                .members
101                .iter()
102                .map(|member| {
103                    (
104                        member.symbol.clone(),
105                        sim_kernel::DefaultFactory
106                            .opaque(Arc::new(member.clone()))
107                            .expect("member function should be boxable"),
108                    )
109                })
110                .collect(),
111        }
112    }
113}
114
115impl Lib for NativeClassLib {
116    fn manifest(&self) -> LibManifest {
117        self.manifest.clone()
118    }
119
120    fn load(&self, _cx: &mut LoadCx, linker: &mut Linker) -> Result<()> {
121        linker.class_value(self.class_symbol.clone(), self.class_value.clone())?;
122        linker.function_value(
123            self.constructor_symbol.clone(),
124            self.constructor_value.clone(),
125        )?;
126        if let (Some(symbol), Some(value)) = (
127            &self.constructor_shape_symbol,
128            &self.constructor_shape_value,
129        ) {
130            linker.shape_value(symbol.clone(), value.clone())?;
131        }
132        if let (Some(symbol), Some(value)) =
133            (&self.instance_shape_symbol, &self.instance_shape_value)
134        {
135            linker.shape_value(symbol.clone(), value.clone())?;
136        }
137        for (symbol, value) in &self.member_values {
138            linker.function_value(symbol.clone(), value.clone())?;
139        }
140        Ok(())
141    }
142}