lafere_api/
util.rs

1use crate::server::{Data, Session};
2
3use std::any::{Any, TypeId};
4use std::cell::RefCell;
5use std::mem::ManuallyDrop;
6
7pub use lafere::util::PinnedFuture;
8
9fn is_req<T: Any, R: Any>() -> bool {
10	TypeId::of::<T>() == TypeId::of::<R>()
11}
12
13fn is_session<T: Any>() -> bool {
14	TypeId::of::<T>() == TypeId::of::<Session>()
15}
16
17fn is_data<T: Any>() -> bool {
18	TypeId::of::<T>() == TypeId::of::<Data>()
19}
20
21/// fn to check if a type can be accessed in a route as reference
22#[doc(hidden)]
23#[inline]
24pub fn valid_data_as_ref<T: Any, R: Any>(data: &Data) -> bool {
25	is_req::<T, R>()
26		|| is_session::<T>()
27		|| is_data::<T>()
28		|| data.exists::<T>()
29}
30
31/// fn to check if a type can be accessed in a route as mutable reference
32#[doc(hidden)]
33#[inline]
34pub fn valid_data_as_owned<T: Any, R: Any>(_data: &Data) -> bool {
35	is_req::<T, R>()
36}
37
38#[doc(hidden)]
39pub struct DataManager<T> {
40	inner: RefCell<Option<T>>,
41}
42
43impl<T> DataManager<T> {
44	pub fn new(val: T) -> Self {
45		Self {
46			inner: RefCell::new(Some(val)),
47		}
48	}
49
50	/// ## Panics
51	/// if the value is already taken or borrowed
52	#[inline]
53	pub fn take(&self) -> T {
54		self.inner.borrow_mut().take().unwrap()
55	}
56
57	/// ## Panics
58	/// If the values is already taken or borrowed mutably
59	#[inline]
60	pub fn as_ref(&self) -> &T {
61		let r = self.inner.borrow();
62		let r = ManuallyDrop::new(r);
63		// since the borrow counter does not get decreased because of the
64		// ManuallyDrop and the lifetime not getting expanded this is safe
65		unsafe { &*(&**r as *const Option<T>) }.as_ref().unwrap()
66	}
67
68	/// ##Panics
69	/// if the value was taken previously
70	#[inline]
71	pub fn take_owned(mut self) -> T {
72		self.inner.get_mut().take().unwrap()
73	}
74}
75
76#[doc(hidden)]
77#[inline]
78pub fn get_data_as_ref<'a, T: Any, R: Any>(
79	data: &'a Data,
80	session: &'a Session,
81	req: &'a DataManager<R>,
82) -> &'a T {
83	if is_req::<T, R>() {
84		let req = req.as_ref();
85		<dyn Any>::downcast_ref(req).unwrap()
86	} else if is_session::<T>() {
87		<dyn Any>::downcast_ref(session).unwrap()
88	} else if is_data::<T>() {
89		<dyn Any>::downcast_ref(data).unwrap()
90	} else {
91		data.get::<T>().unwrap()
92	}
93}
94
95#[doc(hidden)]
96#[inline]
97pub fn get_data_as_owned<T: Any, R: Any>(
98	_data: &Data,
99	_session: &Session,
100	req: &DataManager<R>,
101) -> T {
102	if is_req::<T, R>() {
103		let req = req.take();
104		unsafe { transform_owned::<T, R>(req) }
105	} else {
106		unreachable!()
107	}
108}
109
110/// Safety you need to know that T is `R`
111#[doc(hidden)]
112#[inline]
113pub(crate) unsafe fn transform_owned<T: Any + Sized, R: Any>(from: R) -> T {
114	let mut from = ManuallyDrop::new(from);
115	(&mut from as *mut ManuallyDrop<R> as *mut T).read()
116}