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
27pub type Integer = ffi::lua_Integer;
29pub type Number = ffi::lua_Number;
31
32#[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#[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#[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#[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 #[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 #[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 #[doc(hidden)]
139 pub const fn zero() -> Self {
140 Self([0.0; Self::SIZE])
141 }
142
143 pub const fn x(&self) -> f32 {
145 self.0[0]
146 }
147
148 pub const fn y(&self) -> f32 {
150 self.0[1]
151 }
152
153 pub const fn z(&self) -> f32 {
155 self.0[2]
156 }
157
158 #[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
189pub 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 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 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 #[inline(always)]
255 pub fn id(&self) -> c_int {
256 self.registry_id.load(Ordering::Relaxed)
257 }
258
259 #[inline(always)]
261 pub(crate) fn set_id(&self, id: c_int) {
262 self.registry_id.store(id, Ordering::Relaxed);
263 }
264
265 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 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 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
452pub 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
487pub 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}