1use std::collections::HashMap;
4
5use crate::prelude::*;
6
7#[cfg(feature = "async")]
8#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
9use std::future::Future;
10
11#[derive(Debug)]
46pub struct ModuleBuilder<'a> {
47 fields: HashMap<String, LuaValue<'a>>,
48 lua: &'a Lua,
49}
50
51impl<'a> ModuleBuilder<'a> {
52 pub fn new(lua: &'a Lua) -> Self {
54 Self {
55 fields: HashMap::new(),
56 lua,
57 }
58 }
59
60 fn check_collision(&self, name: &str) -> LuaResult<()> {
61 if self.fields.contains_key(name) {
62 Err(LuaError::RuntimeError(format!(
63 "Module already contains a field named {}",
64 name
65 )))
66 } else {
67 Ok(())
68 }
69 }
70
71 pub fn fields(&'a self) -> impl Iterator<Item = (&String, &LuaValue)> {
73 self.fields.iter()
74 }
75
76 pub fn fields_mut(&'a mut self) -> impl Iterator<Item = (&String, &mut LuaValue)> {
78 self.fields.iter_mut()
79 }
80
81 pub fn add_fn<A, R, F>(&mut self, name: &str, func: F) -> LuaResult<&mut Self>
83 where
84 F: 'static + Send + Fn(&'a Lua, A) -> LuaResult<R>,
85 A: FromLuaMulti<'a>,
86 R: ToLuaMulti<'a>,
87 {
88 self.check_collision(name)?;
89 let func = self.lua.create_function(func)?;
90 self.fields.insert(name.to_owned(), self.lua.pack(func)?);
91 Ok(self)
92 }
93
94 #[cfg(feature = "async")]
95 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
96 pub fn add_fn_async<A, R, F, FR>(&mut self, name: &str, func: F) -> LuaResult<&mut Self>
98 where
99 F: 'static + Send + Fn(&'a Lua, A) -> FR,
100 A: FromLuaMulti<'a>,
101 R: ToLuaMulti<'a>,
102 FR: 'a + Send + Future<Output = LuaResult<R>>,
103 {
104 self.check_collision(name)?;
105 let func = self.lua.create_async_function(func)?;
106 self.fields.insert(name.to_owned(), self.lua.pack(func)?);
107 Ok(self)
108 }
109
110 pub fn add_c_fn(&mut self, name: &str, func: mlua::lua_CFunction) -> LuaResult<&mut Self> {
112 self.check_collision(name)?;
113 unsafe {
114 let func = self.lua.create_c_function(func)?;
115 self.fields.insert(name.to_owned(), self.lua.pack(func)?);
116 }
117 Ok(self)
118 }
119
120 pub fn add_table(&mut self, name: &str, table: LuaTable<'a>) -> LuaResult<&mut Self> {
122 self.check_collision(name)?;
123 self.fields.insert(name.to_owned(), self.lua.pack(table)?);
124 Ok(self)
125 }
126
127 pub fn add_table_from<K, V, I>(&mut self, name: &str, iterator: I) -> LuaResult<&mut Self>
129 where
130 K: ToLua<'a>,
131 V: ToLua<'a>,
132 I: IntoIterator<Item = (K, V)>,
133 {
134 self.check_collision(name)?;
135 self.fields.insert(
136 name.to_owned(),
137 self.lua.pack(self.lua.create_table_from(iterator)?)?,
138 );
139 Ok(self)
140 }
141
142 pub fn add_table_empty(&mut self, name: &str) -> LuaResult<&mut Self> {
144 self.check_collision(name)?;
145 let table = self.lua.create_table()?;
146 self.fields.insert(name.to_owned(), self.lua.pack(table)?);
147 Ok(self)
148 }
149
150 pub fn add_value(&mut self, name: &str, value: impl ToLua<'a>) -> LuaResult<&mut Self> {
152 self.check_collision(name)?;
153 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
154 Ok(self)
155 }
156
157 pub fn add_string(&mut self, name: &str, value: &str) -> LuaResult<&mut Self> {
159 self.check_collision(name)?;
160 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
161 Ok(self)
162 }
163
164 pub fn add_int(&mut self, name: &str, value: i64) -> LuaResult<&mut Self> {
166 self.check_collision(name)?;
167 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
168 Ok(self)
169 }
170
171 pub fn add_float(&mut self, name: &str, value: f64) -> LuaResult<&mut Self> {
173 self.check_collision(name)?;
174 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
175 Ok(self)
176 }
177
178 pub fn add_bool(&mut self, name: &str, value: bool) -> LuaResult<&mut Self> {
180 self.check_collision(name)?;
181 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
182 Ok(self)
183 }
184
185 pub fn with_fn<A, R, F>(mut self, name: &str, func: F) -> LuaResult<Self>
187 where
188 F: 'static + Send + Fn(&'a Lua, A) -> LuaResult<R>,
189 A: FromLuaMulti<'a>,
190 R: ToLuaMulti<'a>,
191 {
192 self.check_collision(name)?;
193 let func = self.lua.create_function(func)?;
194 self.fields.insert(name.to_owned(), self.lua.pack(func)?);
195 Ok(self)
196 }
197
198 #[cfg(feature = "async")]
199 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
200 pub fn with_fn_async<A, R, F, FR>(mut self, name: &str, func: F) -> LuaResult<Self>
202 where
203 F: 'static + Send + Fn(&'a Lua, A) -> FR,
204 A: FromLuaMulti<'a>,
205 R: ToLuaMulti<'a>,
206 FR: 'a + Send + Future<Output = LuaResult<R>>,
207 {
208 self.check_collision(name)?;
209 let func = self.lua.create_async_function(func)?;
210 self.fields.insert(name.to_owned(), self.lua.pack(func)?);
211 Ok(self)
212 }
213
214 pub fn with_c_fn(mut self, name: &str, func: mlua::lua_CFunction) -> LuaResult<Self> {
216 self.check_collision(name)?;
217 unsafe {
218 let func = self.lua.create_c_function(func)?;
219 self.fields.insert(name.to_owned(), self.lua.pack(func)?);
220 }
221 Ok(self)
222 }
223
224 pub fn with_table(mut self, name: &str, table: LuaTable<'a>) -> LuaResult<Self> {
226 self.check_collision(name)?;
227 self.fields.insert(name.to_owned(), self.lua.pack(table)?);
228 Ok(self)
229 }
230
231 pub fn with_table_from<K, V, I>(mut self, name: &str, iterator: I) -> LuaResult<Self>
233 where
234 K: ToLua<'a>,
235 V: ToLua<'a>,
236 I: IntoIterator<Item = (K, V)>,
237 {
238 self.check_collision(name)?;
239 self.fields.insert(
240 name.to_owned(),
241 self.lua.pack(self.lua.create_table_from(iterator)?)?,
242 );
243 Ok(self)
244 }
245
246 pub fn with_table_empty(mut self, name: &str) -> LuaResult<Self> {
248 self.check_collision(name)?;
249 let table = self.lua.create_table()?;
250 self.fields.insert(name.to_owned(), self.lua.pack(table)?);
251 Ok(self)
252 }
253
254 pub fn with_value(mut self, name: &str, value: impl ToLua<'a>) -> LuaResult<Self> {
256 self.check_collision(name)?;
257 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
258 Ok(self)
259 }
260
261 pub fn with_string(mut self, name: &str, value: &str) -> LuaResult<Self> {
263 self.check_collision(name)?;
264 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
265 Ok(self)
266 }
267
268 pub fn with_int(mut self, name: &str, value: i64) -> LuaResult<Self> {
270 self.check_collision(name)?;
271 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
272 Ok(self)
273 }
274
275 pub fn with_float(mut self, name: &str, value: f64) -> LuaResult<Self> {
277 self.check_collision(name)?;
278 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
279 Ok(self)
280 }
281
282 pub fn with_bool(&mut self, name: &str, value: bool) -> LuaResult<&mut Self> {
284 self.check_collision(name)?;
285 self.fields.insert(name.to_owned(), value.to_lua(self.lua)?);
286 Ok(self)
287 }
288
289 pub fn build(self) -> LuaResult<LuaTable<'a>> {
291 let module = self.lua.create_table()?;
292 for (name, value) in self.fields {
293 module.set(name, value)?;
294 }
295 Ok(module)
296 }
297}
298
299impl<'a> ToLua<'a> for ModuleBuilder<'a> {
300 fn to_lua(self, lua: &'a Lua) -> LuaResult<LuaValue<'a>> {
301 Ok(lua.pack(self.build()?)?)
302 }
303}