mlua/userdata/
ref.rs

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