1use std::path::Path;
2
3use mlua::{AnyUserData, FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Lua, Table, UserDataFields};
4
5mod macros;
6mod module;
7mod require;
8
9pub use module::{LuaModule, Module, ModuleBuilder, ModuleFields, ModuleMethods};
10pub use require::Require;
11
12use crate::MaybeSend;
13
14pub trait LuaExtras {
22 fn path(&self) -> mlua::Result<String>;
29
30 fn cpath(&self) -> mlua::Result<String>;
37
38 fn prepend_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
45
46 fn prepend_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>)
53 -> mlua::Result<()>;
54
55 fn append_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
62
63 fn append_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()>;
70
71 fn set_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
78
79 fn set_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()>;
86
87 fn prepend_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
94
95 fn prepend_cpaths<S: AsRef<Path>>(
102 &self,
103 paths: impl IntoIterator<Item = S>,
104 ) -> mlua::Result<()>;
105
106 fn append_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
113
114 fn append_cpaths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>)
121 -> mlua::Result<()>;
122
123 fn set_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
130
131 fn set_cpaths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()>;
138
139 fn set_global<'lua, K, V>(&'lua self, key: K, value: V) -> mlua::Result<()>
141 where
142 K: IntoLua<'lua>,
143 V: IntoLua<'lua>;
144
145 fn set_global_function<'lua, K, A, R, F>(&'lua self, key: K, value: F) -> mlua::Result<()>
146 where
147 K: IntoLua<'lua>,
148 A: FromLuaMulti<'lua>,
149 R: IntoLuaMulti<'lua>,
150 F: Fn(&'lua Lua, A) -> mlua::Result<R> + Send + 'static;
151
152 fn require<'lua, R: FromLua<'lua>>(&'lua self, path: impl AsRef<str>) -> mlua::Result<R>;
154}
155
156impl LuaExtras for Lua {
157 fn set_global<'lua, K, V>(&'lua self, key: K, value: V) -> mlua::Result<()>
158 where
159 K: IntoLua<'lua>,
160 V: IntoLua<'lua>,
161 {
162 self.globals().set(key, value)
163 }
164
165 fn set_global_function<'lua, K, A, R, F>(&'lua self, key: K, value: F) -> mlua::Result<()>
166 where
167 K: IntoLua<'lua>,
168 A: FromLuaMulti<'lua>,
169 R: IntoLuaMulti<'lua>,
170 F: Fn(&'lua Lua, A) -> mlua::Result<R> + Send + 'static,
171 {
172 self.globals().set(key, self.create_function(value)?)
173 }
174
175 fn path(&self) -> mlua::Result<String> {
176 self.globals()
177 .get::<_, Table>("package")?
178 .get::<_, String>("path")
179 }
180
181 fn cpath(&self) -> mlua::Result<String> {
182 self.globals()
183 .get::<_, Table>("package")?
184 .get::<_, String>("cpath")
185 }
186
187 fn set_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
188 self.globals()
189 .get::<_, Table>("package")
190 .unwrap()
191 .set("path", path.as_ref().display().to_string())
192 }
193
194 fn set_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()> {
195 self.globals().get::<_, Table>("package").unwrap().set(
196 "path",
197 paths
198 .into_iter()
199 .map(|s| s.as_ref().display().to_string())
200 .collect::<Vec<_>>()
201 .join(";"),
202 )
203 }
204
205 fn prepend_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
206 let lua_path = match self.path()?.trim() {
207 "" => path.as_ref().display().to_string(),
208 other => format!("{};{other}", path.as_ref().display()),
209 };
210 self.globals()
211 .get::<_, Table>("package")?
212 .set("path", lua_path)
213 }
214
215 fn prepend_paths<S: AsRef<Path>>(
216 &self,
217 paths: impl IntoIterator<Item = S>,
218 ) -> mlua::Result<()> {
219 let new = paths
220 .into_iter()
221 .map(|v| v.as_ref().display().to_string())
222 .collect::<Vec<_>>()
223 .join(";");
224 let lua_path = match self.path()?.trim() {
225 "" => new,
226 other => format!("{new};{other}"),
227 };
228 self.globals()
229 .get::<_, Table>("package")?
230 .set("path", lua_path)
231 }
232
233 fn append_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
234 let lua_path = match self.path()?.trim() {
235 "" => path.as_ref().display().to_string(),
236 other => format!("{other};{}", path.as_ref().display()),
237 };
238 self.globals()
239 .get::<_, Table>("package")?
240 .set("path", lua_path)
241 }
242
243 fn append_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()> {
244 let new = paths
245 .into_iter()
246 .map(|v| v.as_ref().display().to_string())
247 .collect::<Vec<_>>()
248 .join(";");
249 let lua_path = match self.path()?.trim() {
250 "" => new,
251 other => format!("{other};{new}"),
252 };
253 self.globals()
254 .get::<_, Table>("package")?
255 .set("path", lua_path)
256 }
257
258 fn set_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
259 self.globals()
260 .get::<_, Table>("package")
261 .unwrap()
262 .set("cpath", path.as_ref().display().to_string())
263 }
264
265 fn set_cpaths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()> {
266 self.globals().get::<_, Table>("package").unwrap().set(
267 "cpath",
268 paths
269 .into_iter()
270 .map(|s| s.as_ref().display().to_string())
271 .collect::<Vec<_>>()
272 .join(";"),
273 )
274 }
275
276 fn prepend_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
277 let lua_path = match self.path()?.trim() {
278 "" => path.as_ref().display().to_string(),
279 other => format!("{};{other}", path.as_ref().display()),
280 };
281 self.globals()
282 .get::<_, Table>("package")?
283 .set("cpath", lua_path)
284 }
285
286 fn prepend_cpaths<S: AsRef<Path>>(
287 &self,
288 paths: impl IntoIterator<Item = S>,
289 ) -> mlua::Result<()> {
290 let new = paths
291 .into_iter()
292 .map(|v| v.as_ref().display().to_string())
293 .collect::<Vec<_>>()
294 .join(";");
295 let lua_path = match self.path()?.trim() {
296 "" => new,
297 other => format!("{new};{other}"),
298 };
299 self.globals()
300 .get::<_, Table>("package")?
301 .set("cpath", lua_path)
302 }
303
304 fn append_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
305 let lua_path = match self.path()?.trim() {
306 "" => path.as_ref().display().to_string(),
307 other => format!("{other};{}", path.as_ref().display()),
308 };
309 self.globals()
310 .get::<_, Table>("package")?
311 .set("cpath", lua_path)
312 }
313
314 fn append_cpaths<S: AsRef<Path>>(
315 &self,
316 paths: impl IntoIterator<Item = S>,
317 ) -> mlua::Result<()> {
318 let new = paths
319 .into_iter()
320 .map(|v| v.as_ref().display().to_string())
321 .collect::<Vec<_>>()
322 .join(";");
323 let lua_path = match self.path()?.trim() {
324 "" => new,
325 other => format!("{other};{new}"),
326 };
327 self.globals()
328 .get::<_, Table>("package")?
329 .set("cpath", lua_path)
330 }
331
332 fn require<'lua, R: FromLua<'lua>>(&'lua self, path: impl AsRef<str>) -> mlua::Result<R> {
333 let segments = path
334 .as_ref()
335 .split('.')
336 .filter_map(|v| (!v.is_empty()).then_some(v.trim()))
337 .collect::<Vec<_>>();
338
339 let mut module = self.globals();
340 if !segments.is_empty() {
341 for seg in &segments[..segments.len() - 1] {
342 module = module.get::<_, Table>(*seg)?;
343 }
344 }
345
346 match segments.last() {
347 Some(seg) => module.get::<_, R>(*seg),
348 None => Err(mlua::Error::runtime(format!(
349 "module not found: {:?}",
350 path.as_ref()
351 ))),
352 }
353 }
354}
355
356pub trait UserDataGetSet<'lua, T> {
358 fn add_field_method_get_set<S, R, A, GET, SET>(&mut self, name: &S, get: GET, set: SET)
360 where
361 S: AsRef<str> + ?Sized,
362 R: IntoLua<'lua>,
363 A: FromLua<'lua>,
364 GET: 'static + MaybeSend + Fn(&'lua Lua, &T) -> mlua::Result<R>,
365 SET: 'static + MaybeSend + Fn(&'lua Lua, &mut T, A) -> mlua::Result<()>;
366
367 fn add_field_function_get_set<S, R, A, GET, SET>(&mut self, name: &S, get: GET, set: SET)
369 where
370 S: AsRef<str> + ?Sized,
371 R: IntoLua<'lua>,
372 A: FromLua<'lua>,
373 GET: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> mlua::Result<R>,
374 SET: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>, A) -> mlua::Result<()>;
375}
376
377impl<'lua, T, U: UserDataFields<'lua, T>> UserDataGetSet<'lua, T> for U {
378 fn add_field_method_get_set<S, R, A, GET, SET>(&mut self, name: &S, get: GET, set: SET)
379 where
380 S: AsRef<str> + ?Sized,
381 R: IntoLua<'lua>,
382 A: FromLua<'lua>,
383 GET: 'static + MaybeSend + Fn(&'lua Lua, &T) -> mlua::Result<R>,
384 SET: 'static + MaybeSend + Fn(&'lua Lua, &mut T, A) -> mlua::Result<()>,
385 {
386 self.add_field_method_get(name, get);
387 self.add_field_method_set(name, set);
388 }
389
390 fn add_field_function_get_set<S, R, A, GET, SET>(&mut self, name: &S, get: GET, set: SET)
391 where
392 S: AsRef<str> + ?Sized,
393 R: IntoLua<'lua>,
394 A: FromLua<'lua>,
395 GET: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> mlua::Result<R>,
396 SET: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>, A) -> mlua::Result<()>,
397 {
398 self.add_field_function_get(name, get);
399 self.add_field_function_set(name, set);
400 }
401}