1use indexmap::IndexMap;
2#[cfg(feature = "async-runtime")]
3use std::future::Future;
4
5#[cfg(feature = "async-runtime")]
6use crate::error::IonError;
7#[cfg(feature = "async-runtime")]
8use crate::value::AsyncBuiltinClosureFn;
9use crate::value::{BuiltinClosureFn, BuiltinFn, Value};
10
11enum ModuleFn {
12 Function(BuiltinFn),
13 Closure(BuiltinClosureFn),
14 #[cfg(feature = "async-runtime")]
15 AsyncClosure(AsyncBuiltinClosureFn),
16}
17
18pub struct Module {
21 pub name: String,
22 functions: IndexMap<String, (String, ModuleFn)>,
23 values: IndexMap<String, Value>,
24 submodules: IndexMap<String, Module>,
25}
26
27impl Module {
28 pub fn new(name: impl Into<String>) -> Self {
29 Self {
30 name: name.into(),
31 functions: IndexMap::new(),
32 values: IndexMap::new(),
33 submodules: IndexMap::new(),
34 }
35 }
36
37 pub fn register_fn(&mut self, name: &str, func: BuiltinFn) {
39 let qualified = format!("{}::{}", self.name, name);
40 self.functions
41 .insert(name.to_string(), (qualified, ModuleFn::Function(func)));
42 }
43
44 pub fn register_closure<F>(&mut self, name: &str, func: F)
46 where
47 F: Fn(&[Value]) -> Result<Value, String> + Send + Sync + 'static,
48 {
49 let qualified = format!("{}::{}", self.name, name);
50 self.functions.insert(
51 name.to_string(),
52 (qualified, ModuleFn::Closure(BuiltinClosureFn::new(func))),
53 );
54 }
55
56 #[cfg(feature = "async-runtime")]
61 pub fn register_async_fn<F, Fut>(&mut self, name: &str, func: F)
62 where
63 F: Fn(Vec<Value>) -> Fut + 'static,
64 Fut: Future<Output = Result<Value, IonError>> + 'static,
65 {
66 let qualified = format!("{}::{}", self.name, name);
67 self.functions.insert(
68 name.to_string(),
69 (
70 qualified,
71 ModuleFn::AsyncClosure(AsyncBuiltinClosureFn::new(func)),
72 ),
73 );
74 }
75
76 pub fn set(&mut self, name: &str, value: Value) {
78 self.values.insert(name.to_string(), value);
79 }
80
81 pub fn register_submodule(&mut self, sub: Module) {
83 self.submodules.insert(sub.name.clone(), sub);
84 }
85
86 pub fn to_value(&self) -> Value {
89 let mut map = IndexMap::new();
90
91 for (name, (qualified, func)) in &self.functions {
92 let value = match func {
93 ModuleFn::Function(func) => Value::BuiltinFn(qualified.clone(), *func),
94 ModuleFn::Closure(func) => Value::BuiltinClosure(qualified.clone(), func.clone()),
95 #[cfg(feature = "async-runtime")]
96 ModuleFn::AsyncClosure(func) => {
97 Value::AsyncBuiltinClosure(qualified.clone(), func.clone())
98 }
99 };
100 map.insert(name.clone(), value);
101 }
102
103 for (name, value) in &self.values {
104 map.insert(name.clone(), value.clone());
105 }
106
107 for (name, sub) in &self.submodules {
108 map.insert(name.clone(), sub.to_value());
109 }
110
111 Value::Dict(map)
112 }
113
114 pub fn names(&self) -> Vec<String> {
116 let mut names: Vec<String> = self.functions.keys().cloned().collect();
117 names.extend(self.values.keys().cloned());
118 names.extend(self.submodules.keys().cloned());
119 names
120 }
121}