use std::any::{type_name, TypeId}; use std::ops::{Deref, DerefMut}; use std::os::raw::c_int; use std::{fmt, mem}; use crate::error::{Error, Result}; use crate::state::{Lua, RawLua}; use crate::traits::FromLua; use crate::userdata::AnyUserData; use crate::util::get_userdata; use crate::value::Value; use super::cell::{UserDataStorage, UserDataVariant}; use super::lock::{LockGuard, RawLock, UserDataLock}; use super::util::is_sync; #[cfg(feature = "userdata-wrappers")] use { parking_lot::{ Mutex as MutexPL, MutexGuard as MutexGuardPL, RwLock as RwLockPL, RwLockReadGuard as RwLockReadGuardPL, RwLockWriteGuard as RwLockWriteGuardPL, }, std::sync::Arc, }; #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] use { std::cell::{Ref, RefCell, RefMut}, std::rc::Rc, }; /// A wrapper type for a userdata value that provides read access. /// /// It implements [`FromLua`] and can be used to receive a typed userdata from Lua. pub struct UserDataRef { // It's important to drop the guard first, as it refers to the `inner` data. _guard: LockGuard<'static, RawLock>, inner: UserDataRefInner, } impl Deref for UserDataRef { type Target = T; #[inline] fn deref(&self) -> &T { &self.inner } } impl fmt::Debug for UserDataRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl fmt::Display for UserDataRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl TryFrom> for UserDataRef { type Error = Error; #[inline] fn try_from(variant: UserDataVariant) -> Result { let guard = if !cfg!(feature = "send") || is_sync::() { variant.raw_lock().try_lock_shared_guarded() } else { variant.raw_lock().try_lock_exclusive_guarded() }; let guard = guard.map_err(|_| Error::UserDataBorrowError)?; let guard = unsafe { mem::transmute::, LockGuard<'static, _>>(guard) }; Ok(UserDataRef::from_parts(UserDataRefInner::Default(variant), guard)) } } impl FromLua for UserDataRef { fn from_lua(value: Value, _: &Lua) -> Result { try_value_to_userdata::(value)?.borrow() } #[inline] unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result { Self::borrow_from_stack(lua, lua.state(), idx) } } impl UserDataRef { #[inline(always)] fn from_parts(inner: UserDataRefInner, guard: LockGuard<'static, RawLock>) -> Self { Self { _guard: guard, inner } } #[cfg(feature = "userdata-wrappers")] fn remap( self, f: impl FnOnce(UserDataVariant) -> Result>, ) -> Result> { match &self.inner { UserDataRefInner::Default(variant) => { let inner = f(variant.clone())?; Ok(UserDataRef::from_parts(inner, self._guard)) } _ => Err(Error::UserDataTypeMismatch), } } pub(crate) unsafe fn borrow_from_stack( lua: &RawLua, state: *mut ffi::lua_State, idx: c_int, ) -> Result { let type_id = lua.get_userdata_type_id::(state, idx)?; match type_id { Some(type_id) if type_id == TypeId::of::() => { let ud = get_userdata::>(state, idx); (*ud).try_borrow_owned() } #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Some(type_id) if type_id == TypeId::of::>() => { let ud = get_userdata::>>(state, idx); ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_rc()) } #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Some(type_id) if type_id == TypeId::of::>>() => { let ud = get_userdata::>>>(state, idx); ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_rc_refcell()) } #[cfg(feature = "userdata-wrappers")] Some(type_id) if type_id == TypeId::of::>() => { let ud = get_userdata::>>(state, idx); ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc()) } #[cfg(feature = "userdata-wrappers")] Some(type_id) if type_id == TypeId::of::>>() => { let ud = get_userdata::>>>(state, idx); ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc_mutex_pl()) } #[cfg(feature = "userdata-wrappers")] Some(type_id) if type_id == TypeId::of::>>() => { let ud = get_userdata::>>>(state, idx); ((*ud).try_borrow_owned()).and_then(|ud| ud.transform_arc_rwlock_pl()) } _ => Err(Error::UserDataTypeMismatch), } } } #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] impl UserDataRef> { fn transform_rc(self) -> Result> { self.remap(|variant| Ok(UserDataRefInner::Rc(variant))) } } #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] impl UserDataRef>> { fn transform_rc_refcell(self) -> Result> { self.remap(|variant| unsafe { let obj = &*variant.as_ptr(); let r#ref = obj.try_borrow().map_err(|_| Error::UserDataBorrowError)?; let borrow = std::mem::transmute::, Ref<'static, T>>(r#ref); Ok(UserDataRefInner::RcRefCell(borrow, variant)) }) } } #[cfg(feature = "userdata-wrappers")] impl UserDataRef> { fn transform_arc(self) -> Result> { self.remap(|variant| Ok(UserDataRefInner::Arc(variant))) } } #[cfg(feature = "userdata-wrappers")] impl UserDataRef>> { fn transform_arc_mutex_pl(self) -> Result> { self.remap(|variant| unsafe { let obj = &*variant.as_ptr(); let guard = obj.try_lock().ok_or(Error::UserDataBorrowError)?; let borrow = std::mem::transmute::, MutexGuardPL<'static, T>>(guard); Ok(UserDataRefInner::ArcMutexPL(borrow, variant)) }) } } #[cfg(feature = "userdata-wrappers")] impl UserDataRef>> { fn transform_arc_rwlock_pl(self) -> Result> { self.remap(|variant| unsafe { let obj = &*variant.as_ptr(); let guard = obj.try_read().ok_or(Error::UserDataBorrowError)?; let borrow = std::mem::transmute::, RwLockReadGuardPL<'static, T>>(guard); Ok(UserDataRefInner::ArcRwLockPL(borrow, variant)) }) } } #[allow(unused)] enum UserDataRefInner { Default(UserDataVariant), #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Rc(UserDataVariant>), #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] RcRefCell(Ref<'static, T>, UserDataVariant>>), #[cfg(feature = "userdata-wrappers")] Arc(UserDataVariant>), #[cfg(feature = "userdata-wrappers")] ArcMutexPL(MutexGuardPL<'static, T>, UserDataVariant>>), #[cfg(feature = "userdata-wrappers")] ArcRwLockPL(RwLockReadGuardPL<'static, T>, UserDataVariant>>), } impl Deref for UserDataRefInner { type Target = T; #[inline] fn deref(&self) -> &T { match self { Self::Default(inner) => unsafe { &*inner.as_ptr() }, #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Self::Rc(inner) => unsafe { &*Rc::as_ptr(&*inner.as_ptr()) }, #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Self::RcRefCell(x, ..) => x, #[cfg(feature = "userdata-wrappers")] Self::Arc(inner) => unsafe { &*Arc::as_ptr(&*inner.as_ptr()) }, #[cfg(feature = "userdata-wrappers")] Self::ArcMutexPL(x, ..) => x, #[cfg(feature = "userdata-wrappers")] Self::ArcRwLockPL(x, ..) => x, } } } /// A wrapper type for a userdata value that provides read and write access. /// /// It implements [`FromLua`] and can be used to receive a typed userdata from Lua. pub struct UserDataRefMut { // It's important to drop the guard first, as it refers to the `inner` data. _guard: LockGuard<'static, RawLock>, inner: UserDataRefMutInner, } impl Deref for UserDataRefMut { type Target = T; #[inline] fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for UserDataRefMut { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl fmt::Debug for UserDataRefMut { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl fmt::Display for UserDataRefMut { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl TryFrom> for UserDataRefMut { type Error = Error; #[inline] fn try_from(variant: UserDataVariant) -> Result { let guard = variant.raw_lock().try_lock_exclusive_guarded(); let guard = guard.map_err(|_| Error::UserDataBorrowMutError)?; let guard = unsafe { mem::transmute::, LockGuard<'static, _>>(guard) }; Ok(UserDataRefMut::from_parts( UserDataRefMutInner::Default(variant), guard, )) } } impl FromLua for UserDataRefMut { fn from_lua(value: Value, _: &Lua) -> Result { try_value_to_userdata::(value)?.borrow_mut() } unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result { Self::borrow_from_stack(lua, lua.state(), idx) } } impl UserDataRefMut { #[inline(always)] fn from_parts(inner: UserDataRefMutInner, guard: LockGuard<'static, RawLock>) -> Self { Self { _guard: guard, inner } } #[cfg(feature = "userdata-wrappers")] fn remap( self, f: impl FnOnce(UserDataVariant) -> Result>, ) -> Result> { match &self.inner { UserDataRefMutInner::Default(variant) => { let inner = f(variant.clone())?; Ok(UserDataRefMut::from_parts(inner, self._guard)) } _ => Err(Error::UserDataTypeMismatch), } } pub(crate) unsafe fn borrow_from_stack( lua: &RawLua, state: *mut ffi::lua_State, idx: c_int, ) -> Result { let type_id = lua.get_userdata_type_id::(state, idx)?; match type_id { Some(type_id) if type_id == TypeId::of::() => { let ud = get_userdata::>(state, idx); (*ud).try_borrow_owned_mut() } #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Some(type_id) if type_id == TypeId::of::>() => Err(Error::UserDataBorrowMutError), #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Some(type_id) if type_id == TypeId::of::>>() => { let ud = get_userdata::>>>(state, idx); ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_rc_refcell()) } #[cfg(feature = "userdata-wrappers")] Some(type_id) if type_id == TypeId::of::>() => Err(Error::UserDataBorrowMutError), #[cfg(feature = "userdata-wrappers")] Some(type_id) if type_id == TypeId::of::>>() => { let ud = get_userdata::>>>(state, idx); ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_arc_mutex_pl()) } #[cfg(feature = "userdata-wrappers")] Some(type_id) if type_id == TypeId::of::>>() => { let ud = get_userdata::>>>(state, idx); ((*ud).try_borrow_owned_mut()).and_then(|ud| ud.transform_arc_rwlock_pl()) } _ => Err(Error::UserDataTypeMismatch), } } } #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] impl UserDataRefMut>> { fn transform_rc_refcell(self) -> Result> { self.remap(|variant| unsafe { let obj = &*variant.as_ptr(); let refmut = obj.try_borrow_mut().map_err(|_| Error::UserDataBorrowMutError)?; let borrow = std::mem::transmute::, RefMut<'static, T>>(refmut); Ok(UserDataRefMutInner::RcRefCell(borrow, variant)) }) } } #[cfg(feature = "userdata-wrappers")] impl UserDataRefMut>> { fn transform_arc_mutex_pl(self) -> Result> { self.remap(|variant| unsafe { let obj = &*variant.as_ptr(); let guard = obj.try_lock().ok_or(Error::UserDataBorrowMutError)?; let borrow = std::mem::transmute::, MutexGuardPL<'static, T>>(guard); Ok(UserDataRefMutInner::ArcMutexPL(borrow, variant)) }) } } #[cfg(feature = "userdata-wrappers")] impl UserDataRefMut>> { fn transform_arc_rwlock_pl(self) -> Result> { self.remap(|variant| unsafe { let obj = &*variant.as_ptr(); let guard = obj.try_write().ok_or(Error::UserDataBorrowMutError)?; let borrow = std::mem::transmute::, RwLockWriteGuardPL<'static, T>>(guard); Ok(UserDataRefMutInner::ArcRwLockPL(borrow, variant)) }) } } #[allow(unused)] enum UserDataRefMutInner { Default(UserDataVariant), #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] RcRefCell(RefMut<'static, T>, UserDataVariant>>), #[cfg(feature = "userdata-wrappers")] ArcMutexPL(MutexGuardPL<'static, T>, UserDataVariant>>), #[cfg(feature = "userdata-wrappers")] ArcRwLockPL(RwLockWriteGuardPL<'static, T>, UserDataVariant>>), } impl Deref for UserDataRefMutInner { type Target = T; #[inline] fn deref(&self) -> &T { match self { Self::Default(inner) => unsafe { &*inner.as_ptr() }, #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Self::RcRefCell(x, ..) => x, #[cfg(feature = "userdata-wrappers")] Self::ArcMutexPL(x, ..) => x, #[cfg(feature = "userdata-wrappers")] Self::ArcRwLockPL(x, ..) => x, } } } impl DerefMut for UserDataRefMutInner { #[inline] fn deref_mut(&mut self) -> &mut T { match self { Self::Default(inner) => unsafe { &mut *inner.as_ptr() }, #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] Self::RcRefCell(x, ..) => x, #[cfg(feature = "userdata-wrappers")] Self::ArcMutexPL(x, ..) => x, #[cfg(feature = "userdata-wrappers")] Self::ArcRwLockPL(x, ..) => x, } } } #[inline] fn try_value_to_userdata(value: Value) -> Result { match value { Value::UserData(ud) => Ok(ud), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "userdata".to_string(), message: Some(format!("expected userdata of type {}", type_name::())), }), } } #[cfg(test)] mod assertions { use super::*; #[cfg(feature = "send")] static_assertions::assert_impl_all!(UserDataRef<()>: Send, Sync); #[cfg(feature = "send")] static_assertions::assert_not_impl_all!(UserDataRef>: Send, Sync); #[cfg(feature = "send")] static_assertions::assert_impl_all!(UserDataRefMut<()>: Sync, Send); #[cfg(feature = "send")] static_assertions::assert_not_impl_all!(UserDataRefMut>: Send, Sync); #[cfg(not(feature = "send"))] static_assertions::assert_not_impl_all!(UserDataRef<()>: Send, Sync); #[cfg(not(feature = "send"))] static_assertions::assert_not_impl_all!(UserDataRefMut<()>: Send, Sync); }