use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
use luau_vm::Thread as VmThread;
use luau_vm::native::NativeCallResult;
use luau_vm::thread::StackGuard;
use super::Lua;
use crate::error::Error;
type LibraryOpen = unsafe fn(&VmThread) -> NativeCallResult;
const LIBRARIES: &[(StdLib, LibraryOpen)] = &[
(StdLib::BASE, VmThread::open_base),
(StdLib::COROUTINE, VmThread::open_coroutine),
(StdLib::TABLE, VmThread::open_table),
(StdLib::OS, VmThread::open_os),
(StdLib::STRING, VmThread::open_string),
(StdLib::MATH, VmThread::open_math),
(StdLib::DEBUG, VmThread::open_debug),
(StdLib::UTF8, VmThread::open_utf8),
(StdLib::BIT32, VmThread::open_bit32),
(StdLib::BUFFER, VmThread::open_buffer),
(StdLib::VECTOR, VmThread::open_vector),
(StdLib::INTEGER, VmThread::open_integer),
(StdLib::CLASS, VmThread::open_class),
];
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct StdLib(u32);
impl StdLib {
pub const BASE: Self = Self(1);
pub const COROUTINE: Self = Self(1 << 1);
pub const TABLE: Self = Self(1 << 2);
pub const OS: Self = Self(1 << 3);
pub const STRING: Self = Self(1 << 4);
pub const MATH: Self = Self(1 << 5);
pub const DEBUG: Self = Self(1 << 6);
pub const UTF8: Self = Self(1 << 7);
pub const BIT32: Self = Self(1 << 8);
pub const BUFFER: Self = Self(1 << 9);
pub const VECTOR: Self = Self(1 << 10);
pub const INTEGER: Self = Self(1 << 11);
pub const CLASS: Self = Self(1 << 12);
pub const NONE: Self = Self(0);
pub const ALL: Self = Self(u32::MAX);
pub const fn contains(self, lib: Self) -> bool {
(self.0 & lib.0) != 0
}
pub(crate) fn open(self, thread: &VmThread) -> Result<(), Error> {
if self == Self::NONE {
return Ok(());
}
if self == Self::ALL {
return unsafe { open_all(thread) };
}
for (lib, open) in LIBRARIES {
if self.contains(*lib) {
unsafe { open_library(thread, *open)? };
}
}
Ok(())
}
}
impl Lua {
pub fn load_std_libs(&self, libs: StdLib) -> Result<(), Error> {
if libs != StdLib::NONE {
self.runtime.invalidate_managed_safe_env();
}
libs.open(self.state.main_thread())
}
}
impl BitAnd for StdLib {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl BitAndAssign for StdLib {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
impl BitOr for StdLib {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl BitOrAssign for StdLib {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl BitXor for StdLib {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
Self(self.0 ^ rhs.0)
}
}
impl BitXorAssign for StdLib {
fn bitxor_assign(&mut self, rhs: Self) {
self.0 ^= rhs.0;
}
}
impl Not for StdLib {
type Output = Self;
fn not(self) -> Self::Output {
Self(!self.0)
}
}
unsafe fn open_all(thread: &VmThread) -> Result<(), Error> {
let _stack = unsafe { StackGuard::new(thread) };
match unsafe { thread.open_libs() } {
Ok(_) => Ok(()),
Err(exit) => Err(Error::from_thread_exit(thread, exit)),
}
}
unsafe fn open_library(thread: &VmThread, open: LibraryOpen) -> Result<(), Error> {
let _stack = unsafe { StackGuard::new(thread) };
match unsafe { open(thread) } {
Ok(_) => Ok(()),
Err(exit) => Err(Error::from_thread_exit(thread, exit)),
}
}