make initial implementation

credit
- https://github.com/AlphaModder/include-lua
This commit is contained in:
Andy Weidenbaum 2021-02-04 12:16:07 +11:00
parent 187c5f55ea
commit 38c15af4dc
6 changed files with 130 additions and 15 deletions

View File

@ -11,20 +11,24 @@ and `require` the module.
## Synopsis ## Synopsis
```rust ```rust
use rlua_searcher::AddSearcher; use rlua::Lua;
use rlua_searcher::{AddSearcher, Result};
use std::collections::HashMap;
fn main() { fn main() {
let lume = read_lume_to_string(); let lume = read_lume_to_string();
let name = "lume"; let name = "lume".to_string();
let map = HashMap::new<String, String>(); let mut map = HashMap::new();
map.insert(name, lume); map.insert(name, lume);
let lua = Lua::new; let lua = Lua::new();
let hello = lua.context::<_, rlua::Result<_>>(|lua_ctx| { let hello = lua
.context::<_, Result<String>>(|lua_ctx| {
lua_ctx.add_searcher(map)?; lua_ctx.add_searcher(map)?;
Ok(lua_ctx.load(r#"require("lume")"#).eval()?) Ok(lua_ctx.load(r#"return require("lume")"#).eval()?)
}).unwrap(); })
.unwrap();
// prints "hello lume" // prints "hello lume"
println!("{}", hello); println!("{}", hello);

21
src/error.rs Normal file
View File

@ -0,0 +1,21 @@
#[derive(Debug)]
pub enum Error {
RLua(rlua::Error),
}
impl From<rlua::Error> for Error {
fn from(error: rlua::Error) -> Self {
Error::RLua(error)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let res = match self {
Error::RLua(e) => format!("rlua error:\n{:#?}", e),
};
write!(f, "{}", res)
}
}
impl std::error::Error for Error {}

View File

@ -1,7 +1,7 @@
#[cfg(test)] mod searcher;
mod tests { mod error;
#[test] mod types;
fn it_works() {
assert_eq!(2 + 2, 4); pub use crate::error::Error;
} pub use crate::searcher::AddSearcher;
} pub use crate::types::Result;

61
src/searcher.rs Normal file
View File

@ -0,0 +1,61 @@
use rlua::{Context, MetaMethod, RegistryKey, Table, UserData, UserDataMethods, Value};
use std::collections::HashMap;
use crate::types::Result;
/// Stores Lua modules indexed by module name, and provides an
/// `rlua::MetaMethod` to enable `require`ing the stored modules by name
/// in an `rlua::Context`.
struct Searcher {
/// A `HashMap` of Lua modules in `String` representation, indexed
/// by module name.
modules: HashMap<String, String>,
/// An `rlua::RegistryKey` whose value is the Lua environment within
/// which the user made the request to instantiate a `Searcher` for
/// `modules`.
globals: RegistryKey,
}
impl Searcher {
fn new(modules: HashMap<String, String>, globals: RegistryKey) -> Self {
Self { modules, globals }
}
}
impl UserData for Searcher {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Call, |lua_ctx, this, name: String| {
match this.modules.get(&name) {
Some(content) => Ok(Value::Function(
lua_ctx
.load(content)
.set_name(&name)?
.set_environment(lua_ctx.registry_value::<Table>(&this.globals)?)?
.into_function()?,
)),
None => Ok(Value::Nil),
}
});
}
}
/// Extend `rlua::Context` to support `require`ing Lua modules by name.
pub trait AddSearcher<'a> {
/// Add a `HashMap` of Lua modules indexed by module name to Luas
/// `package.searchers` table in an `rlua::Context`, with lookup
/// functionality provided by the `rlua_searcher::Searcher` struct.
fn add_searcher(&self, modules: HashMap<String, String>) -> Result<()>;
}
impl<'a> AddSearcher<'a> for Context<'a> {
fn add_searcher(&self, modules: HashMap<String, String>) -> Result<()> {
let globals = self.globals();
let searchers: Table = globals.get::<_, Table>("package")?.get("searchers")?;
let registry_key = self.create_registry_value(globals)?;
let searcher = Searcher::new(modules, registry_key);
searchers
.set(searchers.len()? + 1, searcher)
.map_err(|e| e.into())
}
}

3
src/types.rs Normal file
View File

@ -0,0 +1,3 @@
use crate::error::Error;
pub type Result<A> = std::result::Result<A, Error>;

26
tests/tests.rs Normal file
View File

@ -0,0 +1,26 @@
use rlua::Lua;
use rlua_searcher::{AddSearcher, Result};
use std::collections::HashMap;
#[test]
fn it_works() {
let lume = read_lume_to_string();
let name = "lume".to_string();
let mut map = HashMap::new();
map.insert(name, lume);
let lua = Lua::new();
let hello = lua
.context::<_, Result<String>>(|lua_ctx| {
lua_ctx.add_searcher(map)?;
Ok(lua_ctx.load(r#"return require("lume")"#).eval()?)
})
.unwrap();
assert_eq!("hello lume", hello);
}
fn read_lume_to_string() -> String {
r#"return "hello lume""#.to_string()
}