1use rustc_hash::FxHashMap;
14use snafu::prelude::*;
15
16use std::{
17 any::{Any, TypeId},
18 ops::{Deref, DerefMut},
19 sync::{Arc, Mutex},
20};
21
22#[cfg(doctest)]
23pub mod doctest {
24 #[doc = include_str!("../README.md")]
25 pub struct ReadmeDoctests;
26}
27
28#[derive(Debug, Snafu)]
29pub enum BroomdogErr {
30 #[snafu(display("Cannot downcast_ref from {} to {to}", from.unwrap_or_else(|| "unknown")))]
31 DowncastRef {
32 from: Option<&'static str>,
33 to: &'static str,
34 },
35
36 #[snafu(display("Cannot downcast_mut from {} to {to}", from.unwrap_or_else(|| "unknown")))]
37 DowncastMut {
38 from: Option<&'static str>,
39 to: &'static str,
40 },
41
42 #[snafu(display("The type of a new value '{new_type}' doesn't match the type of an old value '{}'", old_type.unwrap_or_else(|| "unknown")))]
43 Mismatch {
44 new_type: &'static str,
45 old_type: Option<&'static str>,
46 },
47
48 #[snafu(display("Values are still on loan: {}", loans.iter().map(|k| k.name()).collect::<Vec<_>>().join(", ")))]
49 Unify { loans: Vec<TypeKey> },
50
51 #[snafu(display("Type {name} is already exclusively loaned"))]
52 ExclusiveLoan { name: &'static str },
53
54 #[snafu(display("Type {name} is already loaned"))]
55 Loan { name: &'static str },
56
57 #[snafu(display("Types are still loaned: \n{}", names.concat()))]
58 ManyLoans { names: Vec<&'static str> },
59}
60
61#[derive(Clone, Copy, Debug)]
63pub struct TypeKey {
64 type_id: TypeId,
65 #[cfg(debug_assertions)]
66 type_name: &'static str,
67}
68
69impl std::fmt::Display for TypeKey {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 #[cfg(debug_assertions)]
72 {
73 f.write_str(self.type_name)
74 }
75 #[cfg(not(debug_assertions))]
76 {
77 f.write_str("_")
78 }
79 }
80}
81
82impl std::hash::Hash for TypeKey {
83 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
84 self.type_id.hash(state);
85 }
86}
87
88impl PartialEq for TypeKey {
89 fn eq(&self, other: &Self) -> bool {
90 self.type_id == other.type_id
91 }
92}
93
94impl Eq for TypeKey {}
95
96impl TypeKey {
97 pub fn new<T: Any + Send + Sync>() -> Self {
99 TypeKey {
100 type_id: TypeId::of::<T>(),
101 #[cfg(debug_assertions)]
102 type_name: std::any::type_name::<T>(),
103 }
104 }
105
106 pub const fn name(&self) -> &'static str {
109 #[cfg(debug_assertions)]
110 {
111 self.type_name
112 }
113 #[cfg(not(debug_assertions))]
114 {
115 "unknown"
116 }
117 }
118}
119
120#[derive(Debug)]
122pub struct TypeValue {
123 inner: Box<dyn Any + Send + Sync>,
124 #[cfg(debug_assertions)]
125 type_name: &'static str,
126}
127
128impl<T: Any + Send + Sync> From<Box<T>> for TypeValue {
129 fn from(inner: Box<T>) -> Self {
130 TypeValue {
131 inner,
132 #[cfg(debug_assertions)]
133 type_name: std::any::type_name::<T>(),
134 }
135 }
136}
137
138impl TypeValue {
139 pub fn new<T: Any + Send + Sync>(value: T) -> Self {
141 TypeValue::from(Box::new(value))
142 }
143
144 pub fn type_name(&self) -> Option<&'static str> {
148 #[cfg(debug_assertions)]
149 {
150 Some(self.type_name)
151 }
152 #[cfg(not(debug_assertions))]
153 {
154 None
155 }
156 }
157
158 pub fn downcast<T: Any + Send + Sync + 'static>(
162 self,
163 ) -> std::result::Result<Box<T>, TypeValue> {
164 self.inner.downcast::<T>().map_err(|inner| TypeValue {
165 inner,
166 #[cfg(debug_assertions)]
167 type_name: self.type_name,
168 })
169 }
170
171 pub fn downcast_ref<T: Any + Send + Sync + 'static>(
173 &self,
174 ) -> std::result::Result<&T, BroomdogErr> {
175 self.inner
176 .downcast_ref::<T>()
177 .with_context(|| DowncastRefSnafu {
178 from: self.type_name(),
179 to: std::any::type_name::<T>(),
180 })
181 }
182
183 pub fn downcast_mut<T: Any + Send + Sync + 'static>(
185 &mut self,
186 ) -> std::result::Result<&mut T, BroomdogErr> {
187 let from = self.type_name();
188 self.inner
189 .downcast_mut::<T>()
190 .with_context(move || DowncastMutSnafu {
191 from,
192 to: std::any::type_name::<T>(),
193 })
194 }
195}
196
197pub struct Loan {
199 inner: Arc<TypeValue>,
200}
201
202impl Deref for Loan {
203 type Target = TypeValue;
204
205 fn deref(&self) -> &Self::Target {
206 &self.inner
207 }
208}
209
210pub struct LoanMut {
215 inner: Option<TypeValue>,
216 outer: Arc<Mutex<Option<TypeValue>>>,
217}
218
219impl Drop for LoanMut {
220 fn drop(&mut self) {
221 let inner = self.inner.take().unwrap();
223 let mut outer = self.outer.lock().unwrap();
224 *outer = Some(inner);
225 }
226}
227
228impl Deref for LoanMut {
229 type Target = TypeValue;
230
231 fn deref(&self) -> &Self::Target {
232 self.inner.as_ref().unwrap()
234 }
235}
236
237impl DerefMut for LoanMut {
238 fn deref_mut(&mut self) -> &mut Self::Target {
239 self.inner.as_mut().unwrap()
241 }
242}
243
244#[derive(Debug)]
246pub enum InnerLoan {
247 Owned(TypeValue),
249 Loan(Arc<TypeValue>),
251 LoanMut(Arc<Mutex<Option<TypeValue>>>),
253}
254
255impl From<TypeValue> for InnerLoan {
256 fn from(value: TypeValue) -> Self {
257 InnerLoan::Owned(value)
258 }
259}
260
261impl InnerLoan {
262 pub fn is_owned(&self) -> bool {
263 matches!(self, InnerLoan::Owned(_))
264 }
265
266 pub fn as_owned(&self, name: &'static str) -> std::result::Result<&TypeValue, BroomdogErr> {
267 match self {
268 InnerLoan::Owned(a) => Ok(a),
269 InnerLoan::Loan(_) => Err(BroomdogErr::Loan { name }),
270 InnerLoan::LoanMut(_) => Err(BroomdogErr::ExclusiveLoan { name }),
271 }
272 }
273
274 pub fn as_owned_mut(
275 &mut self,
276 name: &'static str,
277 ) -> std::result::Result<&mut TypeValue, BroomdogErr> {
278 match self {
279 InnerLoan::Owned(a) => Ok(a),
280 InnerLoan::Loan(_) => Err(BroomdogErr::Loan { name }),
281 InnerLoan::LoanMut(_) => Err(BroomdogErr::ExclusiveLoan { name }),
282 }
283 }
284
285 pub fn into_owned(self, name: &'static str) -> std::result::Result<TypeValue, InnerLoan> {
286 match self {
287 InnerLoan::Owned(value) => Ok(value),
288 InnerLoan::Loan(arc) => match Arc::try_unwrap(arc) {
289 Ok(value) => {
290 log::trace!("unified {name}");
291 Ok(value)
292 }
293 Err(arc) => Err(InnerLoan::Loan(arc)),
294 },
295 InnerLoan::LoanMut(arc_mut_opt) => {
296 let mut guard = arc_mut_opt.lock().unwrap();
297 let may_value = guard.take();
298 drop(guard);
299 if let Some(value) = may_value {
300 log::trace!("unified {name}");
301 Ok(value)
302 } else {
303 log::error!(
304 "'{name}' cannot be converted to owned as it is loaned exclusively"
305 );
306 Err(InnerLoan::LoanMut(arc_mut_opt))
307 }
308 }
309 }
310 }
311
312 pub fn into_loaned(self, name: &'static str) -> std::result::Result<Arc<TypeValue>, InnerLoan> {
313 match self {
314 InnerLoan::Owned(value) => Ok(Arc::new(value)),
315 InnerLoan::Loan(arc) => Ok(arc),
316 InnerLoan::LoanMut(arc_mut_opt) => {
317 let maybe_value = arc_mut_opt.lock().unwrap().take();
318 if let Some(value) = maybe_value {
319 log::trace!("converted exclusive {name} loan to non-exclusive");
320 Ok(Arc::new(value))
321 } else {
322 log::error!(
323 "'{name}' cannot be converted into a loan as it is loaned exclusively"
324 );
325 Err(InnerLoan::LoanMut(arc_mut_opt))
326 }
327 }
328 }
329 }
330
331 pub fn downcast_ref<T: Any + Send + Sync>(
332 &self,
333 name: &'static str,
334 ) -> std::result::Result<&T, BroomdogErr> {
335 match self {
336 InnerLoan::Owned(value) => value.downcast_ref(),
337 InnerLoan::Loan(arc) => arc.downcast_ref(),
338 InnerLoan::LoanMut(_) => Err(BroomdogErr::ExclusiveLoan { name }),
339 }
340 }
341
342 pub fn downcast_mut<T: Any + Send + Sync>(
343 &mut self,
344 name: &'static str,
345 ) -> std::result::Result<&mut T, BroomdogErr> {
346 let owned = self.as_owned_mut(name)?;
347 owned.downcast_mut()
348 }
349}
350
351#[derive(Default, Debug)]
353pub struct TypeMap {
354 inner: FxHashMap<TypeKey, InnerLoan>,
355}
356
357impl Deref for TypeMap {
358 type Target = FxHashMap<TypeKey, InnerLoan>;
359
360 fn deref(&self) -> &Self::Target {
361 &self.inner
362 }
363}
364
365impl DerefMut for TypeMap {
366 fn deref_mut(&mut self) -> &mut Self::Target {
367 &mut self.inner
368 }
369}
370
371impl TypeMap {
372 pub fn insert_value<T: Any + Send + Sync>(
374 &mut self,
375 value: T,
376 ) -> std::result::Result<Option<T>, BroomdogErr> {
377 let key = TypeKey::new::<T>();
378 if let Some(old_value) = self
379 .inner
380 .insert(key, InnerLoan::Owned(TypeValue::new(value)))
381 {
382 let old_value = old_value
383 .into_owned(key.name())
384 .map_err(|_| BroomdogErr::Loan {
385 name: std::any::type_name::<T>(),
386 })?;
387 log::trace!("inserted {key} and am returning old value");
388 old_value
389 .downcast()
390 .map(|box_t| Some(*box_t))
391 .map_err(|old_value| BroomdogErr::Mismatch {
392 new_type: std::any::type_name::<T>(),
393 old_type: old_value.type_name(),
394 })
395 } else {
396 log::trace!("inserted {key}");
397 Ok(None)
398 }
399 }
400
401 pub fn get_value<T: Any + Send + Sync>(&self) -> std::result::Result<Option<&T>, BroomdogErr> {
403 let key = TypeKey::new::<T>();
404 if let Some(value) = self.inner.get(&key) {
405 let t = value.downcast_ref(key.name())?;
406 Ok(Some(t))
407 } else {
408 Ok(None)
409 }
410 }
411
412 pub fn get_value_mut<T: Any + Send + Sync>(
415 &mut self,
416 ) -> std::result::Result<Option<&mut T>, BroomdogErr> {
417 let key = TypeKey::new::<T>();
418 if let Some(value) = self.inner.get_mut(&key) {
419 let t = value.downcast_mut(key.name())?;
420 Ok(Some(t))
421 } else {
422 Ok(None)
423 }
424 }
425
426 pub fn loan(&mut self, key: TypeKey) -> std::result::Result<Option<Loan>, BroomdogErr> {
437 if let Some(inner) = self.inner.remove(&key) {
438 log::trace!("loaning {key}");
439 match inner.into_loaned(key.name()) {
440 Ok(arc) => {
441 self.inner.insert(key, InnerLoan::Loan(arc.clone()));
442 Ok(Some(Loan { inner: arc }))
443 }
444 Err(inner) => {
445 self.inner.insert(key, inner);
446 ExclusiveLoanSnafu { name: key.name() }.fail()
447 }
448 }
449 } else {
450 log::trace!("can't loan {key}, DNE");
451 Ok(None)
452 }
453 }
454
455 pub fn loan_mut(&mut self, key: TypeKey) -> std::result::Result<Option<LoanMut>, BroomdogErr> {
464 if let Some(value) = self.inner.remove(&key) {
465 log::trace!("exclusively loaning {key}");
466 if value.is_owned() {
467 let value = value.into_owned(key.name()).unwrap();
469 let outer = Arc::new(Mutex::new(None));
470 self.inner.insert(key, InnerLoan::LoanMut(outer.clone()));
471 Ok(Some(LoanMut {
472 inner: Some(value),
473 outer,
474 }))
475 } else {
476 LoanSnafu { name: key.name() }.fail()
477 }
478 } else {
479 log::trace!("can't exclusively loan {key}, DNE");
480 Ok(None)
481 }
482 }
483
484 pub fn is_unified(&self) -> bool {
486 self.inner
487 .iter()
488 .all(|(_ty_key, loan): (_, &InnerLoan)| loan.is_owned())
489 }
490
491 pub fn unify(&mut self) -> std::result::Result<(), BroomdogErr> {
499 let mut names = vec![];
500 for (key, inner_loan) in std::mem::take(&mut self.inner) {
501 let loan = match inner_loan.into_owned(key.name()) {
502 Ok(value) => InnerLoan::Owned(value),
503 Err(loan) => {
504 names.push(key.name());
505 loan
506 }
507 };
508 let _ = self.inner.insert(key, loan);
509 }
510 if names.is_empty() {
511 Ok(())
512 } else {
513 ManyLoansSnafu { names }.fail()
514 }
515 }
516}