use std::any::TypeId;
use std::convert::TryFrom;
use unchecked_unwrap::UncheckedUnwrap;
use crate::vm::{GcInfo, Pr47PtrNonNull, Pr47Ptr, Pr47DynBase};
use crate::error::Pr47Error;
use crate::util::type_traits::is_copy;
pub trait CastFromPr47<'a, T: 'a> {
type CastResult = T;
fn any_cast(ptr: &Pr47Ptr) -> Result<Self::CastResult, Pr47Error>;
}
impl<'a, T: 'a> CastFromPr47<'a, T> for Pr47Ptr<'a> {
default fn any_cast(ptr: &Pr47Ptr) -> Result<Self::CastResult, Pr47Error> {
Pr47PtrNonNull::try_from(ptr).map_or_else(
|e| {
Err(e)
},
|ptr| {
<Pr47PtrNonNull as GetValueFromPtr<T>>::fetch_from_ptr(&ptr)
}
)
}
}
impl<'a, T: 'a> CastFromPr47<'a, Option<T>> for Pr47Ptr<'a> {
fn any_cast(ptr: &Pr47Ptr) -> Result<Self::CastResult, Pr47Error> {
Pr47PtrNonNull::try_from(ptr).map_or_else(
|_| {
Ok(None)
},
|ptr| {
Ok(Some(<Pr47PtrNonNull as GetValueFromPtr<T>>::fetch_from_ptr(&ptr)?))
}
)
}
}
impl<'a, T: 'a, E: std::error::Error + 'static> CastFromPr47<'a, Result<T, E>> for Pr47Ptr<'a> {
fn any_cast(_ptr: &Pr47Ptr) -> Result<Self::CastResult, Pr47Error> {
unimplemented!("throwing out an Pr47 exception is not implemented yet")
}
}
trait GetValueFromPtr<'a, T> {
fn fetch_from_ptr(ptr: &'a Pr47PtrNonNull) -> Result<T, Pr47Error>;
}
impl<'a, T: 'a> GetValueFromPtr<'a, T> for Pr47PtrNonNull<'a> {
default fn fetch_from_ptr(ptr: &'a Pr47PtrNonNull) -> Result<T, Pr47Error> {
if is_copy::<T>() {
<Pr47PtrNonNull as GetValueFromPtrCopy<T>>::fetch_from_ptr_copy(ptr)
} else {
unsafe {
if ptr.gc_info_ptr.as_ref().load(std::sync::atomic::Ordering::SeqCst)
!= GcInfo::MovedToHost.into() {
Err(Pr47Error::NotMove)
} else {
Ok(*Box::from_raw(ptr.data_ptr.as_ref()
.cast(TypeId::of::<T>(), std::any::type_name::<T>())
.unwrap()
.cast::<T>()
.as_ptr()))
}
}
}
}
}
trait GetValueFromPtrCopy<'a, T> {
fn fetch_from_ptr_copy(ptr: &'a Pr47PtrNonNull<'a>) -> Result<T, Pr47Error>;
}
impl<'a, T: 'a> GetValueFromPtrCopy<'a, T> for Pr47PtrNonNull<'a> {
default fn fetch_from_ptr_copy(_ptr: &'a Pr47PtrNonNull) -> Result<T, Pr47Error> {
unreachable!("Naa-ah... wrong way.")
}
}
impl<'a, T: 'a + Copy> GetValueFromPtrCopy<'a, T> for Pr47PtrNonNull<'a> {
fn fetch_from_ptr_copy(ptr: &'a Pr47PtrNonNull) -> Result<T, Pr47Error> {
unsafe {
Ok(*ptr.data_ptr
.as_ref()
.cast(TypeId::of::<T>(), std::any::type_name::<T>())?
.cast::<T>()
.as_ref())
}
}
}
impl<'a, T: 'a + Pr47DynBase> GetValueFromPtr<'a, &'a T> for Pr47PtrNonNull<'a> {
fn fetch_from_ptr(ptr: &'a Pr47PtrNonNull) -> Result<&'a T, Pr47Error> {
unsafe {
if ptr.gc_info_ptr.as_ref().load(std::sync::atomic::Ordering::SeqCst)
!= GcInfo::SharedWithHost.into() {
Err(Pr47Error::NotBorrow)
} else {
Ok(ptr.data_ptr
.as_ref()
.cast(TypeId::of::<T>(), std::any::type_name::<T>())?
.cast::<T>()
.as_ptr()
.as_ref()
.unchecked_unwrap())
}
}
}
}
impl<'a, T: 'a + Pr47DynBase> GetValueFromPtr<'a, &'a mut T> for Pr47PtrNonNull<'a> {
fn fetch_from_ptr(ptr: &'a Pr47PtrNonNull) -> Result<&'a mut T, Pr47Error> {
unsafe {
if ptr.gc_info_ptr.as_ref().load(std::sync::atomic::Ordering::SeqCst)
!= GcInfo::MutSharedWithHost.into() {
Err(Pr47Error::NotBorrow)
} else {
Ok(ptr.data_ptr
.as_ref()
.cast(TypeId::of::<T>(), std::any::type_name::<T>())?
.cast::<T>()
.as_ptr()
.as_mut()
.unchecked_unwrap())
}
}
}
}