lune_std_luau/
lib.rs

1#![allow(clippy::cargo_common_metadata)]
2
3use mlua::prelude::*;
4
5use lune_utils::{TableBuilder, jit::JitEnablement};
6
7mod options;
8
9use self::options::{LuauCompileOptions, LuauLoadOptions};
10
11const TYPEDEFS: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/types.d.luau"));
12
13/**
14    Returns a string containing type definitions for the `luau` standard library.
15*/
16#[must_use]
17pub fn typedefs() -> String {
18    TYPEDEFS.to_string()
19}
20
21/**
22    Creates the `luau` standard library module.
23
24    # Errors
25
26    Errors when out of memory.
27*/
28pub fn module(lua: Lua) -> LuaResult<LuaTable> {
29    TableBuilder::new(lua)?
30        .with_function("compile", compile_source)?
31        .with_function("load", load_source)?
32        .build_readonly()
33}
34
35fn compile_source(
36    lua: &Lua,
37    (source, options): (LuaString, LuauCompileOptions),
38) -> LuaResult<LuaString> {
39    options
40        .into_compiler()
41        .compile(source.as_bytes())
42        .and_then(|s| lua.create_string(s))
43}
44
45fn load_source(
46    lua: &Lua,
47    (source, options): (LuaString, LuauLoadOptions),
48) -> LuaResult<LuaFunction> {
49    let mut chunk = lua
50        .load(source.as_bytes().to_vec())
51        .set_name(options.debug_name);
52    let env_changed = options.environment.is_some();
53
54    if let Some(custom_environment) = options.environment {
55        let environment = lua.create_table()?;
56
57        // Inject all globals into the environment
58        if options.inject_globals {
59            for pair in lua.globals().pairs() {
60                let (key, value): (LuaValue, LuaValue) = pair?;
61                environment.set(key, value)?;
62            }
63
64            if let Some(global_metatable) = lua.globals().metatable() {
65                environment.set_metatable(Some(global_metatable))?;
66            }
67        } else if let Some(custom_metatable) = custom_environment.metatable() {
68            // Since we don't need to set the global metatable,
69            // we can just set a custom metatable if it exists
70            environment.set_metatable(Some(custom_metatable))?;
71        }
72
73        // Inject the custom environment
74        for pair in custom_environment.pairs() {
75            let (key, value): (LuaValue, LuaValue) = pair?;
76            environment.set(key, value)?;
77        }
78
79        chunk = chunk.set_environment(environment);
80    }
81
82    // Enable JIT if codegen is enabled and the environment hasn't
83    // changed, otherwise disable JIT since it'll fall back anyways
84    lua.enable_jit(options.codegen_enabled && !env_changed);
85    let function = chunk.into_function()?;
86    lua.enable_jit(
87        lua.app_data_ref::<JitEnablement>()
88            .ok_or(LuaError::runtime(
89                "Failed to get current JitStatus ref from AppData",
90            ))?
91            .enabled(),
92    );
93
94    Ok(function)
95}