pr47 0.0.1

A semi-experimental programming language. Still working in progress.
Documentation
use std::any::TypeId;
use std::convert::TryFrom;

use crate::vm::{GcInfo, Pr47PtrNonNull, Pr47Ptr};
use crate::error::Pr47Error;
use crate::util::type_traits::is_copy;

pub trait CastFromPr47<T> {
    type CastResult = T;
    fn any_cast(ptr: &Pr47Ptr) -> Result<Self::CastResult, Pr47Error>;
}

impl<T: 'static> CastFromPr47<T> for Pr47Ptr {
    default fn any_cast(ptr: &Pr47Ptr) -> Result<T, Pr47Error> {
        <Pr47Ptr as CastFromPr47NonNull<T>>::any_cast_non_null(&Pr47PtrNonNull::try_from(ptr)?)
    }
}

impl<T: 'static> CastFromPr47<Option<T>> for Pr47Ptr {
    fn any_cast(ptr: &Pr47Ptr) -> Result<Option<T>, Pr47Error> {
        Pr47PtrNonNull::try_from(ptr).map_or(
            Ok(None),
            |ptr_non_null| {
                Ok(Some(<Pr47Ptr as CastFromPr47NonNull<T>>::any_cast_non_null(&ptr_non_null)?))
            })
    }
}

pub trait CastFromPr47NonNull<T> {
    type CastResult = T;
    fn any_cast_non_null(ptr: &Pr47PtrNonNull) -> Result<Self::CastResult, Pr47Error>;
}

impl<T: 'static> CastFromPr47NonNull<T> for Pr47Ptr {
    default fn any_cast_non_null(ptr: &Pr47PtrNonNull) -> Result<Self::CastResult, Pr47Error> {
        if is_copy::<T>() {
            <Self as CastHelperCopy<Self::CastResult>>::cast_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 CastHelperCopy<T> {
    type CastResult = T;
    fn cast_copy(ptr: &Pr47PtrNonNull) -> Result<Self::CastResult, Pr47Error>;
}

impl<T: 'static> CastHelperCopy<T> for Pr47Ptr {
    default fn cast_copy(ptr: &Pr47PtrNonNull) -> Result<Self::CastResult, Pr47Error> {
        unreachable!()
    }
}

impl<T: 'static + Copy> CastHelperCopy<T> for Pr47Ptr {
    fn cast_copy(ptr: &Pr47PtrNonNull) -> Result<Self::CastResult, Pr47Error> {
        unsafe {
            Ok(*ptr.data_ptr
                .as_ref()
                .cast(TypeId::of::<T>(), std::any::type_name::<T>())?
                .cast::<T>()
                .as_ref())
        }
    }
}

impl<T: 'static> CastFromPr47NonNull<&'_ T> for Pr47Ptr {
    fn any_cast_non_null(reference: &Pr47PtrNonNull) -> Result<Self::CastResult, Pr47Error> {
        unsafe {
            if reference.gc_info_ptr.as_ref().load(std::sync::atomic::Ordering::SeqCst)
                != GcInfo::SharedWithHost.into() {
                Err(Pr47Error::NotBorrow)
            } else {
                Ok(reference.data_ptr
                    .as_ref()
                    .cast(TypeId::of::<T>(),
                          std::any::type_name::<T>())?
                    .cast::<T>()
                    .as_ptr()
                    .as_ref()
                    .unwrap())
            }
        }
    }
}

impl<T: 'static> CastFromPr47NonNull<&'_ mut T> for Pr47Ptr {
    fn any_cast_non_null(reference: &Pr47PtrNonNull) -> Result<Self::CastResult, Pr47Error> {
        unsafe {
            if reference.gc_info_ptr.as_ref().load(std::sync::atomic::Ordering::SeqCst)
                != GcInfo::MutSharedWithHost.into() {
                Err(Pr47Error::NotBorrow)
            } else {
                Ok(reference.data_ptr
                    .as_ref()
                    .cast(TypeId::of::<T>(),
                          std::any::type_name::<T>())?
                    .cast::<T>()
                    .as_ptr()
                    .as_mut()
                    .unwrap())
            }
        }
    }
}