1use std::any::{Any, TypeId};
2use std::cell::{BorrowError, BorrowMutError, Cell, Ref, RefCell, RefMut, UnsafeCell};
3use std::fmt;
4use std::ops::{Deref, DerefMut};
5use std::result::Result as StdResult;
6
7use rustc_hash::FxHashMap;
8
9use super::MaybeSend;
10use crate::state::LuaGuard;
11
12#[cfg(not(feature = "send"))]
13type Container = UnsafeCell<FxHashMap<TypeId, RefCell<Box<dyn Any>>>>;
14
15#[cfg(feature = "send")]
16type Container = UnsafeCell<FxHashMap<TypeId, RefCell<Box<dyn Any + Send>>>>;
17
18#[derive(Debug, Default)]
20pub struct AppData {
21 container: Container,
22 borrow: Cell<usize>,
23}
24
25impl AppData {
26 #[track_caller]
27 pub(crate) fn insert<T: MaybeSend + 'static>(&self, data: T) -> Option<T> {
28 match self.try_insert(data) {
29 Ok(data) => data,
30 Err(_) => panic!("cannot mutably borrow app data container"),
31 }
32 }
33
34 pub(crate) fn try_insert<T: MaybeSend + 'static>(&self, data: T) -> StdResult<Option<T>, T> {
35 if self.borrow.get() != 0 {
36 return Err(data);
37 }
38 Ok(unsafe { &mut *self.container.get() }
40 .insert(TypeId::of::<T>(), RefCell::new(Box::new(data)))
41 .and_then(|data| data.into_inner().downcast::<T>().ok().map(|data| *data)))
42 }
43
44 #[inline]
45 #[track_caller]
46 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> {
57 let data = unsafe { &*self.container.get() }
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 }
73 }
74
75 #[inline]
76 #[track_caller]
77 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> {
88 let data = unsafe { &*self.container.get() }
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 }
104 }
105
106 #[track_caller]
107 pub(crate) fn remove<T: 'static>(&self) -> Option<T> {
108 if self.borrow.get() != 0 {
109 panic!("cannot mutably borrow app data container");
110 }
111 unsafe { &mut *self.container.get() }
113 .remove(&TypeId::of::<T>())?
114 .into_inner()
115 .downcast::<T>()
116 .ok()
117 .map(|data| *data)
118 }
119}
120
121pub struct AppDataRef<'a, T: ?Sized + 'a> {
125 data: Ref<'a, T>,
126 borrow: &'a Cell<usize>,
127 _guard: Option<LuaGuard>,
128}
129
130impl<T: ?Sized> Drop for AppDataRef<'_, T> {
131 fn drop(&mut self) {
132 self.borrow.set(self.borrow.get() - 1);
133 }
134}
135
136impl<T: ?Sized> Deref for AppDataRef<'_, T> {
137 type Target = T;
138
139 #[inline]
140 fn deref(&self) -> &Self::Target {
141 &self.data
142 }
143}
144
145impl<T: ?Sized + fmt::Display> fmt::Display for AppDataRef<'_, T> {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 (**self).fmt(f)
148 }
149}
150
151impl<T: ?Sized + fmt::Debug> fmt::Debug for AppDataRef<'_, T> {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 (**self).fmt(f)
154 }
155}
156
157pub struct AppDataRefMut<'a, T: ?Sized + 'a> {
161 data: RefMut<'a, T>,
162 borrow: &'a Cell<usize>,
163 _guard: Option<LuaGuard>,
164}
165
166impl<T: ?Sized> Drop for AppDataRefMut<'_, T> {
167 fn drop(&mut self) {
168 self.borrow.set(self.borrow.get() - 1);
169 }
170}
171
172impl<T: ?Sized> Deref for AppDataRefMut<'_, T> {
173 type Target = T;
174
175 #[inline]
176 fn deref(&self) -> &Self::Target {
177 &self.data
178 }
179}
180
181impl<T: ?Sized> DerefMut for AppDataRefMut<'_, T> {
182 #[inline]
183 fn deref_mut(&mut self) -> &mut Self::Target {
184 &mut self.data
185 }
186}
187
188impl<T: ?Sized + fmt::Display> fmt::Display for AppDataRefMut<'_, T> {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 (**self).fmt(f)
191 }
192}
193
194impl<T: ?Sized + fmt::Debug> fmt::Debug for AppDataRefMut<'_, T> {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 (**self).fmt(f)
197 }
198}
199
200#[cfg(test)]
201mod assertions {
202 use super::*;
203
204 #[cfg(not(feature = "send"))]
205 static_assertions::assert_not_impl_any!(AppData: Send);
206 #[cfg(feature = "send")]
207 static_assertions::assert_impl_all!(AppData: Send);
208
209 static_assertions::assert_not_impl_any!(AppDataRef<()>: Send);
211 static_assertions::assert_not_impl_any!(AppDataRefMut<()>: Send);
212}