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::get_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 creation
67        // - without `send` feature, single-threaded access makes shared lock safe for any `T`
68        let guard = variant.raw_lock().try_lock_shared_guarded();
69        let guard = guard.map_err(|_| Error::UserDataBorrowError)?;
70        let guard = unsafe { mem::transmute::<LockGuard<_>, LockGuard<'static, _>>(guard) };
71        Ok(UserDataRef::from_parts(UserDataRefInner::Default(variant), guard))
72    }
73}
74
75impl<T: 'static> FromLua for UserDataRef<T> {
76    fn from_lua(value: Value, _: &Lua) -> Result<Self> {
77        try_value_to_userdata::<T>(value)?.borrow()
78    }
79
80    #[inline]
81    unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
82        Self::borrow_from_stack(lua, lua.state(), idx)
83    }
84}
85
86impl<T: 'static> UserDataRef<T> {
87    #[inline(always)]
88    fn from_parts(inner: UserDataRefInner<T>, guard: LockGuard<'static, RawLock>) -> Self {
89        Self { _guard: guard, inner }
90    }
91
92    #[cfg(feature = "userdata-wrappers")]
93    fn remap<U>(
94        self,
95        f: impl FnOnce(UserDataVariant<T>) -> Result<UserDataRefInner<U>>,
96    ) -> Result<UserDataRef<U>> {
97        match &self.inner {
98            UserDataRefInner::Default(variant) => {
99                let inner = f(variant.clone())?;
100                Ok(UserDataRef::from_parts(inner, self._guard))
101            }
102            _ => Err(Error::UserDataTypeMismatch),
103        }
104    }
105
106    pub(crate) unsafe fn borrow_from_stack(
107        lua: &RawLua,
108        state: *mut ffi::lua_State,
109        idx: c_int,
110    ) -> Result<Self> {
111        let type_id = lua.get_userdata_type_id::<T>(state, idx)?;
112        match type_id {
113            Some(type_id) if type_id == TypeId::of::<T>() => {
114                let ud = get_userdata::<UserDataStorage<T>>(state, idx);
115                (*ud).try_borrow_owned()
116            }
117
118            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
119            Some(type_id) if type_id == TypeId::of::<Rc<T>>() => {
120                let ud = get_userdata::<UserDataStorage<Rc<T>>>(state, idx);
121                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_rc())
122            }
123            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
124            Some(type_id) if type_id == TypeId::of::<Rc<RefCell<T>>>() => {
125                let ud = get_userdata::<UserDataStorage<Rc<RefCell<T>>>>(state, idx);
126                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_rc_refcell())
127            }
128
129            #[cfg(feature = "userdata-wrappers")]
130            Some(type_id) if type_id == TypeId::of::<Arc<T>>() => {
131                let ud = get_userdata::<UserDataStorage<Arc<T>>>(state, idx);
132                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc())
133            }
134            #[cfg(feature = "userdata-wrappers")]
135            Some(type_id) if type_id == TypeId::of::<Arc<MutexPL<T>>>() => {
136                let ud = get_userdata::<UserDataStorage<Arc<MutexPL<T>>>>(state, idx);
137                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc_mutex_pl())
138            }
139            #[cfg(feature = "userdata-wrappers")]
140            Some(type_id) if type_id == TypeId::of::<Arc<RwLockPL<T>>>() => {
141                let ud = get_userdata::<UserDataStorage<Arc<RwLockPL<T>>>>(state, idx);
142                ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc_rwlock_pl())
143            }
144            _ => Err(Error::UserDataTypeMismatch),
145        }
146    }
147}
148
149#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
150impl<T> UserDataRef<Rc<T>> {
151    fn transform_rc(self) -> Result<UserDataRef<T>> {
152        self.remap(|variant| Ok(UserDataRefInner::Rc(variant)))
153    }
154}
155
156#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
157impl<T> UserDataRef<Rc<RefCell<T>>> {
158    fn transform_rc_refcell(self) -> Result<UserDataRef<T>> {
159        self.remap(|variant| unsafe {
160            let obj = &*variant.as_ptr();
161            let r#ref = obj.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
162            let borrow = std::mem::transmute::<Ref<T>, Ref<'static, T>>(r#ref);
163            Ok(UserDataRefInner::RcRefCell(borrow, variant))
164        })
165    }
166}
167
168#[cfg(feature = "userdata-wrappers")]
169impl<T> UserDataRef<Arc<T>> {
170    fn transform_arc(self) -> Result<UserDataRef<T>> {
171        self.remap(|variant| Ok(UserDataRefInner::Arc(variant)))
172    }
173}
174
175#[cfg(feature = "userdata-wrappers")]
176impl<T> UserDataRef<Arc<MutexPL<T>>> {
177    fn transform_arc_mutex_pl(self) -> Result<UserDataRef<T>> {
178        self.remap(|variant| unsafe {
179            let obj = &*variant.as_ptr();
180            let guard = obj.try_lock().ok_or(Error::UserDataBorrowError)?;
181            let borrow = std::mem::transmute::<MutexGuardPL<T>, MutexGuardPL<'static, T>>(guard);
182            Ok(UserDataRefInner::ArcMutexPL(borrow, variant))
183        })
184    }
185}
186
187#[cfg(feature = "userdata-wrappers")]
188impl<T> UserDataRef<Arc<RwLockPL<T>>> {
189    fn transform_arc_rwlock_pl(self) -> Result<UserDataRef<T>> {
190        self.remap(|variant| unsafe {
191            let obj = &*variant.as_ptr();
192            let guard = obj.try_read().ok_or(Error::UserDataBorrowError)?;
193            let borrow = std::mem::transmute::<RwLockReadGuardPL<T>, RwLockReadGuardPL<'static, T>>(guard);
194            Ok(UserDataRefInner::ArcRwLockPL(borrow, variant))
195        })
196    }
197}
198
199#[allow(unused)]
200enum UserDataRefInner<T: 'static> {
201    Default(UserDataVariant<T>),
202
203    #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
204    Rc(UserDataVariant<Rc<T>>),
205    #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
206    RcRefCell(Ref<'static, T>, UserDataVariant<Rc<RefCell<T>>>),
207
208    #[cfg(feature = "userdata-wrappers")]
209    Arc(UserDataVariant<Arc<T>>),
210    #[cfg(feature = "userdata-wrappers")]
211    ArcMutexPL(MutexGuardPL<'static, T>, UserDataVariant<Arc<MutexPL<T>>>),
212    #[cfg(feature = "userdata-wrappers")]
213    ArcRwLockPL(RwLockReadGuardPL<'static, T>, UserDataVariant<Arc<RwLockPL<T>>>),
214}
215
216impl<T> Deref for UserDataRefInner<T> {
217    type Target = T;
218
219    #[inline]
220    fn deref(&self) -> &T {
221        match self {
222            Self::Default(inner) => unsafe { &*inner.as_ptr() },
223
224            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
225            Self::Rc(inner) => unsafe { &*Rc::as_ptr(&*inner.as_ptr()) },
226            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
227            Self::RcRefCell(x, ..) => x,
228
229            #[cfg(feature = "userdata-wrappers")]
230            Self::Arc(inner) => unsafe { &*Arc::as_ptr(&*inner.as_ptr()) },
231            #[cfg(feature = "userdata-wrappers")]
232            Self::ArcMutexPL(x, ..) => x,
233            #[cfg(feature = "userdata-wrappers")]
234            Self::ArcRwLockPL(x, ..) => x,
235        }
236    }
237}
238
239/// A wrapper type for a userdata value that provides read and write access.
240///
241/// It implements [`FromLua`] and can be used to receive a typed userdata from Lua.
242pub struct UserDataRefMut<T: 'static> {
243    // It's important to drop the guard first, as it refers to the `inner` data.
244    _guard: LockGuard<'static, RawLock>,
245    inner: UserDataRefMutInner<T>,
246}
247
248impl<T> Deref for UserDataRefMut<T> {
249    type Target = T;
250
251    #[inline]
252    fn deref(&self) -> &Self::Target {
253        &self.inner
254    }
255}
256
257impl<T> DerefMut for UserDataRefMut<T> {
258    #[inline]
259    fn deref_mut(&mut self) -> &mut Self::Target {
260        &mut self.inner
261    }
262}
263
264impl<T: fmt::Debug> fmt::Debug for UserDataRefMut<T> {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        (**self).fmt(f)
267    }
268}
269
270impl<T: fmt::Display> fmt::Display for UserDataRefMut<T> {
271    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272        (**self).fmt(f)
273    }
274}
275
276impl<T> TryFrom<UserDataVariant<T>> for UserDataRefMut<T> {
277    type Error = Error;
278
279    #[inline]
280    fn try_from(variant: UserDataVariant<T>) -> Result<Self> {
281        let guard = variant.raw_lock().try_lock_exclusive_guarded();
282        let guard = guard.map_err(|_| Error::UserDataBorrowMutError)?;
283        let guard = unsafe { mem::transmute::<LockGuard<_>, LockGuard<'static, _>>(guard) };
284        Ok(UserDataRefMut::from_parts(
285            UserDataRefMutInner::Default(variant),
286            guard,
287        ))
288    }
289}
290
291impl<T: 'static> FromLua for UserDataRefMut<T> {
292    fn from_lua(value: Value, _: &Lua) -> Result<Self> {
293        try_value_to_userdata::<T>(value)?.borrow_mut()
294    }
295
296    unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
297        Self::borrow_from_stack(lua, lua.state(), idx)
298    }
299}
300
301impl<T: 'static> UserDataRefMut<T> {
302    #[inline(always)]
303    fn from_parts(inner: UserDataRefMutInner<T>, guard: LockGuard<'static, RawLock>) -> Self {
304        Self { _guard: guard, inner }
305    }
306
307    #[cfg(feature = "userdata-wrappers")]
308    fn remap<U>(
309        self,
310        f: impl FnOnce(UserDataVariant<T>) -> Result<UserDataRefMutInner<U>>,
311    ) -> Result<UserDataRefMut<U>> {
312        match &self.inner {
313            UserDataRefMutInner::Default(variant) => {
314                let inner = f(variant.clone())?;
315                Ok(UserDataRefMut::from_parts(inner, self._guard))
316            }
317            _ => Err(Error::UserDataTypeMismatch),
318        }
319    }
320
321    pub(crate) unsafe fn borrow_from_stack(
322        lua: &RawLua,
323        state: *mut ffi::lua_State,
324        idx: c_int,
325    ) -> Result<Self> {
326        let type_id = lua.get_userdata_type_id::<T>(state, idx)?;
327        match type_id {
328            Some(type_id) if type_id == TypeId::of::<T>() => {
329                let ud = get_userdata::<UserDataStorage<T>>(state, idx);
330                (*ud).try_borrow_owned_mut()
331            }
332
333            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
334            Some(type_id) if type_id == TypeId::of::<Rc<T>>() => Err(Error::UserDataBorrowMutError),
335            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
336            Some(type_id) if type_id == TypeId::of::<Rc<RefCell<T>>>() => {
337                let ud = get_userdata::<UserDataStorage<Rc<RefCell<T>>>>(state, idx);
338                ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_rc_refcell())
339            }
340
341            #[cfg(feature = "userdata-wrappers")]
342            Some(type_id) if type_id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError),
343            #[cfg(feature = "userdata-wrappers")]
344            Some(type_id) if type_id == TypeId::of::<Arc<MutexPL<T>>>() => {
345                let ud = get_userdata::<UserDataStorage<Arc<MutexPL<T>>>>(state, idx);
346                ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_arc_mutex_pl())
347            }
348            #[cfg(feature = "userdata-wrappers")]
349            Some(type_id) if type_id == TypeId::of::<Arc<RwLockPL<T>>>() => {
350                let ud = get_userdata::<UserDataStorage<Arc<RwLockPL<T>>>>(state, idx);
351                ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_arc_rwlock_pl())
352            }
353            _ => Err(Error::UserDataTypeMismatch),
354        }
355    }
356}
357
358#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
359impl<T> UserDataRefMut<Rc<RefCell<T>>> {
360    fn transform_rc_refcell(self) -> Result<UserDataRefMut<T>> {
361        self.remap(|variant| unsafe {
362            let obj = &*variant.as_ptr();
363            let refmut = obj.try_borrow_mut().map_err(|_| Error::UserDataBorrowMutError)?;
364            let borrow = std::mem::transmute::<RefMut<T>, RefMut<'static, T>>(refmut);
365            Ok(UserDataRefMutInner::RcRefCell(borrow, variant))
366        })
367    }
368}
369
370#[cfg(feature = "userdata-wrappers")]
371impl<T> UserDataRefMut<Arc<MutexPL<T>>> {
372    fn transform_arc_mutex_pl(self) -> Result<UserDataRefMut<T>> {
373        self.remap(|variant| unsafe {
374            let obj = &*variant.as_ptr();
375            let guard = obj.try_lock().ok_or(Error::UserDataBorrowMutError)?;
376            let borrow = std::mem::transmute::<MutexGuardPL<T>, MutexGuardPL<'static, T>>(guard);
377            Ok(UserDataRefMutInner::ArcMutexPL(borrow, variant))
378        })
379    }
380}
381
382#[cfg(feature = "userdata-wrappers")]
383impl<T> UserDataRefMut<Arc<RwLockPL<T>>> {
384    fn transform_arc_rwlock_pl(self) -> Result<UserDataRefMut<T>> {
385        self.remap(|variant| unsafe {
386            let obj = &*variant.as_ptr();
387            let guard = obj.try_write().ok_or(Error::UserDataBorrowMutError)?;
388            let borrow = std::mem::transmute::<RwLockWriteGuardPL<T>, RwLockWriteGuardPL<'static, T>>(guard);
389            Ok(UserDataRefMutInner::ArcRwLockPL(borrow, variant))
390        })
391    }
392}
393
394#[allow(unused)]
395enum UserDataRefMutInner<T: 'static> {
396    Default(UserDataVariant<T>),
397
398    #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
399    RcRefCell(RefMut<'static, T>, UserDataVariant<Rc<RefCell<T>>>),
400
401    #[cfg(feature = "userdata-wrappers")]
402    ArcMutexPL(MutexGuardPL<'static, T>, UserDataVariant<Arc<MutexPL<T>>>),
403    #[cfg(feature = "userdata-wrappers")]
404    ArcRwLockPL(RwLockWriteGuardPL<'static, T>, UserDataVariant<Arc<RwLockPL<T>>>),
405}
406
407impl<T> Deref for UserDataRefMutInner<T> {
408    type Target = T;
409
410    #[inline]
411    fn deref(&self) -> &T {
412        match self {
413            Self::Default(inner) => unsafe { &*inner.as_ptr() },
414
415            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
416            Self::RcRefCell(x, ..) => x,
417
418            #[cfg(feature = "userdata-wrappers")]
419            Self::ArcMutexPL(x, ..) => x,
420            #[cfg(feature = "userdata-wrappers")]
421            Self::ArcRwLockPL(x, ..) => x,
422        }
423    }
424}
425
426impl<T> DerefMut for UserDataRefMutInner<T> {
427    #[inline]
428    fn deref_mut(&mut self) -> &mut T {
429        match self {
430            Self::Default(inner) => unsafe { &mut *inner.as_ptr() },
431
432            #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
433            Self::RcRefCell(x, ..) => x,
434
435            #[cfg(feature = "userdata-wrappers")]
436            Self::ArcMutexPL(x, ..) => x,
437            #[cfg(feature = "userdata-wrappers")]
438            Self::ArcRwLockPL(x, ..) => x,
439        }
440    }
441}
442
443#[inline]
444fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
445    match value {
446        Value::UserData(ud) => Ok(ud),
447        _ => Err(Error::from_lua_conversion(
448            value.type_name(),
449            "userdata",
450            format!("expected userdata of type {}", type_name::<T>()),
451        )),
452    }
453}
454
455#[cfg(test)]
456mod assertions {
457    use super::*;
458
459    #[cfg(feature = "send")]
460    static_assertions::assert_impl_all!(UserDataRef<()>: Send, Sync);
461    #[cfg(feature = "send")]
462    static_assertions::assert_not_impl_all!(UserDataRef<std::rc::Rc<()>>: Send, Sync);
463    #[cfg(feature = "send")]
464    static_assertions::assert_impl_all!(UserDataRefMut<()>: Sync, Send);
465    #[cfg(feature = "send")]
466    static_assertions::assert_not_impl_all!(UserDataRefMut<std::rc::Rc<()>>: Send, Sync);
467
468    #[cfg(not(feature = "send"))]
469    static_assertions::assert_not_impl_all!(UserDataRef<()>: Send, Sync);
470    #[cfg(not(feature = "send"))]
471    static_assertions::assert_not_impl_all!(UserDataRefMut<()>: Send, Sync);
472}