1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use mlua::{Error, FromLua, Table};

/// Adds a similar syntax to tables as lua's `require` function.
///
/// # Example
///
/// ```
/// use mlua_extras::{
///     mlua::{Lua, Function},
///     extras::Require,
/// };
///
/// let lua = Lua::new();
///
/// let unpack = lua.require::<Function>("table.unpack")?;
/// ```
///
/// Would be the same as
///
/// ```lua
/// local unpack = require("table").unpack
/// ```
pub trait Require<'lua> {
    /// Fetch a nested lua value from the table
    fn require<R: FromLua<'lua>>(&'lua self, path: impl AsRef<str>) -> mlua::Result<R>;
}

impl<'lua> Require<'lua> for Table<'lua> {
    fn require<R: FromLua<'lua>>(&'lua self, path: impl AsRef<str>) -> mlua::Result<R> {
        let segments = path
            .as_ref()
            .split('.')
            .filter_map(|v| (!v.trim().is_empty()).then_some(v.trim()))
            .collect::<Vec<_>>();

        let mut module = self.clone();
        if !segments.is_empty() {
            for seg in &segments[..segments.len() - 1] {
                module = module.get::<_, Table>(*seg)?;
            }
        }

        match segments.last() {
            Some(seg) => module.get::<_, R>(*seg),
            None => Err(Error::runtime(format!(
                "module not found: {:?}",
                path.as_ref()
            ))),
        }
    }
}