Skip to main content

ion_core/
module.rs

1use indexmap::IndexMap;
2
3use crate::value::{BuiltinFn, Value};
4
5/// A named collection of functions and values that can be registered
6/// with an Engine and accessed via `module::name` syntax in Ion scripts.
7pub struct Module {
8    pub name: String,
9    functions: IndexMap<String, (String, BuiltinFn)>,
10    values: IndexMap<String, Value>,
11    submodules: IndexMap<String, Module>,
12}
13
14impl Module {
15    pub fn new(name: impl Into<String>) -> Self {
16        Self {
17            name: name.into(),
18            functions: IndexMap::new(),
19            values: IndexMap::new(),
20            submodules: IndexMap::new(),
21        }
22    }
23
24    /// Register a builtin function in this module.
25    pub fn register_fn(&mut self, name: &str, func: BuiltinFn) {
26        let qualified = format!("{}::{}", self.name, name);
27        self.functions
28            .insert(name.to_string(), (qualified, func));
29    }
30
31    /// Register a constant value in this module.
32    pub fn set(&mut self, name: &str, value: Value) {
33        self.values.insert(name.to_string(), value);
34    }
35
36    /// Register a submodule (e.g., `net::http`).
37    pub fn register_submodule(&mut self, sub: Module) {
38        self.submodules.insert(sub.name.clone(), sub);
39    }
40
41    /// Convert this module into a `Value::Dict` for use in the interpreter env.
42    /// Functions become `Value::BuiltinFn`, submodules become nested dicts.
43    pub fn to_value(&self) -> Value {
44        let mut map = IndexMap::new();
45
46        for (name, (qualified, func)) in &self.functions {
47            map.insert(name.clone(), Value::BuiltinFn(qualified.clone(), *func));
48        }
49
50        for (name, value) in &self.values {
51            map.insert(name.clone(), value.clone());
52        }
53
54        for (name, sub) in &self.submodules {
55            map.insert(name.clone(), sub.to_value());
56        }
57
58        Value::Dict(map)
59    }
60
61    /// Get all exported names (for `use mod::*`).
62    pub fn names(&self) -> Vec<String> {
63        let mut names: Vec<String> = self.functions.keys().cloned().collect();
64        names.extend(self.values.keys().cloned());
65        names.extend(self.submodules.keys().cloned());
66        names
67    }
68}