首页 > 解决方案 > 如何从 Rust 的上下文中检索 lua 表?

问题描述

我正在尝试从 Rust 中的 lua 文件中检索表。我正在register_entitylua 全局上下文中注册一个函数,以便数据文件注册它们的表。当 lua 文件被执行并调用该register_entity函数时,注册的回调在 Rust 中被调用。回调应将传递的表添加到 aHashMap中以维护所有实体的集合。

这是一个正在读取的示例 lua 文件。

Goblin = {
  glyph: "2"
}

register_entity("Goblin", Goblin)

锈代码

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();
        });
    }
}

这是错误。

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<'_>>>>]

标签: luarust

解决方案


您不能lua_ctx在调用之外存储对 的引用Lua::contextrlua::Table您存储在实体中的内容与lua_ctx.

rlua 提供了一种在上下文调用之外存储对 Lua 对象的引用的方法,使用Context::create_registry_value. 它返回一个Regsitry键,您可以安全地存储在 HashMap 中,然后在另一个调用中使用它Lua::context。检查以下代码以获取示例:

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);
        }
    });
}

推荐阅读