pub mod exception;
pub mod generic;
pub mod traits;
pub mod tyck;
pub mod value_typed;
pub mod wrapper;
use std::marker::PhantomData;
use std::mem::{MaybeUninit, transmute};
use xjbutil::mem::move_to_heap;
use xjbutil::unchecked::UnsafeFrom;
use xjbutil::void::Void;
use xjbutil::wide_ptr::WidePointer;
use crate::data::generic::{GENERIC_TYPE_MASK, GenericTypeVT};
use crate::data::traits::StaticBase;
use crate::data::value_typed::{VALUE_TYPE_MASK, ValueTypedData};
use crate::data::wrapper::{DynBase, OwnershipInfo, Wrapper};
#[cfg(any(test, feature = "bench"))]
use std::fmt::{Debug, Formatter};
use xjbutil::provenance_ignore;
#[cfg(any(test, feature = "bench"))]
use crate::data::value_typed::{VALUE_TYPE_TAG_MASK, ValueTypeTag};
pub const TAG_BITS_MASK: u8 = 0b00000_111;
pub const TAG_BITS_MASK_USIZE: usize = TAG_BITS_MASK as usize;
pub const PTR_BITS_MASK: u8 = !TAG_BITS_MASK;
pub const PTR_BITS_MASK_USIZE: usize = !TAG_BITS_MASK_USIZE;
#[repr(C)]
#[derive(Clone, Copy)]
pub union Value {
pub ptr: *mut dyn DynBase,
pub ptr_repr: WidePointer,
pub vt_data: ValueTypedData,
}
impl Value {
pub fn new_owned<T>(data: T) -> Self
where T: 'static,
Void: StaticBase<T>
{
let ptr: *mut Wrapper<T> = move_to_heap(Wrapper::new_owned(data)).as_ptr();
let s = Self { ptr: provenance_ignore!(ptr) };
s
}
pub fn new_container(wrapper: *mut Wrapper<()>, vt: *const GenericTypeVT) -> Self {
let ptr: usize = (provenance_ignore!(wrapper) as usize) | (GENERIC_TYPE_MASK as usize);
let trivia: usize = provenance_ignore!(vt) as _;
Self { ptr_repr: WidePointer::new(ptr, trivia) }
}
pub unsafe fn new_shared<T>(data: &T) -> Self
where T: 'static,
Void: StaticBase<T>
{
Self {
ptr: move_to_heap(Wrapper::new_ref(
provenance_ignore!(data as *const T))
).as_ptr()
}
}
pub unsafe fn new_mut_shared<T>(data: &mut T) -> Self
where T: 'static,
Void: StaticBase<T>
{
Self {
ptr: move_to_heap(Wrapper::new_mut_ref(
provenance_ignore!(data as *mut T))
).as_ptr()
}
}
#[inline(always)] pub fn new_raw_value(tag: usize, repr: u64) -> Self {
Self {
vt_data: ValueTypedData::new_raw(tag, repr)
}
}
#[inline(always)] pub fn new_int(int_value: i64) -> Self {
Self {
vt_data: ValueTypedData::from(int_value)
}
}
#[inline(always)] pub fn new_float(float_value: f64) -> Self {
Self {
vt_data: ValueTypedData::from(float_value)
}
}
#[inline(always)] pub fn new_bool(bool_value: bool) -> Self {
Self {
vt_data: ValueTypedData::from(bool_value)
}
}
#[inline(always)] pub const fn new_null() -> Self {
Self {
ptr_repr: WidePointer::new(0, 0)
}
}
pub fn is_null(&self) -> bool {
unsafe { self.ptr_repr.ptr == 0 }
}
pub fn is_value(&self) -> bool {
unsafe {
self.ptr_repr.ptr & (VALUE_TYPE_MASK as usize) != 0
}
}
pub fn is_ref(&self) -> bool {
unsafe {
self.ptr_repr.ptr & (VALUE_TYPE_MASK as usize) == 0
}
}
pub fn is_container(&self) -> bool {
unsafe {
self.ptr_repr.ptr & (GENERIC_TYPE_MASK as usize) != 0
}
}
#[inline(always)] pub unsafe fn untagged_ptr_field(&self) -> usize {
self.ptr_repr.ptr & PTR_BITS_MASK_USIZE
}
pub unsafe fn ref_count(&self) -> u32 {
#[cfg(debug_assertions)] self.assert_shared();
*(self.untagged_ptr_field() as *const u32)
}
pub unsafe fn ref_count_norm(&self) -> u32 {
#[cfg(debug_assertions)] self.assert_shared();
debug_assert!(!self.is_container());
*(self.ptr_repr.ptr as *const u32)
}
pub unsafe fn incr_ref_count(&self) {
#[cfg(debug_assertions)] self.assert_shared();
*(self.untagged_ptr_field() as *mut u32) += 1
}
pub unsafe fn incr_ref_count_norm(&self) {
#[cfg(debug_assertions)] self.assert_shared();
debug_assert!(!self.is_container());
*(self.ptr_repr.ptr as *mut u32) += 1
}
pub unsafe fn decr_ref_count(&self) {
#[cfg(debug_assertions)] self.assert_shared();
*(self.untagged_ptr_field() as *mut u32) -= 1
}
pub unsafe fn decr_ref_count_norm(&self) {
#[cfg(debug_assertions)] self.assert_shared();
debug_assert!(!self.is_container());
*(self.ptr_repr.ptr as *mut u32) -= 1
}
#[cfg(debug_assertions)]
fn assert_shared(&self) {
let ownership_info: OwnershipInfo = unsafe { self.ownership_info() };
assert!(ownership_info == OwnershipInfo::SharedFromRust
|| ownership_info == OwnershipInfo::SharedToRust);
}
pub unsafe fn ownership_info(&self) -> OwnershipInfo {
debug_assert!(self.is_ref());
UnsafeFrom::unsafe_from(*((self.untagged_ptr_field() + 4usize) as *const u8))
}
#[cfg_attr(not(debug_assertions), inline(always))]
pub unsafe fn ownership_info_norm(&self) -> OwnershipInfo {
debug_assert!(self.is_ref());
debug_assert!(!self.is_container());
UnsafeFrom::unsafe_from(*((self.ptr_repr.ptr + 4usize) as *const u8))
}
pub unsafe fn set_ownership_info(&self, ownership_info: OwnershipInfo) {
debug_assert!(self.is_ref());
*((self.untagged_ptr_field() + 4usize) as *mut u8) = ownership_info as u8;
}
pub unsafe fn set_ownership_info_norm(&self, ownership_info: OwnershipInfo) {
debug_assert!(self.is_ref());
debug_assert!(!self.is_container());
*((self.ptr_repr.ptr + 4usize) as *mut u8) = ownership_info as u8;
}
pub unsafe fn gc_info(&self) -> u8 {
debug_assert!(self.is_ref());
*((self.untagged_ptr_field() + 5usize) as *mut u8)
}
pub unsafe fn gc_info_norm(&self) -> u8 {
debug_assert!(self.is_ref());
debug_assert!(!self.is_container());
*((self.ptr_repr.ptr + 5usize) as *mut u8)
}
pub unsafe fn set_gc_info(&self, gc_info: u8) {
debug_assert!(self.is_ref());
*((self.untagged_ptr_field() + 5usize) as *mut u8) = gc_info;
}
#[cfg_attr(not(debug_assertions), inline)]
pub unsafe fn set_gc_info_norm(&self, gc_info: u8) {
debug_assert!(self.is_ref());
debug_assert!(!self.is_container());
*((self.ptr_repr.ptr + 5usize) as *mut u8) = gc_info;
}
#[cfg_attr(not(debug_assertions), inline)]
pub unsafe fn get_as_dyn_base(&self) -> *mut dyn DynBase {
debug_assert!(self.is_ref());
debug_assert!(!self.is_container());
self.ptr
}
#[cfg_attr(not(debug_assertions), inline)]
pub unsafe fn get_as_mut_ptr<T>(&self) -> *mut T
where T: 'static
{
debug_assert!(self.ownership_info().is_readable());
let untagged_ptr_field: usize = self.untagged_ptr_field();
let data_offset: usize = *((untagged_ptr_field + 6usize) as *mut u8) as usize;
if self.ownership_info().is_owned() {
(untagged_ptr_field + data_offset as usize) as *mut T
} else {
let ptr: *const *mut T = (untagged_ptr_field + data_offset) as *const *mut T;
*ptr
}
}
#[cfg_attr(not(debug_assertions), inline)]
pub unsafe fn get_as_mut_ptr_norm<T>(&self) -> *mut T
where T: 'static
{
debug_assert!(self.ownership_info().is_readable());
let data_offset: usize = *((self.ptr_repr.ptr + 6usize) as *mut u8) as usize;
if self.ownership_info_norm().is_owned() {
(self.ptr_repr.ptr + data_offset as usize) as *mut T
} else {
let ptr: *const *mut T = (self.ptr_repr.ptr + data_offset) as *const *mut T;
*ptr
}
}
pub unsafe fn move_out<T>(&self) -> T
where T: 'static,
Void: StaticBase<T>
{
debug_assert!(self.is_ref());
let mut maybe_uninit: MaybeUninit<T> = MaybeUninit::uninit();
if !self.is_container() {
let dyn_base: *mut dyn DynBase = self.ptr;
#[cfg(debug_assertions)]
dyn_base.as_mut().unwrap_unchecked().move_out_ck(
&mut maybe_uninit as *mut _ as *mut (),
<Void as StaticBase<T>>::type_id()
);
#[cfg(not(debug_assertions))]
dyn_base.as_mut().unwrap_unchecked().move_out(
&mut maybe_uninit as *mut _ as *mut ()
);
} else {
let this_ptr: *mut () = self.untagged_ptr_field() as *mut ();
let custom_vt: *const GenericTypeVT = self.ptr_repr.trivia as *const _;
#[cfg(debug_assertions)]
(custom_vt.as_ref().unwrap_unchecked().move_out_fn) (
this_ptr,
&mut maybe_uninit as *mut _ as *mut (),
<Void as StaticBase<T>>::type_id()
);
#[cfg(not(debug_assertions))]
(custom_vt.as_ref().unwrap_unchecked().move_out_fn) (
this_ptr,
&mut maybe_uninit as *mut _ as *mut (),
);
}
maybe_uninit.assume_init()
}
pub unsafe fn move_out_norm<T>(&self) -> T
where T: 'static,
Void: StaticBase<T>
{
debug_assert!(self.is_ref());
debug_assert!(!self.is_container());
let mut maybe_uninit: MaybeUninit<T> = MaybeUninit::uninit();
let dyn_base: *mut dyn DynBase = self.ptr;
#[cfg(debug_assertions)]
dyn_base.as_mut().unwrap_unchecked().move_out_ck(
&mut maybe_uninit as *mut _ as *mut (),
<Void as StaticBase<T>>::type_id()
);
#[cfg(not(debug_assertions))]
dyn_base.as_mut().unwrap_unchecked().move_out(
&mut maybe_uninit as *mut _ as *mut ()
);
maybe_uninit.assume_init()
}
}
#[cfg(any(test, feature = "bench"))]
impl Debug for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_value() {
unsafe {
match ValueTypeTag::unsafe_from((self.vt_data.tag as u8) & VALUE_TYPE_TAG_MASK) {
ValueTypeTag::Int => write!(f, "IntV({})", self.vt_data.inner.int_value),
ValueTypeTag::Float => write!(f, "FloatV({})", self.vt_data.inner.float_value),
ValueTypeTag::Bool => write!(f, "BoolV({})", self.vt_data.inner.bool_value)
}
}
} else if self.is_container() {
unsafe {
write!(f, "CustomContainer(ptr = {:X}, vt = {:X})",
self.ptr_repr.trivia, self.ptr_repr.ptr)
}
} else if self.is_null() {
write!(f, "Null")
} else {
unsafe {
write!(f, "Reference(ptr = {:X})", self.ptr_repr.ptr)
}
}
}
}
#[repr(transparent)]
pub struct TypedValue<T: 'static> {
pub inner: Value,
_phantom: PhantomData<T>
}
impl<T> TypedValue<T>
where T: 'static,
Void: StaticBase<T>
{
}
impl TypedValue<i64> {
}
impl TypedValue<f64> {
}
impl TypedValue<bool> {
}
#[cfg(test)]
mod test;