1use std::ffi::CStr;
2use std::os::raw::c_int;
3use std::ptr;
4
5use crate::chunk::ChunkMode;
6use crate::error::Result;
7use crate::function::Function;
8use crate::state::{callback_error_ext, ExtraData, Lua};
9use crate::traits::{FromLuaMulti, IntoLua};
10use crate::types::MaybeSend;
11
12pub use require::{NavigateError, Require, TextRequirer};
13
14impl Lua {
17 #[cfg(any(feature = "luau", doc))]
20 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
21 pub fn create_require_function<R: Require + MaybeSend + 'static>(&self, require: R) -> Result<Function> {
22 require::create_require_function(self, require)
23 }
24
25 pub(crate) unsafe fn configure_luau(&self) -> Result<()> {
26 let globals = self.globals();
27
28 globals.raw_set("collectgarbage", self.create_c_function(lua_collectgarbage)?)?;
29 globals.raw_set("loadstring", self.create_c_function(lua_loadstring)?)?;
30
31 if let Some(version) = ffi::luau_version() {
34 globals.raw_set("_VERSION", format!("Luau {version}"))?;
35 }
36
37 let require = self.create_require_function(require::TextRequirer::new())?;
39 self.globals().raw_set("require", require)?;
40
41 Ok(())
42 }
43}
44
45unsafe extern "C-unwind" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_int {
46 let option = ffi::luaL_optstring(state, 1, cstr!("collect"));
47 let option = CStr::from_ptr(option);
48 let arg = ffi::luaL_optinteger(state, 2, 0);
49 let is_sandboxed = (*ExtraData::get(state)).sandboxed;
50 match option.to_str() {
51 Ok("collect") if !is_sandboxed => {
52 ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0);
53 0
54 }
55 Ok("stop") if !is_sandboxed => {
56 ffi::lua_gc(state, ffi::LUA_GCSTOP, 0);
57 0
58 }
59 Ok("restart") if !is_sandboxed => {
60 ffi::lua_gc(state, ffi::LUA_GCRESTART, 0);
61 0
62 }
63 Ok("count") => {
64 let kbytes = ffi::lua_gc(state, ffi::LUA_GCCOUNT, 0) as ffi::lua_Number;
65 let kbytes_rem = ffi::lua_gc(state, ffi::LUA_GCCOUNTB, 0) as ffi::lua_Number;
66 ffi::lua_pushnumber(state, kbytes + kbytes_rem / 1024.0);
67 1
68 }
69 Ok("step") if !is_sandboxed => {
70 let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg as _);
71 ffi::lua_pushboolean(state, res);
72 1
73 }
74 Ok("isrunning") if !is_sandboxed => {
75 let res = ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0);
76 ffi::lua_pushboolean(state, res);
77 1
78 }
79 _ => ffi::luaL_error(state, cstr!("collectgarbage called with invalid option")),
80 }
81}
82
83unsafe extern "C-unwind" fn lua_loadstring(state: *mut ffi::lua_State) -> c_int {
84 callback_error_ext(state, ptr::null_mut(), false, move |extra, nargs| {
85 let rawlua = (*extra).raw_lua();
86 let (chunk, chunk_name) =
87 <(String, Option<String>)>::from_stack_args(nargs, 1, Some("loadstring"), rawlua)?;
88 let chunk_name = chunk_name.as_deref().unwrap_or("=(loadstring)");
89 (rawlua.lua())
90 .load(chunk)
91 .set_name(chunk_name)
92 .set_mode(ChunkMode::Text)
93 .into_function()?
94 .push_into_stack(rawlua)?;
95 Ok(1)
96 })
97}
98
99mod require;