1mod any;
16mod func;
17
18use std::cell::Cell;
19use std::marker::PhantomData;
20
21use lua_stdlib::auxlib::load_buffer;
22use lua_stdlib::init::open_libs;
23use lua_types::closure::LuaLClosure;
24use lua_types::gc::GcRef;
25use lua_types::upval::UpVal;
26use lua_types::value::LuaValue;
27use lua_vm::api;
28use lua_vm::state::{new_state, LuaState};
29
30pub use any::{AnyHashableLuaValue, AnyLuaString, AnyLuaValue};
31pub use func::{
32 function0, function1, function2, function3, function4, function5, function6, FnHandle,
33 LuaFunction, StringInLua,
34};
35
36use func::{registry_remove, Adapter, FromLuaGlobal, SetValue};
37
38#[derive(Debug, Clone)]
43pub struct LuaError {
44 message: String,
45}
46
47impl LuaError {
48 pub(crate) fn from_vm(err: lua_types::LuaError) -> Self {
49 LuaError {
50 message: format!("{err}"),
51 }
52 }
53}
54
55impl std::fmt::Display for LuaError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.write_str(&self.message)
58 }
59}
60
61impl std::error::Error for LuaError {}
62
63pub struct Lua<'lua> {
68 state: LuaState,
69 owned_closures: Vec<usize>,
70 _marker: PhantomData<&'lua ()>,
71}
72
73impl Default for Lua<'_> {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79impl<'lua> Lua<'lua> {
80 pub fn new() -> Lua<'lua> {
84 let mut state = new_state().expect("lua-rs state allocation failed");
85 state.global_mut().parser_hook = Some(parser_hook);
86 open_libs(&mut state).expect("opening lua-rs standard libraries failed");
87 Lua {
88 state,
89 owned_closures: Vec::new(),
90 _marker: PhantomData,
91 }
92 }
93
94 pub fn open_string(&mut self) {}
97
98 pub fn execute<T: FromExec>(&mut self, code: &str) -> Result<T, LuaError> {
100 let status = load_buffer(&mut self.state, code.as_bytes(), b"=(load)")
101 .map_err(LuaError::from_vm)?;
102 if status != 0 {
103 let err = self.state.pop();
104 return Err(LuaError::from_vm(lua_types::LuaError::from_value(err)));
105 }
106 api::pcall_k(&mut self.state, 0, 0, 0, 0, None).map_err(LuaError::from_vm)?;
107 T::from_exec(self)
108 }
109
110 pub fn set<V: SetValue>(&mut self, name: &str, value: V) {
112 value.set_into(self, name);
113 }
114
115 pub fn get<'l, V>(&'l mut self, name: &str) -> Option<V>
118 where
119 V: FromLuaGlobal<'l>,
120 {
121 V::from_lua_global(self, name)
122 }
123
124 pub(crate) fn state_mut(&mut self) -> &mut LuaState {
125 &mut self.state
126 }
127
128 pub(crate) fn install_closure(&mut self, name: &str, adapter: Adapter) {
131 let index = func::registry_insert(adapter);
132 self.owned_closures.push(index);
133 let state = &mut self.state;
134 api::push_integer(state, index as i64);
135 api::push_cclosure(state, func::trampoline, 1).expect("push_cclosure failed");
136 api::set_global(state, name.as_bytes()).expect("set_global failed");
137 }
138}
139
140impl Drop for Lua<'_> {
141 fn drop(&mut self) {
142 for &index in &self.owned_closures {
143 registry_remove(index);
144 }
145 }
146}
147
148pub trait FromExec: Sized {
151 fn from_exec(lua: &mut Lua<'_>) -> Result<Self, LuaError>;
152}
153
154impl FromExec for () {
155 fn from_exec(_lua: &mut Lua<'_>) -> Result<Self, LuaError> {
156 Ok(())
157 }
158}
159
160fn parser_hook(
164 state: &mut LuaState,
165 source: &[u8],
166 name: &[u8],
167 firstchar: i32,
168) -> Result<GcRef<LuaLClosure>, lua_types::LuaError> {
169 let proto = lua_parse::parse(state, lua_parse::DynData::default(), source, name, firstchar)?;
170 let nupvals = proto.upvalues.len();
171 let mut upvals = Vec::with_capacity(nupvals);
172 for _ in 0..nupvals {
173 upvals.push(Cell::new(GcRef::new(UpVal::closed(LuaValue::Nil))));
174 }
175 Ok(GcRef::new(LuaLClosure {
176 proto: GcRef::new(*proto),
177 upvals,
178 }))
179}