Skip to main content

sim_lib_lang_lua/
metatable.rs

1use sim_kernel::{Args, Cx, Result, Symbol, Value};
2use sim_lib_dispatch::{MetaObjectProtocol, meta_index};
3
4use crate::table::{lua_rawget, lua_table_value};
5
6/// Stable Lua metatable slot for indexed reads.
7pub fn lua_index_slot() -> Symbol {
8    Symbol::new("__index")
9}
10
11/// Performs Lua indexed read with the shared metaobject protocol.
12pub fn lua_get(cx: &mut Cx, receiver: &Value, key: &Value) -> Result<Option<Value>> {
13    meta_index(cx, &LuaMetaProtocol, receiver, key, &lua_index_slot())
14}
15
16/// Reads a raw metamethod from a value's metatable.
17pub fn lua_metamethod(cx: &mut Cx, value: &Value, slot: &Symbol) -> Result<Option<Value>> {
18    let table = match lua_table_value(value) {
19        Ok(table) => table,
20        Err(_) => return Ok(None),
21    };
22    let Some(metatable) = table.metatable()? else {
23        return Ok(None);
24    };
25    let slot = cx.factory().string(slot.name.to_string())?;
26    lua_rawget(cx, &metatable, &slot)
27}
28
29struct LuaMetaProtocol;
30
31impl MetaObjectProtocol for LuaMetaProtocol {
32    fn raw_get(&self, cx: &mut Cx, value: &Value, key: &Value) -> Result<Option<Value>> {
33        let Ok(table) = lua_table_value(value) else {
34            return Ok(None);
35        };
36        table.raw_get(cx, key)
37    }
38
39    fn get_meta(&self, cx: &mut Cx, value: &Value, slot: &Symbol) -> Result<Option<Value>> {
40        lua_metamethod(cx, value, slot)
41    }
42
43    fn apply_meta(
44        &self,
45        cx: &mut Cx,
46        receiver: &Value,
47        key: &Value,
48        index_slot: &Symbol,
49        meta_value: &Value,
50    ) -> Result<Option<Value>> {
51        if lua_table_value(meta_value).is_ok() {
52            return meta_index(cx, self, meta_value, key, index_slot);
53        }
54        cx.call_value(
55            meta_value.clone(),
56            Args::new(vec![receiver.clone(), key.clone()]),
57        )
58        .map(Some)
59    }
60}