neige_lua/api/
get.rs

1use neige_infra::{LuaType, LUA_RIDX_GLOBALS};
2
3use crate::{api::CallApi, state::LuaState, value::value::LuaValue};
4
5pub trait GetApi {
6    fn new_table(&mut self);
7    fn create_table(&mut self, n_arr: usize, n_rec: usize);
8    fn get_table(&mut self, idx: isize) -> LuaType;
9    fn get_field(&mut self, idx: isize, key: String) -> LuaType;
10    fn get_i(&mut self, idx: isize, i: i64) -> LuaType;
11    fn get_meta_table(&mut self, idx: isize) -> bool;
12    fn raw_get(&mut self, idx: isize) -> LuaType;
13    fn raw_get_i(&mut self, idx: isize, i: i64) -> LuaType;
14    fn get_global(&mut self, name: String) -> LuaType;
15}
16
17impl GetApi for LuaState {
18    fn new_table(&mut self) {
19        self.create_table(0, 0)
20    }
21
22    fn create_table(&mut self, n_arr: usize, n_rec: usize) {
23        let tb = LuaValue::new_table(n_arr, n_rec);
24        self.stack_push(tb);
25    }
26
27    fn get_table(&mut self, idx: isize) -> LuaType {
28        let t = self.stack_get(idx);
29        let k = self.stack_pop();
30        self.inline_get_table(t, k, false)
31    }
32
33    fn get_field(&mut self, idx: isize, key: String) -> LuaType {
34        let t = self.stack_get(idx);
35        self.inline_get_table(t, LuaValue::Str(key), false)
36    }
37
38    fn get_i(&mut self, idx: isize, i: i64) -> LuaType {
39        let t = self.stack_get(idx);
40        self.inline_get_table(t, LuaValue::Integer(i), false)
41    }
42
43    fn get_meta_table(&mut self, idx: isize) -> bool {
44        let val = self.stack_get(idx);
45        if let Some(mt) = self.inline_get_meta_table(&val) {
46            self.stack_push(LuaValue::Table(mt));
47            true
48        } else {
49            false
50        }
51    }
52
53    fn raw_get(&mut self, idx: isize) -> LuaType {
54        let t = self.stack_get(idx);
55        let k = self.stack_pop();
56        self.inline_get_table(t, k, true)
57    }
58
59    fn raw_get_i(&mut self, idx: isize, i: i64) -> LuaType {
60        let t = self.stack_get(idx);
61        self.inline_get_table(t, LuaValue::Integer(i), true)
62    }
63
64    fn get_global(&mut self, name: String) -> LuaType {
65        let t = self.registry_get(&LuaValue::Integer(LUA_RIDX_GLOBALS));
66        self.inline_get_table(t, LuaValue::Str(name), true)
67    }
68}
69
70impl LuaState {
71    fn inline_get_table(&mut self, t: LuaValue, k: LuaValue, raw: bool) -> LuaType {
72        if let LuaValue::Table(tbl) = &t {
73            let v = tbl.get(&k);
74            let v_type = v.type_of();
75            if raw || !v.is_nil() || !tbl.has_meta_field("__index") {
76                self.stack_push(v);
77                return v_type;
78            }
79        }
80
81        if !raw {
82            let mf = self.inline_get_meta_field(&t, "__index");
83            match mf {
84                LuaValue::Table(_) => {
85                    return self.inline_get_table(mf, k, false);
86                }
87                LuaValue::Function(_) => {
88                    self.stack_push(mf);
89                    self.stack_push(t);
90                    self.stack_push(k);
91                    self.call(2, 1);
92                    return self.stack_get(-1).type_of();
93                }
94                _ => {}
95            }
96        }
97
98        panic!("not a lua table!")
99    }
100}