Reputation: 84
I'm trying to retrieve tables from lua files in Rust. I'm registering a register_entity
function in the lua global context for data files to register their tables. When the lua file is executed and it calls the register_entity
function, the registered callback is called in Rust. The callback should add the passed table into a HashMap
to maintain a collection of all entities.
Here's an example lua file that is being read.
Goblin = {
glyph: "2"
}
register_entity("Goblin", Goblin)
Rust Code
fn load_lua_globals(&self) {
let entities = Arc::new(Mutex::new(HashMap::new()));
self.lua.context(|lua_ctx| {
let register_entity = {
let entities = Arc::clone(&entities);
let register_entity = lua_ctx.create_function(
move |_, (name, table): (String, Table)| {
entities.lock().unwrap().insert(name, table);
Ok(())
}).unwrap();
};
lua_ctx.globals().set("register_entity", register_entity).unwrap();
});
}
}
This is the error.
error[E0277]: `*mut rlua::ffi::lua_State` cannot be sent between threads safely
--> src/bin/main.rs:106:47
|
106 | let register_entity = lua_ctx.create_function(
| ^^^^^^^^^^^^^^^ `*mut rlua::ffi::lua_State` cannot be sent between threads safely
|
= help: within `(std::string::String, rlua::Table<'_>)`, the trait `std::marker::Send` is not implemented for `*mut rlua::ffi::lua_State`
= note: required because it appears within the type `rlua::Context<'_>`
= note: required because it appears within the type `rlua::types::LuaRef<'_>`
= note: required because it appears within the type `rlua::Table<'_>`
= note: required because it appears within the type `(std::string::String, rlua::Table<'_>)`
= note: required because of the requirements on the impl of `std::marker::Send` for `hashbrown::raw::RawTable<(std::string::String, rlua::Table<'_>)>`
= note: required because it appears within the type `hashbrown::map::HashMap<std::string::String, rlua::Table<'_>, std::collections::hash_map::RandomState>`
= note: required because it appears within the type `std::collections::HashMap<std::string::String, rlua::Table<'_>>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<std::collections::HashMap<std::string::String, rlua::Table<'_>>>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<std::collections::HashMap<std::string::String, rlua::Table<'_>>>>`
= note: required because it appears within the type `[closure@src/bin/main.rs:107:21: 112:18 entities:std::sync::Arc<std::sync::Mutex<std::collections::HashMap<std::string::String, rlua::Table<'_>>>>]
Upvotes: 1
Views: 783
Reputation: 1768
You cannot store reference to lua_ctx
outside the call to Lua::context
. The rlua::Table
you store in entities is bound to the lifetime of lua_ctx
.
rlua provides a way to store reference to Lua objects outside of context calls, with Context::create_registry_value
. It returns a Regsitry
key that you can safely store in your HashMap, and use it afterwards in another call to Lua::context
. Check the following code for an example :
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use rlua::{Lua, RegistryKey, Table};
const LUA_SOURCE: &str = r#"
Goblin = {
glyph = "2"
}
register_entity("Goblin", Goblin)
"#;
fn setup_register_entity(lua: &Lua) -> Arc<Mutex<HashMap<String, RegistryKey>>> {
let entities = Arc::new(Mutex::new(HashMap::new()));
lua.context(|lua_ctx| {
let entities = entities.clone();
let register_entity = lua_ctx.create_function(
move |ctx, (name, table): (String, Table)| {
// Store a refenrence to the object as a RegistryKey
let key = ctx.create_registry_value(table)
.expect("should have inserted in registry");
entities.lock().unwrap().insert(name, key);
Ok(())
})
.unwrap();
lua_ctx.globals().set("register_entity", register_entity).unwrap();
});
entities
}
fn main() {
let lua = Lua::new();
let entities = setup_register_entity(&lua);
lua.context(|lua_ctx| {
// Load lua code
lua_ctx.load(LUA_SOURCE)
.exec()
.expect("should load");
for (name, key) in entities.lock().unwrap().iter() {
// Retreive table
let table: Table = lua_ctx.registry_value(key).unwrap();
// Use it
let glyph: String = table.get("glyph").unwrap();
println!("{}.glyph = {}", name, glyph);
}
});
}
Upvotes: 2