mlua/
types.rs

1use std::any::{Any, TypeId};
2use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
3use std::hash::{Hash, Hasher};
4use std::ops::{Deref, DerefMut};
5use std::os::raw::{c_int, c_void};
6use std::result::Result as StdResult;
7use std::sync::atomic::{AtomicI32, Ordering};
8use std::sync::{Arc, Mutex};
9use std::{fmt, mem, ptr};
10
11use rustc_hash::FxHashMap;
12
13use crate::error::Result;
14#[cfg(not(feature = "luau"))]
15use crate::hook::Debug;
16use crate::lua::{ExtraData, Lua};
17
18#[cfg(feature = "async")]
19use {crate::value::MultiValue, futures_util::future::LocalBoxFuture};
20
21#[cfg(feature = "unstable")]
22use {crate::lua::LuaInner, std::marker::PhantomData};
23
24#[cfg(all(feature = "luau", feature = "serialize"))]
25use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
26
27/// Type of Lua integer numbers.
28pub type Integer = ffi::lua_Integer;
29/// Type of Lua floating point numbers.
30pub type Number = ffi::lua_Number;
31
32// Represents different subtypes wrapped to AnyUserData
33#[derive(Debug, Copy, Clone, Eq, PartialEq)]
34pub(crate) enum SubtypeId {
35    None,
36    #[cfg(feature = "luau")]
37    Buffer,
38    #[cfg(feature = "luajit")]
39    CData,
40}
41
42/// A "light" userdata value. Equivalent to an unmanaged raw pointer.
43#[derive(Debug, Copy, Clone, Eq, PartialEq)]
44pub struct LightUserData(pub *mut c_void);
45
46pub(crate) type Callback<'lua, 'a> = Box<dyn Fn(&'lua Lua, c_int) -> Result<c_int> + 'a>;
47
48pub(crate) struct Upvalue<T> {
49    pub(crate) data: T,
50    pub(crate) extra: Arc<UnsafeCell<ExtraData>>,
51}
52
53pub(crate) type CallbackUpvalue = Upvalue<Callback<'static, 'static>>;
54
55#[cfg(feature = "async")]
56pub(crate) type AsyncCallback<'lua, 'a> =
57    Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> LocalBoxFuture<'lua, Result<c_int>> + 'a>;
58
59#[cfg(feature = "async")]
60pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static, 'static>>;
61
62#[cfg(feature = "async")]
63pub(crate) type AsyncPollUpvalue = Upvalue<LocalBoxFuture<'static, Result<c_int>>>;
64
65/// Type to set next Luau VM action after executing interrupt function.
66#[cfg(any(feature = "luau", doc))]
67#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
68pub enum VmState {
69    Continue,
70    Yield,
71}
72
73#[cfg(all(feature = "send", not(feature = "luau")))]
74pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()> + Send>;
75
76#[cfg(all(not(feature = "send"), not(feature = "luau")))]
77pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()>>;
78
79#[cfg(all(feature = "luau", feature = "send"))]
80pub(crate) type InterruptCallback = Arc<dyn Fn(&Lua) -> Result<VmState> + Send>;
81
82#[cfg(all(feature = "luau", not(feature = "send")))]
83pub(crate) type InterruptCallback = Arc<dyn Fn(&Lua) -> Result<VmState>>;
84
85#[cfg(all(feature = "send", feature = "lua54"))]
86pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &str, bool) -> Result<()> + Send>;
87
88#[cfg(all(not(feature = "send"), feature = "lua54"))]
89pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &str, bool) -> Result<()>>;
90
91#[cfg(feature = "send")]
92pub trait MaybeSend: Send {}
93#[cfg(feature = "send")]
94impl<T: Send> MaybeSend for T {}
95
96#[cfg(not(feature = "send"))]
97pub trait MaybeSend {}
98#[cfg(not(feature = "send"))]
99impl<T> MaybeSend for T {}
100
101/// A Luau vector type.
102///
103/// By default vectors are 3-dimensional, but can be 4-dimensional
104/// if the `luau-vector4` feature is enabled.
105#[cfg(any(feature = "luau", doc))]
106#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
107#[derive(Debug, Default, Clone, Copy, PartialEq)]
108pub struct Vector(pub(crate) [f32; Self::SIZE]);
109
110#[cfg(any(feature = "luau", doc))]
111impl fmt::Display for Vector {
112    #[rustfmt::skip]
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        #[cfg(not(feature = "luau-vector4"))]
115        return write!(f, "vector({}, {}, {})", self.x(), self.y(), self.z());
116        #[cfg(feature = "luau-vector4")]
117        return write!(f, "vector({}, {}, {}, {})", self.x(), self.y(), self.z(), self.w());
118    }
119}
120
121#[cfg(any(feature = "luau", doc))]
122impl Vector {
123    pub(crate) const SIZE: usize = if cfg!(feature = "luau-vector4") { 4 } else { 3 };
124
125    /// Creates a new vector.
126    #[cfg(not(feature = "luau-vector4"))]
127    pub const fn new(x: f32, y: f32, z: f32) -> Self {
128        Self([x, y, z])
129    }
130
131    /// Creates a new vector.
132    #[cfg(feature = "luau-vector4")]
133    pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
134        Self([x, y, z, w])
135    }
136
137    /// Creates a new vector with all components set to `0.0`.
138    #[doc(hidden)]
139    pub const fn zero() -> Self {
140        Self([0.0; Self::SIZE])
141    }
142
143    /// Returns 1st component of the vector.
144    pub const fn x(&self) -> f32 {
145        self.0[0]
146    }
147
148    /// Returns 2nd component of the vector.
149    pub const fn y(&self) -> f32 {
150        self.0[1]
151    }
152
153    /// Returns 3rd component of the vector.
154    pub const fn z(&self) -> f32 {
155        self.0[2]
156    }
157
158    /// Returns 4th component of the vector.
159    #[cfg(any(feature = "luau-vector4", doc))]
160    #[cfg_attr(docsrs, doc(cfg(feature = "luau-vector4")))]
161    pub const fn w(&self) -> f32 {
162        self.0[3]
163    }
164}
165
166#[cfg(all(feature = "luau", feature = "serialize"))]
167impl Serialize for Vector {
168    fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
169        let mut ts = serializer.serialize_tuple_struct("Vector", Self::SIZE)?;
170        ts.serialize_field(&self.x())?;
171        ts.serialize_field(&self.y())?;
172        ts.serialize_field(&self.z())?;
173        #[cfg(feature = "luau-vector4")]
174        ts.serialize_field(&self.w())?;
175        ts.end()
176    }
177}
178
179#[cfg(any(feature = "luau", doc))]
180impl PartialEq<[f32; Self::SIZE]> for Vector {
181    #[inline]
182    fn eq(&self, other: &[f32; Self::SIZE]) -> bool {
183        self.0 == *other
184    }
185}
186
187pub(crate) struct DestructedUserdata;
188
189/// An auto generated key into the Lua registry.
190///
191/// This is a handle to a value stored inside the Lua registry. It is not automatically
192/// garbage collected on Drop, but it can be removed with [`Lua::remove_registry_value`],
193/// and instances not manually removed can be garbage collected with [`Lua::expire_registry_values`].
194///
195/// Be warned, If you place this into Lua via a [`UserData`] type or a rust callback, it is *very
196/// easy* to accidentally cause reference cycles that the Lua garbage collector cannot resolve.
197/// Instead of placing a [`RegistryKey`] into a [`UserData`] type, prefer instead to use
198/// [`AnyUserData::set_user_value`] / [`AnyUserData::user_value`].
199///
200/// [`UserData`]: crate::UserData
201/// [`RegistryKey`]: crate::RegistryKey
202/// [`Lua::remove_registry_value`]: crate::Lua::remove_registry_value
203/// [`Lua::expire_registry_values`]: crate::Lua::expire_registry_values
204/// [`AnyUserData::set_user_value`]: crate::AnyUserData::set_user_value
205/// [`AnyUserData::user_value`]: crate::AnyUserData::user_value
206pub struct RegistryKey {
207    pub(crate) registry_id: AtomicI32,
208    pub(crate) unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
209}
210
211impl fmt::Debug for RegistryKey {
212    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213        write!(f, "RegistryKey({})", self.id())
214    }
215}
216
217impl Hash for RegistryKey {
218    fn hash<H: Hasher>(&self, state: &mut H) {
219        self.id().hash(state)
220    }
221}
222
223impl PartialEq for RegistryKey {
224    fn eq(&self, other: &RegistryKey) -> bool {
225        self.id() == other.id() && Arc::ptr_eq(&self.unref_list, &other.unref_list)
226    }
227}
228
229impl Eq for RegistryKey {}
230
231impl Drop for RegistryKey {
232    fn drop(&mut self) {
233        let registry_id = self.id();
234        // We don't need to collect nil slot
235        if registry_id > ffi::LUA_REFNIL {
236            let mut unref_list = mlua_expect!(self.unref_list.lock(), "unref list poisoned");
237            if let Some(list) = unref_list.as_mut() {
238                list.push(registry_id);
239            }
240        }
241    }
242}
243
244impl RegistryKey {
245    /// Creates a new instance of `RegistryKey`
246    pub(crate) const fn new(id: c_int, unref_list: Arc<Mutex<Option<Vec<c_int>>>>) -> Self {
247        RegistryKey {
248            registry_id: AtomicI32::new(id),
249            unref_list,
250        }
251    }
252
253    /// Returns the underlying Lua reference of this `RegistryKey`
254    #[inline(always)]
255    pub fn id(&self) -> c_int {
256        self.registry_id.load(Ordering::Relaxed)
257    }
258
259    /// Sets the unique Lua reference key of this `RegistryKey`
260    #[inline(always)]
261    pub(crate) fn set_id(&self, id: c_int) {
262        self.registry_id.store(id, Ordering::Relaxed);
263    }
264
265    /// Destroys the `RegistryKey` without adding to the unref list
266    pub(crate) fn take(self) -> i32 {
267        let registry_id = self.id();
268        unsafe {
269            ptr::read(&self.unref_list);
270            mem::forget(self);
271        }
272        registry_id
273    }
274}
275
276pub(crate) struct LuaRef<'lua> {
277    pub(crate) lua: &'lua Lua,
278    pub(crate) index: c_int,
279    pub(crate) drop: bool,
280}
281
282impl<'lua> LuaRef<'lua> {
283    pub(crate) const fn new(lua: &'lua Lua, index: c_int) -> Self {
284        LuaRef {
285            lua,
286            index,
287            drop: true,
288        }
289    }
290
291    #[inline]
292    pub(crate) fn to_pointer(&self) -> *const c_void {
293        unsafe { ffi::lua_topointer(self.lua.ref_thread(), self.index) }
294    }
295
296    #[cfg(feature = "unstable")]
297    #[inline]
298    pub(crate) fn into_owned(self) -> LuaOwnedRef {
299        assert!(self.drop, "Cannot turn non-drop reference into owned");
300        let owned_ref = LuaOwnedRef::new(self.lua.clone(), self.index);
301        mem::forget(self);
302        owned_ref
303    }
304}
305
306impl<'lua> fmt::Debug for LuaRef<'lua> {
307    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308        write!(f, "Ref({:p})", self.to_pointer())
309    }
310}
311
312impl<'lua> Clone for LuaRef<'lua> {
313    fn clone(&self) -> Self {
314        self.lua.clone_ref(self)
315    }
316}
317
318impl<'lua> Drop for LuaRef<'lua> {
319    fn drop(&mut self) {
320        if self.drop {
321            self.lua.drop_ref_index(self.index);
322        }
323    }
324}
325
326impl<'lua> PartialEq for LuaRef<'lua> {
327    fn eq(&self, other: &Self) -> bool {
328        let ref_thread = self.lua.ref_thread();
329        assert!(
330            ref_thread == other.lua.ref_thread(),
331            "Lua instance passed Value created from a different main Lua state"
332        );
333        unsafe { ffi::lua_rawequal(ref_thread, self.index, other.index) == 1 }
334    }
335}
336
337#[cfg(feature = "unstable")]
338pub(crate) struct LuaOwnedRef {
339    pub(crate) inner: Arc<LuaInner>,
340    pub(crate) index: c_int,
341    _non_send: PhantomData<*const ()>,
342}
343
344#[cfg(feature = "unstable")]
345impl fmt::Debug for LuaOwnedRef {
346    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347        write!(f, "OwnedRef({:p})", self.to_ref().to_pointer())
348    }
349}
350
351#[cfg(feature = "unstable")]
352impl Clone for LuaOwnedRef {
353    fn clone(&self) -> Self {
354        self.to_ref().clone().into_owned()
355    }
356}
357
358#[cfg(feature = "unstable")]
359impl Drop for LuaOwnedRef {
360    fn drop(&mut self) {
361        let lua: &Lua = unsafe { mem::transmute(&self.inner) };
362        lua.drop_ref_index(self.index);
363    }
364}
365
366#[cfg(feature = "unstable")]
367impl LuaOwnedRef {
368    pub(crate) const fn new(inner: Arc<LuaInner>, index: c_int) -> Self {
369        LuaOwnedRef {
370            inner,
371            index,
372            _non_send: PhantomData,
373        }
374    }
375
376    pub(crate) const fn to_ref(&self) -> LuaRef {
377        LuaRef {
378            lua: unsafe { mem::transmute(&self.inner) },
379            index: self.index,
380            drop: false,
381        }
382    }
383}
384
385#[derive(Debug, Default)]
386pub(crate) struct AppData {
387    #[cfg(not(feature = "send"))]
388    container: UnsafeCell<FxHashMap<TypeId, RefCell<Box<dyn Any>>>>,
389    #[cfg(feature = "send")]
390    container: UnsafeCell<FxHashMap<TypeId, RefCell<Box<dyn Any + Send>>>>,
391    borrow: Cell<usize>,
392}
393
394impl AppData {
395    #[track_caller]
396    pub(crate) fn insert<T: MaybeSend + 'static>(&self, data: T) -> Option<T> {
397        match self.try_insert(data) {
398            Ok(data) => data,
399            Err(_) => panic!("cannot mutably borrow app data container"),
400        }
401    }
402
403    pub(crate) fn try_insert<T: MaybeSend + 'static>(&self, data: T) -> StdResult<Option<T>, T> {
404        if self.borrow.get() != 0 {
405            return Err(data);
406        }
407        // SAFETY: we checked that there are no other references to the container
408        Ok(unsafe { &mut *self.container.get() }
409            .insert(TypeId::of::<T>(), RefCell::new(Box::new(data)))
410            .and_then(|data| data.into_inner().downcast::<T>().ok().map(|data| *data)))
411    }
412
413    #[track_caller]
414    pub(crate) fn borrow<T: 'static>(&self) -> Option<AppDataRef<T>> {
415        let data = unsafe { &*self.container.get() }
416            .get(&TypeId::of::<T>())?
417            .borrow();
418        self.borrow.set(self.borrow.get() + 1);
419        Some(AppDataRef {
420            data: Ref::filter_map(data, |data| data.downcast_ref()).ok()?,
421            borrow: &self.borrow,
422        })
423    }
424
425    #[track_caller]
426    pub(crate) fn borrow_mut<T: 'static>(&self) -> Option<AppDataRefMut<T>> {
427        let data = unsafe { &*self.container.get() }
428            .get(&TypeId::of::<T>())?
429            .borrow_mut();
430        self.borrow.set(self.borrow.get() + 1);
431        Some(AppDataRefMut {
432            data: RefMut::filter_map(data, |data| data.downcast_mut()).ok()?,
433            borrow: &self.borrow,
434        })
435    }
436
437    #[track_caller]
438    pub(crate) fn remove<T: 'static>(&self) -> Option<T> {
439        if self.borrow.get() != 0 {
440            panic!("cannot mutably borrow app data container");
441        }
442        // SAFETY: we checked that there are no other references to the container
443        unsafe { &mut *self.container.get() }
444            .remove(&TypeId::of::<T>())?
445            .into_inner()
446            .downcast::<T>()
447            .ok()
448            .map(|data| *data)
449    }
450}
451
452/// A wrapper type for an immutably borrowed value from an app data container.
453///
454/// This type is similar to [`Ref`].
455pub struct AppDataRef<'a, T: ?Sized + 'a> {
456    data: Ref<'a, T>,
457    borrow: &'a Cell<usize>,
458}
459
460impl<T: ?Sized> Drop for AppDataRef<'_, T> {
461    fn drop(&mut self) {
462        self.borrow.set(self.borrow.get() - 1);
463    }
464}
465
466impl<T: ?Sized> Deref for AppDataRef<'_, T> {
467    type Target = T;
468
469    #[inline]
470    fn deref(&self) -> &Self::Target {
471        &self.data
472    }
473}
474
475impl<T: ?Sized + fmt::Display> fmt::Display for AppDataRef<'_, T> {
476    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477        (**self).fmt(f)
478    }
479}
480
481impl<T: ?Sized + fmt::Debug> fmt::Debug for AppDataRef<'_, T> {
482    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483        (**self).fmt(f)
484    }
485}
486
487/// A wrapper type for a mutably borrowed value from an app data container.
488///
489/// This type is similar to [`RefMut`].
490pub struct AppDataRefMut<'a, T: ?Sized + 'a> {
491    data: RefMut<'a, T>,
492    borrow: &'a Cell<usize>,
493}
494
495impl<T: ?Sized> Drop for AppDataRefMut<'_, T> {
496    fn drop(&mut self) {
497        self.borrow.set(self.borrow.get() - 1);
498    }
499}
500
501impl<T: ?Sized> Deref for AppDataRefMut<'_, T> {
502    type Target = T;
503
504    #[inline]
505    fn deref(&self) -> &Self::Target {
506        &self.data
507    }
508}
509
510impl<T: ?Sized> DerefMut for AppDataRefMut<'_, T> {
511    #[inline]
512    fn deref_mut(&mut self) -> &mut Self::Target {
513        &mut self.data
514    }
515}
516
517impl<T: ?Sized + fmt::Display> fmt::Display for AppDataRefMut<'_, T> {
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519        (**self).fmt(f)
520    }
521}
522
523impl<T: ?Sized + fmt::Debug> fmt::Debug for AppDataRefMut<'_, T> {
524    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525        (**self).fmt(f)
526    }
527}
528
529#[cfg(test)]
530mod assertions {
531    use super::*;
532
533    static_assertions::assert_impl_all!(RegistryKey: Send, Sync);
534    static_assertions::assert_not_impl_any!(LuaRef: Send);
535
536    #[cfg(feature = "unstable")]
537    static_assertions::assert_not_impl_any!(LuaOwnedRef: Send);
538}