Skip to main content

mlua/userdata/
ref.rs

1use std::any::{TypeId, type_name};
2use std::ops::{Deref, DerefMut};
3use std::os::raw::c_int;
4use std::{fmt, mem};
5
6use crate::error::{Error, Result};
7use crate::state::{Lua, RawLua};
8use crate::traits::FromLua;
9use crate::userdata::AnyUserData;
10use crate::util::{check_stack, get_userdata, take_userdata};
11use crate::value::Value;
12
13use super::cell::{UserDataStorage, UserDataVariant};
14use super::lock::{LockGuard, RawLock, UserDataLock};
15
16#[cfg(feature = "userdata-wrappers")]
17use {
18    parking_lot::{
19        Mutex as MutexPL, MutexGuard as MutexGuardPL, RwLock as RwLockPL,
20        RwLockReadGuard as RwLockReadGuardPL, RwLockWriteGuard as RwLockWriteGuardPL,
21    },
22    std::sync::Arc,
23};
24#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
25use {
26    std::cell::{Ref, RefCell, RefMut},
27    std::rc::Rc,
28};
29
30/// A wrapper type for a userdata value that provides read access.
31///
32/// It implements [`FromLua`] and can be used to receive a typed userdata from Lua.
33pub struct UserDataRef<T: 'static> {
34    // It's important to drop the guard first, as it refers to the `inner` data.
35    _guard: LockGuard<'static, RawLock>,
36    inner: UserDataRefInner<T>,
37}
38
39impl<T> Deref for UserDataRef<T> {
40    type Target = T;
41
42    #[inline]
43    fn deref(&self) -> &T {
44        &self.inner
45    }
46}
47
48impl<T: fmt::Debug> fmt::Debug for UserDataRef<T> {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        (**self).fmt(f)
51    }
52}
53
54impl<T: fmt::Display> fmt::Display for UserDataRef<T> {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        (**self).fmt(f)
57    }
58}
59
60impl<T> TryFrom<UserDataVariant<T>> for UserDataRef<T> {
61    type Error = Error;
62
63    #[inline]
64    fn try_from(variant: UserDataVariant<T>) -> Result<Self> {
65        // Shared (read) lock is always correct:
66        // - with `send` feature, `T: Sync` is guaranteed by the `MaybeSync` bound on userdata
67        //   creation
68        // - without `send` feature, single-threaded access makes shared lock safe for any `T`
69        let guard = variant.raw_lock().try_lock_shared_guarded();
70        let guard = guard.map_err(|_| Error::UserDataBorrowError)?;
71        let guard = unsafe { mem::transmute::<LockGuard<_>, LockGuard<'static, _>>(guard) };
72        Ok(UserDataRef::from_parts(UserDataRefInner::Default(variant), guard))
73    }
74}
75
76impl<T: 'static> FromLua for UserDataRef<T> {
77    fn from_lua(value: Value, _: &Lua) -> Result<Self> {
78        try_value_to_userdata::<T>(value)?.borrow()
79    }
80
81    #[inline]
82    unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
83        Self::borrow_from_stack(lua, lua.state(), idx)
84    }
85}
86
87impl<T: 'static> UserDataRef<T> {
88    #[inline(always)]
89    fn from_parts(inner: UserDataRefInner<T>, guard: LockGuard<'static, RawLock>) -> Self {
90        Self { _guard: guard, inner }
91    }
92
93    #[cfg(feature = "userdata-wrappers")]
94    fn remap<U>(
95        self,
96        f: impl FnOnce(UserDataVariant<T>) -> Result<UserDataRefInner<U>>,
97    ) -> Result<UserDataRef<U>> {
98        match &self.inner {
99            UserDataRefInner::Default(variant) => {
100                let inner = f(variant.clone())?;
101                Ok(UserDataRef::from_parts(inner, self._guard))
102            }
103            _ => Err(Error::UserDataTypeMismatch),
104        }
105    }
106
107    pub(crate) unsafe fn borrow_from_stack(
108        lua: &RawLua,
109        state: *mut ffi::lua_State,
110        idx: c_int,
111    ) -> Result<Self> {
112        let type_id = lua.get_userdata_type_id::<T>(state, idx)?;
113        match type_id {
114            Some(type_id) if type_id == TypeId::of::<T>() => {
115                let ud = get_userdata::<UserDataStorage<T>>(state, idx);
116                (*ud).try_borrow_owned()
117            }
118
119            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
120            Some(type_id) if type_id == TypeId::of::<Rc<T>>() => {
121                let ud = get_userdata::<UserDataStorage<Rc<T>>>(state, idx);
122                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_rc())
123            }
124            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
125            Some(type_id) if type_id == TypeId::of::<Rc<RefCell<T>>>() => {
126                let ud = get_userdata::<UserDataStorage<Rc<RefCell<T>>>>(state, idx);
127                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_rc_refcell())
128            }
129
130            #[cfg(feature = "userdata-wrappers")]
131            Some(type_id) if type_id == TypeId::of::<Arc<T>>() => {
132                let ud = get_userdata::<UserDataStorage<Arc<T>>>(state, idx);
133                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc())
134            }
135            #[cfg(feature = "userdata-wrappers")]
136            Some(type_id) if type_id == TypeId::of::<Arc<MutexPL<T>>>() => {
137                let ud = get_userdata::<UserDataStorage<Arc<MutexPL<T>>>>(state, idx);
138                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc_mutex_pl())
139            }
140            #[cfg(feature = "userdata-wrappers")]
141            Some(type_id) if type_id == TypeId::of::<Arc<RwLockPL<T>>>() => {
142                let ud = get_userdata::<UserDataStorage<Arc<RwLockPL<T>>>>(state, idx);
143                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc_rwlock_pl())
144            }
145            _ => Err(Error::UserDataTypeMismatch),
146        }
147    }
148}
149
150#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
151impl<T> UserDataRef<Rc<T>> {
152    fn transform_rc(self) -> Result<UserDataRef<T>> {
153        self.remap(|variant| Ok(UserDataRefInner::Rc(variant)))
154    }
155}
156
157#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
158impl<T> UserDataRef<Rc<RefCell<T>>> {
159    fn transform_rc_refcell(self) -> Result<UserDataRef<T>> {
160        self.remap(|variant| unsafe {
161            let obj = &*variant.as_ptr();
162            let r#ref = obj.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
163            let borrow = std::mem::transmute::<Ref<T>, Ref<'static, T>>(r#ref);
164            Ok(UserDataRefInner::RcRefCell(borrow, variant))
165        })
166    }
167}
168
169#[cfg(feature = "userdata-wrappers")]
170impl<T> UserDataRef<Arc<T>> {
171    fn transform_arc(self) -> Result<UserDataRef<T>> {
172        self.remap(|variant| Ok(UserDataRefInner::Arc(variant)))
173    }
174}
175
176#[cfg(feature = "userdata-wrappers")]
177impl<T> UserDataRef<Arc<MutexPL<T>>> {
178    fn transform_arc_mutex_pl(self) -> Result<UserDataRef<T>> {
179        self.remap(|variant| unsafe {
180            let obj = &*variant.as_ptr();
181            let guard = obj.try_lock().ok_or(Error::UserDataBorrowError)?;
182            let borrow = std::mem::transmute::<MutexGuardPL<T>, MutexGuardPL<'static, T>>(guard);
183            Ok(UserDataRefInner::ArcMutexPL(borrow, variant))
184        })
185    }
186}
187
188#[cfg(feature = "userdata-wrappers")]
189impl<T> UserDataRef<Arc<RwLockPL<T>>> {
190    fn transform_arc_rwlock_pl(self) -> Result<UserDataRef<T>> {
191        self.remap(|variant| unsafe {
192            let obj = &*variant.as_ptr();
193            let guard = obj.try_read().ok_or(Error::UserDataBorrowError)?;
194            let borrow = std::mem::transmute::<RwLockReadGuardPL<T>, RwLockReadGuardPL<'static, T>>(guard);
195            Ok(UserDataRefInner::ArcRwLockPL(borrow, variant))
196        })
197    }
198}
199
200#[allow(unused)]
201enum UserDataRefInner<T: 'static> {
202    Default(UserDataVariant<T>),
203
204    #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
205    Rc(UserDataVariant<Rc<T>>),
206    #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
207    RcRefCell(Ref<'static, T>, UserDataVariant<Rc<RefCell<T>>>),
208
209    #[cfg(feature = "userdata-wrappers")]
210    Arc(UserDataVariant<Arc<T>>),
211    #[cfg(feature = "userdata-wrappers")]
212    ArcMutexPL(MutexGuardPL<'static, T>, UserDataVariant<Arc<MutexPL<T>>>),
213    #[cfg(feature = "userdata-wrappers")]
214    ArcRwLockPL(RwLockReadGuardPL<'static, T>, UserDataVariant<Arc<RwLockPL<T>>>),
215}
216
217impl<T> Deref for UserDataRefInner<T> {
218    type Target = T;
219
220    #[inline]
221    fn deref(&self) -> &T {
222        match self {
223            Self::Default(inner) => unsafe { &*inner.as_ptr() },
224
225            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
226            Self::Rc(inner) => unsafe { &*Rc::as_ptr(&*inner.as_ptr()) },
227            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
228            Self::RcRefCell(x, ..) => x,
229
230            #[cfg(feature = "userdata-wrappers")]
231            Self::Arc(inner) => unsafe { &*Arc::as_ptr(&*inner.as_ptr()) },
232            #[cfg(feature = "userdata-wrappers")]
233            Self::ArcMutexPL(x, ..) => x,
234            #[cfg(feature = "userdata-wrappers")]
235            Self::ArcRwLockPL(x, ..) => x,
236        }
237    }
238}
239
240/// A wrapper type for a userdata value that provides read and write access.
241///
242/// It implements [`FromLua`] and can be used to receive a typed userdata from Lua.
243pub struct UserDataRefMut<T: 'static> {
244    // It's important to drop the guard first, as it refers to the `inner` data.
245    _guard: LockGuard<'static, RawLock>,
246    inner: UserDataRefMutInner<T>,
247}
248
249impl<T> Deref for UserDataRefMut<T> {
250    type Target = T;
251
252    #[inline]
253    fn deref(&self) -> &Self::Target {
254        &self.inner
255    }
256}
257
258impl<T> DerefMut for UserDataRefMut<T> {
259    #[inline]
260    fn deref_mut(&mut self) -> &mut Self::Target {
261        &mut self.inner
262    }
263}
264
265impl<T: fmt::Debug> fmt::Debug for UserDataRefMut<T> {
266    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267        (**self).fmt(f)
268    }
269}
270
271impl<T: fmt::Display> fmt::Display for UserDataRefMut<T> {
272    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273        (**self).fmt(f)
274    }
275}
276
277impl<T> TryFrom<UserDataVariant<T>> for UserDataRefMut<T> {
278    type Error = Error;
279
280    #[inline]
281    fn try_from(variant: UserDataVariant<T>) -> Result<Self> {
282        let guard = variant.raw_lock().try_lock_exclusive_guarded();
283        let guard = guard.map_err(|_| Error::UserDataBorrowMutError)?;
284        let guard = unsafe { mem::transmute::<LockGuard<_>, LockGuard<'static, _>>(guard) };
285        Ok(UserDataRefMut::from_parts(
286            UserDataRefMutInner::Default(variant),
287            guard,
288        ))
289    }
290}
291
292impl<T: 'static> FromLua for UserDataRefMut<T> {
293    fn from_lua(value: Value, _: &Lua) -> Result<Self> {
294        try_value_to_userdata::<T>(value)?.borrow_mut()
295    }
296
297    unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
298        Self::borrow_from_stack(lua, lua.state(), idx)
299    }
300}
301
302impl<T: 'static> UserDataRefMut<T> {
303    #[inline(always)]
304    fn from_parts(inner: UserDataRefMutInner<T>, guard: LockGuard<'static, RawLock>) -> Self {
305        Self { _guard: guard, inner }
306    }
307
308    #[cfg(feature = "userdata-wrappers")]
309    fn remap<U>(
310        self,
311        f: impl FnOnce(UserDataVariant<T>) -> Result<UserDataRefMutInner<U>>,
312    ) -> Result<UserDataRefMut<U>> {
313        match &self.inner {
314            UserDataRefMutInner::Default(variant) => {
315                let inner = f(variant.clone())?;
316                Ok(UserDataRefMut::from_parts(inner, self._guard))
317            }
318            _ => Err(Error::UserDataTypeMismatch),
319        }
320    }
321
322    pub(crate) unsafe fn borrow_from_stack(
323        lua: &RawLua,
324        state: *mut ffi::lua_State,
325        idx: c_int,
326    ) -> Result<Self> {
327        let type_id = lua.get_userdata_type_id::<T>(state, idx)?;
328        match type_id {
329            Some(type_id) if type_id == TypeId::of::<T>() => {
330                let ud = get_userdata::<UserDataStorage<T>>(state, idx);
331                (*ud).try_borrow_owned_mut()
332            }
333
334            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
335            Some(type_id) if type_id == TypeId::of::<Rc<T>>() => Err(Error::UserDataBorrowMutError),
336            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
337            Some(type_id) if type_id == TypeId::of::<Rc<RefCell<T>>>() => {
338                let ud = get_userdata::<UserDataStorage<Rc<RefCell<T>>>>(state, idx);
339                ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_rc_refcell())
340            }
341
342            #[cfg(feature = "userdata-wrappers")]
343            Some(type_id) if type_id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError),
344            #[cfg(feature = "userdata-wrappers")]
345            Some(type_id) if type_id == TypeId::of::<Arc<MutexPL<T>>>() => {
346                let ud = get_userdata::<UserDataStorage<Arc<MutexPL<T>>>>(state, idx);
347                ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_arc_mutex_pl())
348            }
349            #[cfg(feature = "userdata-wrappers")]
350            Some(type_id) if type_id == TypeId::of::<Arc<RwLockPL<T>>>() => {
351                let ud = get_userdata::<UserDataStorage<Arc<RwLockPL<T>>>>(state, idx);
352                ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_arc_rwlock_pl())
353            }
354            _ => Err(Error::UserDataTypeMismatch),
355        }
356    }
357}
358
359#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
360impl<T> UserDataRefMut<Rc<RefCell<T>>> {
361    fn transform_rc_refcell(self) -> Result<UserDataRefMut<T>> {
362        self.remap(|variant| unsafe {
363            let obj = &*variant.as_ptr();
364            let refmut = obj.try_borrow_mut().map_err(|_| Error::UserDataBorrowMutError)?;
365            let borrow = std::mem::transmute::<RefMut<T>, RefMut<'static, T>>(refmut);
366            Ok(UserDataRefMutInner::RcRefCell(borrow, variant))
367        })
368    }
369}
370
371#[cfg(feature = "userdata-wrappers")]
372impl<T> UserDataRefMut<Arc<MutexPL<T>>> {
373    fn transform_arc_mutex_pl(self) -> Result<UserDataRefMut<T>> {
374        self.remap(|variant| unsafe {
375            let obj = &*variant.as_ptr();
376            let guard = obj.try_lock().ok_or(Error::UserDataBorrowMutError)?;
377            let borrow = std::mem::transmute::<MutexGuardPL<T>, MutexGuardPL<'static, T>>(guard);
378            Ok(UserDataRefMutInner::ArcMutexPL(borrow, variant))
379        })
380    }
381}
382
383#[cfg(feature = "userdata-wrappers")]
384impl<T> UserDataRefMut<Arc<RwLockPL<T>>> {
385    fn transform_arc_rwlock_pl(self) -> Result<UserDataRefMut<T>> {
386        self.remap(|variant| unsafe {
387            let obj = &*variant.as_ptr();
388            let guard = obj.try_write().ok_or(Error::UserDataBorrowMutError)?;
389            let borrow = std::mem::transmute::<RwLockWriteGuardPL<T>, RwLockWriteGuardPL<'static, T>>(guard);
390            Ok(UserDataRefMutInner::ArcRwLockPL(borrow, variant))
391        })
392    }
393}
394
395#[allow(unused)]
396enum UserDataRefMutInner<T: 'static> {
397    Default(UserDataVariant<T>),
398
399    #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
400    RcRefCell(RefMut<'static, T>, UserDataVariant<Rc<RefCell<T>>>),
401
402    #[cfg(feature = "userdata-wrappers")]
403    ArcMutexPL(MutexGuardPL<'static, T>, UserDataVariant<Arc<MutexPL<T>>>),
404    #[cfg(feature = "userdata-wrappers")]
405    ArcRwLockPL(RwLockWriteGuardPL<'static, T>, UserDataVariant<Arc<RwLockPL<T>>>),
406}
407
408impl<T> Deref for UserDataRefMutInner<T> {
409    type Target = T;
410
411    #[inline]
412    fn deref(&self) -> &T {
413        match self {
414            Self::Default(inner) => unsafe { &*inner.as_ptr() },
415
416            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
417            Self::RcRefCell(x, ..) => x,
418
419            #[cfg(feature = "userdata-wrappers")]
420            Self::ArcMutexPL(x, ..) => x,
421            #[cfg(feature = "userdata-wrappers")]
422            Self::ArcRwLockPL(x, ..) => x,
423        }
424    }
425}
426
427impl<T> DerefMut for UserDataRefMutInner<T> {
428    #[inline]
429    fn deref_mut(&mut self) -> &mut T {
430        match self {
431            Self::Default(inner) => unsafe { &mut *inner.as_ptr() },
432
433            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
434            Self::RcRefCell(x, ..) => x,
435
436            #[cfg(feature = "userdata-wrappers")]
437            Self::ArcMutexPL(x, ..) => x,
438            #[cfg(feature = "userdata-wrappers")]
439            Self::ArcRwLockPL(x, ..) => x,
440        }
441    }
442}
443
444/// A wrapper type that takes ownership of a userdata value.
445///
446/// It implements [`FromLua`] and can be used to receive a typed userdata from Lua by taking
447/// ownership of it.
448/// The original Lua userdata is marked as destructed and cannot be used further.
449pub struct UserDataOwned<T>(pub T);
450
451impl<T> Deref for UserDataOwned<T> {
452    type Target = T;
453
454    #[inline]
455    fn deref(&self) -> &T {
456        &self.0
457    }
458}
459
460impl<T> DerefMut for UserDataOwned<T> {
461    #[inline]
462    fn deref_mut(&mut self) -> &mut T {
463        &mut self.0
464    }
465}
466
467impl<T: fmt::Debug> fmt::Debug for UserDataOwned<T> {
468    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469        (**self).fmt(f)
470    }
471}
472
473impl<T: fmt::Display> fmt::Display for UserDataOwned<T> {
474    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
475        (**self).fmt(f)
476    }
477}
478
479impl<T: 'static> FromLua for UserDataOwned<T> {
480    fn from_lua(value: Value, _: &Lua) -> Result<Self> {
481        try_value_to_userdata::<T>(value)?.take().map(UserDataOwned)
482    }
483
484    unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
485        let state = lua.state();
486        let type_id = lua.get_userdata_type_id::<T>(state, idx)?;
487        match type_id {
488            Some(type_id) if type_id == TypeId::of::<T>() => {
489                let ud = get_userdata::<UserDataStorage<T>>(state, idx);
490                if (*ud).has_exclusive_access() {
491                    check_stack(state, 1)?;
492                    take_userdata::<UserDataStorage<T>>(state, idx)
493                        .into_inner()
494                        .map(UserDataOwned)
495                } else {
496                    Err(Error::UserDataBorrowMutError)
497                }
498            }
499            _ => Err(Error::UserDataTypeMismatch),
500        }
501    }
502}
503
504#[inline]
505fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
506    match value {
507        Value::UserData(ud) => Ok(ud),
508        _ => Err(Error::from_lua_conversion(
509            value.type_name(),
510            "userdata",
511            format!("expected userdata of type {}", type_name::<T>()),
512        )),
513    }
514}
515
516#[cfg(test)]
517mod assertions {
518    use super::*;
519
520    #[cfg(feature = "send")]
521    static_assertions::assert_impl_all!(UserDataRef<()>: Send, Sync);
522    #[cfg(feature = "send")]
523    static_assertions::assert_not_impl_all!(UserDataRef<std::rc::Rc<()>>: Send, Sync);
524    #[cfg(feature = "send")]
525    static_assertions::assert_impl_all!(UserDataRefMut<()>: Sync, Send);
526    #[cfg(feature = "send")]
527    static_assertions::assert_not_impl_all!(UserDataRefMut<std::rc::Rc<()>>: Send, Sync);
528    #[cfg(feature = "send")]
529    static_assertions::assert_impl_all!(UserDataOwned<()>: Send, Sync);
530    #[cfg(feature = "send")]
531    static_assertions::assert_not_impl_all!(UserDataOwned<std::rc::Rc<()>>: Send, Sync);
532
533    #[cfg(not(feature = "send"))]
534    static_assertions::assert_not_impl_all!(UserDataRef<()>: Send, Sync);
535    #[cfg(not(feature = "send"))]
536    static_assertions::assert_not_impl_all!(UserDataRefMut<()>: Send, Sync);
537}