use std::any::TypeId;
use std::ptr::NonNull;
use std::collections::BTreeMap;
use std::sync::atomic::AtomicU8;
use std::convert::TryFrom;
use crate::error::Pr47Error;
pub trait Pr47DynBase {
fn get_type_id(&self) -> TypeId;
fn get_type_name(&self) -> &'static str;
unsafe fn cast(&self,
dest_type_id: TypeId,
dest_type_name: &'static str) -> Result<NonNull<()>, Pr47Error> {
if self.get_type_id() == dest_type_id {
Ok(NonNull::new_unchecked(self as *const Self as *mut Self as *mut ()))
} else {
Err(Pr47Error::TypeCast {
from: self.get_type_id(),
to: dest_type_id,
from_name: self.get_type_name(),
to_name: dest_type_name
})
}
}
}
type Pr47Object = BTreeMap<String, Box<dyn Pr47DynBase>>;
pub struct Pr47Wrapper<T> {
pub data: T
}
impl<T> Pr47Wrapper<T> {
pub fn new(data: T) -> Self {
Self { data }
}
}
impl Pr47DynBase for Pr47Object {
fn get_type_id(&self) -> TypeId {
TypeId::of::<Pr47Object>()
}
fn get_type_name(&self) -> &'static str {
"Object"
}
}
impl Pr47DynBase for () {
fn get_type_id(&self) -> TypeId {
TypeId::of::<()>()
}
fn get_type_name(&self) -> &'static str {
"rust::Void"
}
}
impl Pr47DynBase for i64 {
fn get_type_id(&self) -> TypeId {
TypeId::of::<i64>()
}
fn get_type_name(&self) -> &'static str {
"int"
}
}
impl Pr47DynBase for f64 {
fn get_type_id(&self) -> TypeId {
TypeId::of::<f64>()
}
fn get_type_name(&self) -> &'static str {
"float"
}
}
impl Pr47DynBase for String {
fn get_type_id(&self) -> TypeId {
TypeId::of::<String>()
}
fn get_type_name(&self) -> &'static str {
"string"
}
}
impl<T: 'static> Pr47DynBase for Pr47Wrapper<T> {
fn get_type_id(&self) -> TypeId {
TypeId::of::<Pr47Wrapper<T>>()
}
fn get_type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
unsafe fn cast(&self,
dest_type_id: TypeId,
dest_type_name: &'static str) -> Result<NonNull<()>, Pr47Error> {
if dest_type_id == self.get_type_id() {
Ok(NonNull::new_unchecked(self as *const Self as *mut Self as *mut ()))
} else if dest_type_id == TypeId::of::<T>() {
Ok(NonNull::new_unchecked(&self.data as *const T as *mut T as *mut ()))
} else {
Err(Pr47Error::TypeCast {
from: self.get_type_id(),
to: dest_type_id,
from_name: self.get_type_name(),
to_name: dest_type_name
})
}
}
}
#[derive(Copy, Clone)]
pub enum Pr47Value {
ByteValue(u8),
IntValue(i64),
FloatValue(f64),
BoolValue(bool),
CharValue(char)
}
#[derive(Copy, Clone)]
pub enum GcInfo {
Useful,
Garbage,
SharedWithHost,
MutSharedWithHost,
MovedToHost,
}
impl Into<u8> for GcInfo {
fn into(self) -> u8 {
match self {
GcInfo::Useful => 0,
GcInfo::Garbage => 1,
GcInfo::SharedWithHost => 2,
GcInfo::MutSharedWithHost => 3,
GcInfo::MovedToHost => 4
}
}
}
impl From<u8> for GcInfo {
fn from(num: u8) -> Self {
match num {
0 => GcInfo::Useful,
1 => GcInfo::Garbage,
2 => GcInfo::SharedWithHost,
3 => GcInfo::MutSharedWithHost,
4 => GcInfo::MovedToHost,
_ => panic!()
}
}
}
#[derive(Copy, Clone)]
pub struct Pr47Ptr {
pub data_ptr: Option<NonNull<dyn Pr47DynBase>>,
pub gc_info_ptr: NonNull<AtomicU8>
}
impl Pr47Ptr {
pub fn dangling() -> Self {
Self {
data_ptr: None,
gc_info_ptr: NonNull::dangling()
}
}
pub fn shared(data_ptr: &mut (dyn Pr47DynBase + 'static)) -> Self {
Self {
data_ptr: unsafe {
Some(NonNull::new_unchecked(data_ptr as *mut dyn Pr47DynBase))
},
gc_info_ptr: unsafe {
NonNull::new_unchecked(
Box::into_raw(
Box::new(
AtomicU8::new(
GcInfo::SharedWithHost.into()))))
}
}
}
pub fn owned<T: 'static + Pr47DynBase>(data: T) -> Self {
Self {
data_ptr: unsafe {
Some(NonNull::new_unchecked(
Box::into_raw(Box::new(data)) as *mut dyn Pr47DynBase))
},
gc_info_ptr: unsafe {
NonNull::new_unchecked(
Box::into_raw(
Box::new(
AtomicU8::new(
GcInfo::Useful.into()))))
}
}
}
pub fn from_raw(data: Box<dyn Pr47DynBase>) -> Self {
Self {
data_ptr: unsafe {
Some(NonNull::new_unchecked(Box::into_raw(data)))
},
gc_info_ptr: unsafe {
NonNull::new_unchecked(
Box::into_raw(
Box::new(
AtomicU8::new(
GcInfo::Useful.into()))))
}
}
}
pub unsafe fn explicit_drop_data(&mut self) {
if let Some(data_ptr) = self.data_ptr {
Box::from_raw(data_ptr.as_ptr());
}
}
pub unsafe fn explicit_drop_gc(&mut self) {
if self.data_ptr.is_some() {
Box::from_raw(self.gc_info_ptr.as_ptr());
}
}
}
#[derive(Copy, Clone)]
pub struct Pr47PtrNonNull {
pub data_ptr: NonNull<dyn Pr47DynBase>,
pub gc_info_ptr: NonNull<AtomicU8>
}
impl TryFrom<&Pr47Ptr> for Pr47PtrNonNull {
type Error = Pr47Error;
fn try_from(value: &Pr47Ptr) -> Result<Self, Self::Error> {
if let Some(data_ptr) = value.data_ptr.as_ref() {
Ok(Self {
data_ptr: data_ptr.clone(),
gc_info_ptr: value.gc_info_ptr.clone()
})
} else {
Err(Pr47Error::NullPointer)
}
}
}