factorio_mlua/
types.rs

1use std::cell::UnsafeCell;
2use std::hash::{Hash, Hasher};
3use std::os::raw::{c_int, c_void};
4use std::sync::{Arc, Mutex};
5use std::{fmt, mem, ptr};
6
7#[cfg(feature = "lua54")]
8use std::ffi::CStr;
9
10#[cfg(feature = "async")]
11use futures_core::future::LocalBoxFuture;
12
13use crate::error::Result;
14use crate::ffi;
15#[cfg(not(feature = "luau"))]
16use crate::hook::Debug;
17use crate::lua::{ExtraData, Lua};
18use crate::util::{assert_stack, StackGuard};
19use crate::value::MultiValue;
20
21/// Type of Lua integer numbers.
22pub type Integer = ffi::lua_Integer;
23/// Type of Lua floating point numbers.
24pub type Number = ffi::lua_Number;
25
26/// A "light" userdata value. Equivalent to an unmanaged raw pointer.
27#[derive(Debug, Copy, Clone, Eq, PartialEq)]
28pub struct LightUserData(pub *mut c_void);
29
30pub(crate) type Callback<'lua, 'a> =
31    Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>> + 'a>;
32
33pub(crate) struct Upvalue<T> {
34    pub(crate) data: T,
35    pub(crate) extra: Arc<UnsafeCell<ExtraData>>,
36}
37
38pub(crate) type CallbackUpvalue = Upvalue<Callback<'static, 'static>>;
39
40#[cfg(feature = "async")]
41pub(crate) type AsyncCallback<'lua, 'a> =
42    Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> LocalBoxFuture<'lua, Result<MultiValue<'lua>>> + 'a>;
43
44#[cfg(feature = "async")]
45pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static, 'static>>;
46
47#[cfg(feature = "async")]
48pub(crate) type AsyncPollUpvalue = Upvalue<LocalBoxFuture<'static, Result<MultiValue<'static>>>>;
49
50/// Type to set next Luau VM action after executing interrupt function.
51#[cfg(any(feature = "luau", doc))]
52#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
53pub enum VmState {
54    Continue,
55    Yield,
56}
57
58#[cfg(all(feature = "send", not(feature = "luau")))]
59pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()> + Send>;
60
61#[cfg(all(not(feature = "send"), not(feature = "luau")))]
62pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()>>;
63
64#[cfg(all(feature = "luau", feature = "send"))]
65pub(crate) type InterruptCallback = Arc<dyn Fn() -> Result<VmState> + Send>;
66
67#[cfg(all(feature = "luau", not(feature = "send")))]
68pub(crate) type InterruptCallback = Arc<dyn Fn() -> Result<VmState>>;
69
70#[cfg(all(feature = "send", feature = "lua54"))]
71pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &CStr, bool) -> Result<()> + Send>;
72
73#[cfg(all(not(feature = "send"), feature = "lua54"))]
74pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &CStr, bool) -> Result<()>>;
75
76#[cfg(feature = "send")]
77pub trait MaybeSend: Send {}
78#[cfg(feature = "send")]
79impl<T: Send> MaybeSend for T {}
80
81#[cfg(not(feature = "send"))]
82pub trait MaybeSend {}
83#[cfg(not(feature = "send"))]
84impl<T> MaybeSend for T {}
85
86pub(crate) struct DestructedUserdataMT;
87
88/// An auto generated key into the Lua registry.
89///
90/// This is a handle to a value stored inside the Lua registry. It is not automatically
91/// garbage collected on Drop, but it can be removed with [`Lua::remove_registry_value`],
92/// and instances not manually removed can be garbage collected with [`Lua::expire_registry_values`].
93///
94/// Be warned, If you place this into Lua via a [`UserData`] type or a rust callback, it is *very
95/// easy* to accidentally cause reference cycles that the Lua garbage collector cannot resolve.
96/// Instead of placing a [`RegistryKey`] into a [`UserData`] type, prefer instead to use
97/// [`AnyUserData::set_user_value`] / [`AnyUserData::get_user_value`].
98///
99/// [`UserData`]: crate::UserData
100/// [`RegistryKey`]: crate::RegistryKey
101/// [`Lua::remove_registry_value`]: crate::Lua::remove_registry_value
102/// [`Lua::expire_registry_values`]: crate::Lua::expire_registry_values
103/// [`AnyUserData::set_user_value`]: crate::AnyUserData::set_user_value
104/// [`AnyUserData::get_user_value`]: crate::AnyUserData::get_user_value
105pub struct RegistryKey {
106    pub(crate) registry_id: c_int,
107    pub(crate) unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
108}
109
110impl fmt::Debug for RegistryKey {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        write!(f, "RegistryKey({})", self.registry_id)
113    }
114}
115
116impl Hash for RegistryKey {
117    fn hash<H: Hasher>(&self, state: &mut H) {
118        self.registry_id.hash(state)
119    }
120}
121
122impl PartialEq for RegistryKey {
123    fn eq(&self, other: &RegistryKey) -> bool {
124        self.registry_id == other.registry_id && Arc::ptr_eq(&self.unref_list, &other.unref_list)
125    }
126}
127
128impl Eq for RegistryKey {}
129
130impl Drop for RegistryKey {
131    fn drop(&mut self) {
132        let mut unref_list = mlua_expect!(self.unref_list.lock(), "unref list poisoned");
133        if let Some(list) = unref_list.as_mut() {
134            list.push(self.registry_id);
135        }
136    }
137}
138
139impl RegistryKey {
140    // Destroys the RegistryKey without adding to the drop list
141    pub(crate) fn take(self) -> c_int {
142        let registry_id = self.registry_id;
143        unsafe {
144            ptr::read(&self.unref_list);
145            mem::forget(self);
146        }
147        registry_id
148    }
149}
150
151pub(crate) struct LuaRef<'lua> {
152    pub(crate) lua: &'lua Lua,
153    pub(crate) index: c_int,
154}
155
156impl<'lua> fmt::Debug for LuaRef<'lua> {
157    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158        write!(f, "Ref({})", self.index)
159    }
160}
161
162impl<'lua> Clone for LuaRef<'lua> {
163    fn clone(&self) -> Self {
164        self.lua.clone_ref(self)
165    }
166}
167
168impl<'lua> Drop for LuaRef<'lua> {
169    fn drop(&mut self) {
170        if self.index > 0 {
171            self.lua.drop_ref(self);
172        }
173    }
174}
175
176impl<'lua> PartialEq for LuaRef<'lua> {
177    fn eq(&self, other: &Self) -> bool {
178        let lua = self.lua;
179        unsafe {
180            let _sg = StackGuard::new(lua.state);
181            assert_stack(lua.state, 2);
182            lua.push_ref(self);
183            lua.push_ref(other);
184            ffi::lua_rawequal(lua.state, -1, -2) == 1
185        }
186    }
187}