use crate::server::{Session, Data};
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::mem::ManuallyDrop;
pub use stream::util::PinnedFuture;
fn is_req<T: Any, R: Any>() -> bool {
TypeId::of::<T>() == TypeId::of::<R>()
}
fn is_session<T: Any>() -> bool {
TypeId::of::<T>() == TypeId::of::<Session>()
}
fn is_data<T: Any>() -> bool {
TypeId::of::<T>() == TypeId::of::<Data>()
}
#[doc(hidden)]
#[inline]
pub fn valid_data_as_ref<T: Any, R: Any>(data: &Data) -> bool {
is_req::<T, R>() || is_session::<T>() ||
is_data::<T>() || data.exists::<T>()
}
#[doc(hidden)]
#[inline]
pub fn valid_data_as_owned<T: Any, R: Any>(_data: &Data) -> bool {
is_req::<T, R>()
}
#[doc(hidden)]
pub struct DataManager<T> {
inner: RefCell<Option<T>>
}
impl<T> DataManager<T> {
pub fn new(val: T) -> Self {
Self {
inner: RefCell::new(Some(val))
}
}
#[inline]
pub fn take(&self) -> T {
self.inner.borrow_mut().take().unwrap()
}
#[inline]
pub fn as_ref(&self) -> &T {
let r = self.inner.borrow();
let r = ManuallyDrop::new(r);
unsafe {
&*(&**r as *const Option<T>)
}.as_ref().unwrap()
}
#[inline]
pub fn take_owned(mut self) -> T {
self.inner.get_mut().take().unwrap()
}
}
#[doc(hidden)]
#[inline]
pub fn get_data_as_ref<'a, T: Any, R: Any>(
data: &'a Data,
session: &'a Session,
req: &'a DataManager<R>
) -> &'a T {
if is_req::<T, R>() {
let req = req.as_ref();
<dyn Any>::downcast_ref(req).unwrap()
} else if is_session::<T>() {
<dyn Any>::downcast_ref(session).unwrap()
} else if is_data::<T>() {
<dyn Any>::downcast_ref(data).unwrap()
} else {
data.get::<T>().unwrap()
}
}
#[doc(hidden)]
#[inline]
pub fn get_data_as_owned<T: Any, R: Any>(
_data: &Data,
_session: &Session,
req: &DataManager<R>
) -> T {
if is_req::<T, R>() {
let req = req.take();
unsafe {
transform_owned::<T, R>(req)
}
} else {
unreachable!()
}
}
#[doc(hidden)]
#[inline]
pub(crate) unsafe fn transform_owned<T: Any + Sized, R: Any>(from: R) -> T {
let mut from = ManuallyDrop::new(from);
(&mut from as *mut ManuallyDrop<R> as *mut T).read()
}