Skip to content

Commit a8d5f23

Browse files
committed
Add Lua::try_app_data_ref and Lua::try_app_data_mut
1 parent 5ec4e03 commit a8d5f23

File tree

3 files changed

+72
-18
lines changed

3 files changed

+72
-18
lines changed

src/state.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::any::TypeId;
2-
use std::cell::RefCell;
2+
use std::cell::{BorrowError, BorrowMutError, RefCell};
33
use std::marker::PhantomData;
44
use std::ops::Deref;
55
use std::os::raw::c_int;
@@ -1854,6 +1854,14 @@ impl Lua {
18541854
extra.app_data.borrow(Some(guard))
18551855
}
18561856

1857+
/// Tries to get a reference to an application data object stored by [`Lua::set_app_data`] of
1858+
/// type `T`.
1859+
pub fn try_app_data_ref<T: 'static>(&self) -> StdResult<Option<AppDataRef<T>>, BorrowError> {
1860+
let guard = self.lock_arc();
1861+
let extra = unsafe { &*guard.extra.get() };
1862+
extra.app_data.try_borrow(Some(guard))
1863+
}
1864+
18571865
/// Gets a mutable reference to an application data object stored by [`Lua::set_app_data`] of
18581866
/// type `T`.
18591867
///
@@ -1867,6 +1875,14 @@ impl Lua {
18671875
extra.app_data.borrow_mut(Some(guard))
18681876
}
18691877

1878+
/// Tries to get a mutable reference to an application data object stored by
1879+
/// [`Lua::set_app_data`] of type `T`.
1880+
pub fn try_app_data_mut<T: 'static>(&self) -> StdResult<Option<AppDataRefMut<T>>, BorrowMutError> {
1881+
let guard = self.lock_arc();
1882+
let extra = unsafe { &*guard.extra.get() };
1883+
extra.app_data.try_borrow_mut(Some(guard))
1884+
}
1885+
18701886
/// Removes an application data of type `T`.
18711887
///
18721888
/// # Panics

src/types/app_data.rs

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::any::{Any, TypeId};
2-
use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
2+
use std::cell::{BorrowError, BorrowMutError, Cell, Ref, RefCell, RefMut, UnsafeCell};
33
use std::fmt;
44
use std::ops::{Deref, DerefMut};
55
use std::result::Result as StdResult;
@@ -41,30 +41,66 @@ impl AppData {
4141
.and_then(|data| data.into_inner().downcast::<T>().ok().map(|data| *data)))
4242
}
4343

44+
#[inline]
4445
#[track_caller]
4546
pub(crate) fn borrow<T: 'static>(&self, guard: Option<LuaGuard>) -> Option<AppDataRef<T>> {
47+
match self.try_borrow(guard) {
48+
Ok(data) => data,
49+
Err(err) => panic!("already mutably borrowed: {err:?}"),
50+
}
51+
}
52+
53+
pub(crate) fn try_borrow<T: 'static>(
54+
&self,
55+
guard: Option<LuaGuard>,
56+
) -> Result<Option<AppDataRef<T>>, BorrowError> {
4657
let data = unsafe { &*self.container.get() }
47-
.get(&TypeId::of::<T>())?
48-
.borrow();
49-
self.borrow.set(self.borrow.get() + 1);
50-
Some(AppDataRef {
51-
data: Ref::filter_map(data, |data| data.downcast_ref()).ok()?,
52-
borrow: &self.borrow,
53-
_guard: guard,
54-
})
58+
.get(&TypeId::of::<T>())
59+
.map(|c| c.try_borrow())
60+
.transpose()?
61+
.and_then(|data| Ref::filter_map(data, |data| data.downcast_ref()).ok());
62+
match data {
63+
Some(data) => {
64+
self.borrow.set(self.borrow.get() + 1);
65+
Ok(Some(AppDataRef {
66+
data,
67+
borrow: &self.borrow,
68+
_guard: guard,
69+
}))
70+
}
71+
None => Ok(None),
72+
}
5573
}
5674

75+
#[inline]
5776
#[track_caller]
5877
pub(crate) fn borrow_mut<T: 'static>(&self, guard: Option<LuaGuard>) -> Option<AppDataRefMut<T>> {
78+
match self.try_borrow_mut(guard) {
79+
Ok(data) => data,
80+
Err(err) => panic!("already borrowed: {err:?}"),
81+
}
82+
}
83+
84+
pub(crate) fn try_borrow_mut<T: 'static>(
85+
&self,
86+
guard: Option<LuaGuard>,
87+
) -> Result<Option<AppDataRefMut<T>>, BorrowMutError> {
5988
let data = unsafe { &*self.container.get() }
60-
.get(&TypeId::of::<T>())?
61-
.borrow_mut();
62-
self.borrow.set(self.borrow.get() + 1);
63-
Some(AppDataRefMut {
64-
data: RefMut::filter_map(data, |data| data.downcast_mut()).ok()?,
65-
borrow: &self.borrow,
66-
_guard: guard,
67-
})
89+
.get(&TypeId::of::<T>())
90+
.map(|c| c.try_borrow_mut())
91+
.transpose()?
92+
.and_then(|data| RefMut::filter_map(data, |data| data.downcast_mut()).ok());
93+
match data {
94+
Some(data) => {
95+
self.borrow.set(self.borrow.get() + 1);
96+
Ok(Some(AppDataRefMut {
97+
data,
98+
borrow: &self.borrow,
99+
_guard: guard,
100+
}))
101+
}
102+
None => Ok(None),
103+
}
68104
}
69105

70106
#[track_caller]

tests/tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,10 +844,12 @@ fn test_application_data() -> Result<()> {
844844
assert_eq!(format!("{s:?}"), "\"test1\"");
845845

846846
// Borrowing immutably and mutably of the same type is not allowed
847+
assert!(lua.try_app_data_mut::<&str>().is_err());
847848
match catch_unwind(AssertUnwindSafe(|| lua.app_data_mut::<&str>().unwrap())) {
848849
Ok(_) => panic!("expected panic"),
849850
Err(_) => {}
850851
}
852+
assert!(lua.try_app_data_ref::<Vec<&str>>().is_err());
851853
drop((s, v));
852854

853855
// Test that application data is accessible from anywhere

0 commit comments

Comments
 (0)