fire_stream_api/
util.rs

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