Skip to main content

mlua_extras/extras/
mod.rs

1use std::path::Path;
2
3use mlua::{AnyUserData, FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Lua, Table, UserDataFields};
4
5mod module;
6
7pub use module::{LuaModule, Module, ModuleBuilder, ModuleFields, ModuleMethods, ExtendModule};
8
9use crate::MaybeSend;
10
11/// Adds quality of life helper methods to the [`Lua`] type
12///
13/// Helpers:
14/// - [`path`](https://www.lua.org/manual/5.1/manual.html#pdf-package.path) and [`cpath`](https://www.lua.org/manual/5.1/manual.html#pdf-package.cpath) manipulation
15/// - Shorthand for `lua.globals().set` that include adding any value and adding rust functions
16///     skipping [`create_function`][mlua::Lua::create_function]
17pub trait LuaExtras {
18    /// Get the `package.path` value
19    ///
20    /// This is the value used by the lua engine to resolve `require` calls on `lua` files.
21    /// see:
22    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.path>
23    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
24    fn path(&self) -> mlua::Result<String>;
25
26    /// Get the `package.cpath` value
27    ///
28    /// This is the value used by the lua engine to resolve `require` calls on `lib` files.
29    /// see:
30    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.cpath>
31    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
32    fn cpath(&self) -> mlua::Result<String>;
33
34    /// Prepend a path tothe `package.path` value
35    ///
36    /// This is the value used by the lua engine to resolve `require` calls.
37    /// see:
38    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.path>
39    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
40    fn prepend_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
41
42    /// Prepend paths to the `package.path` value
43    ///
44    /// This is the value used by the lua engine to resolve `require` calls.
45    /// see:
46    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.path>
47    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
48    fn prepend_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>)
49        -> mlua::Result<()>;
50
51    /// Append a path tothe `package.path` value
52    ///
53    /// This is the value used by the lua engine to resolve `require` calls.
54    /// see:
55    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.path>
56    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
57    fn append_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
58
59    /// Append paths to the `package.path` value
60    ///
61    /// This is the value used by the lua engine to resolve `require` calls.
62    /// see:
63    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.path>
64    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
65    fn append_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()>;
66
67    /// Set the `package.path` value
68    ///
69    /// This is the value used by the lua engine to resolve `require` calls.
70    /// see:
71    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.path>
72    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
73    fn set_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
74
75    /// Set the `package.path` values
76    ///
77    /// This is the value used by the lua engine to resolve `require` calls.
78    /// see:
79    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.path>
80    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
81    fn set_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()>;
82
83    /// Prepend a path tothe `package.cpath` value
84    ///
85    /// This is the value used by the lua engine to resolve `require` calls.
86    /// see:
87    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.cpath>
88    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
89    fn prepend_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
90
91    /// Prepend paths to the `package.cpath` value
92    ///
93    /// This is the value used by the lua engine to resolve `require` calls.
94    /// see:
95    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.cpath>
96    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
97    fn prepend_cpaths<S: AsRef<Path>>(
98        &self,
99        paths: impl IntoIterator<Item = S>,
100    ) -> mlua::Result<()>;
101
102    /// Append a path to the `package.cpath` value
103    ///
104    /// This is the value used by the lua engine to resolve `require` calls.
105    /// see:
106    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.cpath>
107    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
108    fn append_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
109
110    /// Append paths to the `package.cpath` value
111    ///
112    /// This is the value used by the lua engine to resolve `require` calls.
113    /// see:
114    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.cpath>
115    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
116    fn append_cpaths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>)
117        -> mlua::Result<()>;
118
119    /// Set the `package.cpath` value
120    ///
121    /// This is the value used by the lua engine to resolve `require` calls.
122    /// see:
123    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.cpath>
124    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
125    fn set_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()>;
126
127    /// Set the `package.cpath` values
128    ///
129    /// This is the value used by the lua engine to resolve `require` calls.
130    /// see:
131    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.cpath>
132    ///   - <https://www.lua.org/manual/5.4/manual.html#pdf-package.searchpath>
133    fn set_cpaths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()>;
134
135    /// Set a global variable
136    fn set_global<K, V>(&self, key: K, value: V) -> mlua::Result<()>
137    where
138        K: IntoLua,
139        V: IntoLua;
140
141    fn set_global_function<K, A, R, F>(&self, key: K, value: F) -> mlua::Result<()>
142    where
143        K: IntoLua,
144        A: FromLuaMulti,
145        R: IntoLuaMulti,
146        F: Fn(&Lua, A) -> mlua::Result<R> + Send + 'static;
147}
148
149impl LuaExtras for Lua {
150    fn set_global<K, V>(&self, key: K, value: V) -> mlua::Result<()>
151    where
152        K: IntoLua,
153        V: IntoLua,
154    {
155        self.globals().set(key, value)
156    }
157
158    fn set_global_function<K, A, R, F>(&self, key: K, value: F) -> mlua::Result<()>
159    where
160        K: IntoLua,
161        A: FromLuaMulti,
162        R: IntoLuaMulti,
163        F: Fn(&Lua, A) -> mlua::Result<R> + Send + 'static,
164    {
165        self.globals().set(key, self.create_function(value)?)
166    }
167
168    fn path(&self) -> mlua::Result<String> {
169        self.globals()
170            .get::<Table>("package")?
171            .get::<String>("path")
172    }
173
174    fn cpath(&self) -> mlua::Result<String> {
175        self.globals()
176            .get::<Table>("package")?
177            .get::<String>("cpath")
178    }
179
180    fn set_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
181        self.globals()
182            .get::<Table>("package")
183            .unwrap()
184            .set("path", path.as_ref().display().to_string())
185    }
186
187    fn set_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()> {
188        self.globals().get::<Table>("package").unwrap().set(
189            "path",
190            paths
191                .into_iter()
192                .map(|s| s.as_ref().display().to_string())
193                .collect::<Vec<_>>()
194                .join(";"),
195        )
196    }
197
198    fn prepend_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
199        let lua_path = match self.path()?.trim() {
200            "" => path.as_ref().display().to_string(),
201            other => format!("{};{other}", path.as_ref().display()),
202        };
203        self.globals()
204            .get::<Table>("package")?
205            .set("path", lua_path)
206    }
207
208    fn prepend_paths<S: AsRef<Path>>(
209        &self,
210        paths: impl IntoIterator<Item = S>,
211    ) -> mlua::Result<()> {
212        let new = paths
213            .into_iter()
214            .map(|v| v.as_ref().display().to_string())
215            .collect::<Vec<_>>()
216            .join(";");
217        let lua_path = match self.path()?.trim() {
218            "" => new,
219            other => format!("{new};{other}"),
220        };
221        self.globals()
222            .get::<Table>("package")?
223            .set("path", lua_path)
224    }
225
226    fn append_path<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
227        let lua_path = match self.path()?.trim() {
228            "" => path.as_ref().display().to_string(),
229            other => format!("{other};{}", path.as_ref().display()),
230        };
231        self.globals()
232            .get::<Table>("package")?
233            .set("path", lua_path)
234    }
235
236    fn append_paths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()> {
237        let new = paths
238            .into_iter()
239            .map(|v| v.as_ref().display().to_string())
240            .collect::<Vec<_>>()
241            .join(";");
242        let lua_path = match self.path()?.trim() {
243            "" => new,
244            other => format!("{other};{new}"),
245        };
246        self.globals()
247            .get::<Table>("package")?
248            .set("path", lua_path)
249    }
250
251    fn set_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
252        self.globals()
253            .get::<Table>("package")
254            .unwrap()
255            .set("cpath", path.as_ref().display().to_string())
256    }
257
258    fn set_cpaths<S: AsRef<Path>>(&self, paths: impl IntoIterator<Item = S>) -> mlua::Result<()> {
259        self.globals().get::<Table>("package").unwrap().set(
260            "cpath",
261            paths
262                .into_iter()
263                .map(|s| s.as_ref().display().to_string())
264                .collect::<Vec<_>>()
265                .join(";"),
266        )
267    }
268
269    fn prepend_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
270        let lua_path = match self.path()?.trim() {
271            "" => path.as_ref().display().to_string(),
272            other => format!("{};{other}", path.as_ref().display()),
273        };
274        self.globals()
275            .get::<Table>("package")?
276            .set("cpath", lua_path)
277    }
278
279    fn prepend_cpaths<S: AsRef<Path>>(
280        &self,
281        paths: impl IntoIterator<Item = S>,
282    ) -> mlua::Result<()> {
283        let new = paths
284            .into_iter()
285            .map(|v| v.as_ref().display().to_string())
286            .collect::<Vec<_>>()
287            .join(";");
288        let lua_path = match self.path()?.trim() {
289            "" => new,
290            other => format!("{new};{other}"),
291        };
292        self.globals()
293            .get::<Table>("package")?
294            .set("cpath", lua_path)
295    }
296
297    fn append_cpath<S: AsRef<Path>>(&self, path: S) -> mlua::Result<()> {
298        let lua_path = match self.cpath()?.trim() {
299            "" => path.as_ref().display().to_string(),
300            other => format!("{other};{}", path.as_ref().display()),
301        };
302        self.globals()
303            .get::<Table>("package")?
304            .set("cpath", lua_path)
305    }
306
307    fn append_cpaths<S: AsRef<Path>>(
308        &self,
309        paths: impl IntoIterator<Item = S>,
310    ) -> mlua::Result<()> {
311        let new = paths
312            .into_iter()
313            .map(|v| v.as_ref().display().to_string())
314            .collect::<Vec<_>>()
315            .join(";");
316        let lua_path = match self.path()?.trim() {
317            "" => new,
318            other => format!("{other};{new}"),
319        };
320        self.globals()
321            .get::<Table>("package")?
322            .set("cpath", lua_path)
323    }
324}
325
326/// Helper that combines some of the assignments of fields for UserData
327pub trait UserDataGetSet<T> {
328    /// Combination of [add_field_method_get](mlua::UserDataFields::add_field_method_get) and [add_field_method_set](mlua::UserDataFields::add_field_method_set)
329    fn add_field_method_get_set<S, R, A, GET, SET>(&mut self, name: S, get: GET, set: SET)
330    where
331        S: Into<String>,
332        R: IntoLua,
333        A: FromLua,
334        GET: 'static + MaybeSend + Fn(&Lua, &T) -> mlua::Result<R>,
335        SET: 'static + MaybeSend + Fn(&Lua, &mut T, A) -> mlua::Result<()>;
336
337    /// Typed version of [add_field_function_get](mlua::UserDataFields::add_field_function_get) and [add_field_function_set](mlua::UserDataFields::add_field_function_set) combined
338    fn add_field_function_get_set<S, R, A, GET, SET>(&mut self, name: S, get: GET, set: SET)
339    where
340        S: Into<String>,
341        R: IntoLua,
342        A: FromLua,
343        GET: 'static + MaybeSend + Fn(&Lua, AnyUserData) -> mlua::Result<R>,
344        SET: 'static + MaybeSend + Fn(&Lua, AnyUserData, A) -> mlua::Result<()>;
345}
346
347impl<T, U: UserDataFields<T>> UserDataGetSet<T> for U {
348    fn add_field_method_get_set<S, R, A, GET, SET>(&mut self, name: S, get: GET, set: SET)
349    where
350        S: Into<String>,
351        R: IntoLua,
352        A: FromLua,
353        GET: Fn(&Lua, &T) -> mlua::Result<R> + MaybeSend + 'static,
354        SET: Fn(&Lua, &mut T, A) -> mlua::Result<()> + MaybeSend + 'static,
355    {
356        let name: String = name.into();
357        self.add_field_method_get(&name, get);
358        self.add_field_method_set(name, set);
359    }
360
361    fn add_field_function_get_set<S, R, A, GET, SET>(&mut self, name: S, get: GET, set: SET)
362    where
363        S: Into<String>,
364        R: IntoLua,
365        A: FromLua,
366        GET: Fn(&Lua, AnyUserData) -> mlua::Result<R> + MaybeSend + 'static,
367        SET: Fn(&Lua, AnyUserData, A) -> mlua::Result<()> + MaybeSend + 'static,
368    {
369        let name: String = name.into();
370        self.add_field_function_get(&name, get);
371        self.add_field_function_set(name, set);
372    }
373}