low_luajit/lua/state.rs
1use core::ptr::{self, NonNull};
2use crate::ffi::{self, lua_State};
3
4/// Opaque container of the state of a Lua interpreter and entry point to the LuaJIT C API.
5///
6/// See the [top-level documentation](index.html) for details on how to access `LuaState`.
7///
8/// Most functions assume you have a general understanding of the virtual stack the Lua interpreter uses.
9/// If not, refer to [§3.1](https://www.lua.org/manual/5.1/manual.html#3.1) and [§3.2](https://www.lua.org/manual/5.1/manual.html#3.1).
10///
11/// A `LuaState` (and its wrapped pointer) should always be valid (unless unsafe constructors are used incorrectly) and will be treated as such.
12///
13/// *(Most of the methods' documentation below, and a few other places,
14/// has been written using the [Lua 5.1 Reference Manual](https://www.lua.org/manual/5.1/manual.html) as reference:
15/// Copyright © 2006–2012 Lua.org, PUC-Rio. Licensed under the [MIT license](https://www.lua.org/license.html).*)
16#[repr(transparent)]
17#[derive(Debug, PartialEq, Eq)]
18pub struct LuaState(NonNull<lua_State>);
19
20/// State handling functions.
21impl LuaState {
22 /* Not yet...
23 /// Creates a new valid and independent Lua state.
24 ///
25 /// This state will use the standard C `realloc` function as its allocator.
26 ///
27 /// # Safety
28 ///
29 /// While there is nothing inherently unsafe about creating a new `LuaState`,
30 /// using the state without a protected environment could end badly in case a Lua error is triggered:
31 /// at best, Rust simply aborts abruptly...but I've had segmentation faults happen sometimes too.
32 #[inline]
33 pub unsafe fn new_unchecked() -> Self {
34 let ptr = unsafe { luaL_newstate() };
35 assert!(!ptr.is_null(), "cannot create new Lua state: memory allocation error");
36 Self(ptr)
37 }*/
38
39 /// Wraps a pre-existing raw [`lua_State`] pointer.
40 ///
41 /// # Safety
42 ///
43 /// `ptr` **must** be a valid non-null pointer of an already existing state, as all other methods will assume it to be so.
44 ///
45 /// Additionally, there must not be an existing accessible `LuaState` that is already using this pointer.
46 #[must_use]
47 pub const unsafe fn from_ptr(ptr: *mut lua_State) -> Self {
48 // SAFETY: The caller must ensure ptr is a valid non-null pointer.
49 unsafe { Self::from_non_null(NonNull::new_unchecked(ptr) ) }
50 }
51
52 /// Wraps a pre-existing non-null [`lua_State`] pointer.
53 ///
54 /// # Safety
55 ///
56 /// `ptr` **must** be a valid pointer of an already existing state, as all other methods will assume it to be so.
57 ///
58 /// Additionally, there must not be an existing accessible `LuaState` that is already using this pointer.
59 #[must_use]
60 pub const unsafe fn from_non_null(ptr: NonNull<lua_State>) -> Self {
61 Self(ptr)
62 }
63
64 /// Returns the underlying raw [`lua_State`] pointer.
65 /// This can be used to pass the `LuaState` to raw [`ffi`] functions.
66 ///
67 /// The caller must ensure that the `LuaState` outlives the pointer this function returns, or else it will end up dangling.
68 ///
69 /// The returned pointer should also not be passed to functions that might invalidate the `LuaState` (like [`lua_close`]).
70 ///
71 /// [`lua_close`]: ./ffi/fn.lua_close.html
72 #[must_use]
73 pub const fn as_ptr(&self) -> *mut lua_State {
74 self.as_non_null().as_ptr()
75 }
76
77 /// Returns the underlying non-null [`lua_State`] pointer.
78 ///
79 /// The caller must ensure that the `LuaState` outlives the pointer this function returns, or else it will end up dangling.
80 ///
81 /// To pass the `LuaState` to raw [`ffi`] functions, see [`LuaState::as_ptr`].
82 #[must_use]
83 pub const fn as_non_null(&self) -> NonNull<lua_State> {
84 self.0
85 }
86
87 /// Grants temporary mutable access to the [`LuaState`] from an immutable reference.
88 /// This function should be used seldomly.
89 ///
90 /// # Safety
91 ///
92 /// `f` must not pop any pre-existing element and any element pushed onto the stack by `f` should be popped before the function ends.
93 ///
94 /// While not popping all pushed elements will *not* result in undefined behavior,
95 /// it must still be treated as a logic error that should not be relied upon.
96 /// *(Compiling with `debug_assertions` enabled will even includes an extra check for this.)*
97 pub unsafe fn access_mut<T>(&self, f: impl FnOnce(&mut Self) -> T) -> T {
98 #[cfg(debug_assertions)]
99 let top = self.get_top();
100 // SAFETY: self.as_ptr() is always valid and the caller must uphold the safety conditions.
101 let mut lua = unsafe { Self::from_ptr(self.as_ptr()) };
102 let result = f(&mut lua);
103
104 #[cfg(debug_assertions)]
105 debug_assert!(top == self.get_top(), "mutably accessed the Lua state as the stack held {top} elements, but left it with {} elements instead", self.get_top());
106 result
107 }
108
109 /// Destroys all objects and frees all dynamic memory of the state.
110 ///
111 /// # Safety
112 ///
113 /// Can only be called if this `LuaState` is not being used anywhere else.
114 ///
115 /// If your crate is a Lua module, this function must *not* return back to the Lua interpreter (as it would no longer exist).
116 #[inline]
117 pub unsafe fn close(self) {
118 // SAFETY: self.as_ptr() is always valid and the caller must make sure that the LuaState is not used anywhere else.
119 unsafe { ffi::lua_close(self.as_ptr()); }
120 }
121
122 /// Returns a reference to a number that represents the version of Lua.
123 ///
124 /// For LuaJIT, this should always returns `501` (which represents 5.1, the Lua version LuaJIT is based on).
125 #[inline]
126 #[must_use]
127 pub fn version() -> &'static f64 {
128 // SAFETY: lua_version doesn't actually use the pointer given to it and always returns a valid pointer to a static f64.
129 unsafe { &*ffi::lua_version(ptr::null_mut()) }
130 }
131}
132
133/// Creates a new `LuaState` for internal testing purposes.
134#[macro_export]
135#[doc(hidden)]
136macro_rules! __test {
137 ($($lib:ident),*) => {{
138 #[cfg(not(windows))]
139 #[link(name = "luajit-5.1")]
140 unsafe extern "C" {}
141
142 let ptr = $crate::ffi::luaL_newstate();
143 $($crate::ffi::$lib(ptr);)*
144 $crate::LuaState::from_ptr(ptr)
145 }};
146}