1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use std::fmt::{Debug, Formatter};
use std::ptr::NonNull;

use crate::data::traits::ChildrenType;
use crate::data::tyck::ContainerTyckInfo;
use crate::data::wrapper::Wrapper;

#[cfg(debug_assertions)] use std::any::TypeId;

pub trait GenericTypeRef {
    fn create_ref(wrapper_ptr: *mut Wrapper<()>) -> Self;
}

pub const GENERIC_TYPE_MASK: u8 = 0b00000_010;

#[cfg(debug_assertions)]
pub type MoveOutCkFn = unsafe fn(this: *mut (), out: *mut (), type_id: TypeId);
#[cfg(not(debug_assertions))]
pub type MoveOutFn = unsafe fn(this: *mut (), out: *mut ());

pub type ChildrenFn = unsafe fn(this: *const ()) -> ChildrenType;

pub type DropFn = unsafe fn(this: *mut());

pub type GenericTypeCtor = fn() -> *mut Wrapper<()>;

pub struct GenericTypeVT {
    pub tyck_info: NonNull<ContainerTyckInfo>,
    pub type_name: String,
    #[cfg(debug_assertions)]
    pub move_out_fn: MoveOutCkFn,
    #[cfg(not(debug_assertions))]
    pub move_out_fn: MoveOutFn,
    pub children_fn: ChildrenFn,
    pub drop_fn: DropFn
}

impl GenericTypeVT {
    #[cfg(debug_assertions)]
    pub fn new(
        tyck_info: NonNull<ContainerTyckInfo>,
        type_name: impl ToString,
        move_out_fn: MoveOutCkFn,
        children_fn: ChildrenFn,
        drop_fn: DropFn
    ) -> Self {
        Self {
            tyck_info,
            type_name: type_name.to_string(),
            move_out_fn,
            children_fn,
            drop_fn
        }
    }

    #[cfg(not(debug_assertions))]
    pub fn new(
        tyck_info: NonNull<ContainerTyckInfo>,
        type_name: impl ToString,
        move_out_fn: MoveOutFn,
        children_fn: ChildrenFn,
        drop_fn: DropFn
    ) -> Self {
        Self {
            tyck_info,
            type_name: type_name.to_string(),
            move_out_fn,
            children_fn,
            drop_fn
        }
    }
}

impl Debug for GenericTypeVT {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "ContainerVT({})", self.type_name)
    }
}

#[derive(Clone, Copy)]
pub struct ContainerPtr {
    pub data_ptr: *mut u8,
    pub vt: *mut GenericTypeVT
}

pub mod gen_impls {
    use std::mem::{MaybeUninit, ManuallyDrop};

    use xjbutil::void::Void;

    use crate::data::traits::{ChildrenType, StaticBase};
    use crate::data::wrapper::{OwnershipInfo, Wrapper};

    #[cfg(debug_assertions)] use std::any::TypeId;

    #[cfg(debug_assertions)]
    #[inline(always)]
    pub unsafe fn generic_move_out_ck<T>(this: *mut (), out: *mut (), type_id: TypeId)
        where T: 'static,
              Void: StaticBase<T>
    {
        assert_eq!(type_id, TypeId::of::<T>());
        let this: &mut Wrapper<T> = &mut *(this as *mut Wrapper<_>);
        let out: &mut MaybeUninit<T> = &mut *(out as *mut MaybeUninit<_>);

        assert_eq!(this.ownership_info, OwnershipInfo::VMOwned as u8);
        let data: T = ManuallyDrop::take(&mut this.data.owned).assume_init();
        std::ptr::write(out.as_mut_ptr(), data);
        this.ownership_info = OwnershipInfo::MovedToRust as u8;
    }

    #[cfg(not(debug_assertions))]
    #[inline(always)]
    pub unsafe fn generic_move_out<T>(this: *mut (), out: *mut ())
        where T: 'static,
              Void: StaticBase<T>
    {
        let this: &mut Wrapper<T> = &mut *(this as *mut Wrapper<_>);
        let out: &mut MaybeUninit<T> = &mut *(out as *mut MaybeUninit<_>);

        let data: T = ManuallyDrop::take(&mut this.data.owned).assume_init();
        std::ptr::write(out.as_mut_ptr(), data);
        this.ownership_info = OwnershipInfo::MovedToRust as u8;
    }

    #[inline(always)]
    pub unsafe fn generic_children<T>(this: *const ()) -> ChildrenType
        where T: 'static,
              Void: StaticBase<T>
    {
        <Void as StaticBase<T>>::children(this as *const _)
    }

    #[inline(always)]
    pub unsafe fn generic_drop<T>(this: *mut ())
        where T: 'static,
              Void: StaticBase<T>
    {
        let boxed: Box<Wrapper<T>> = Box::from_raw(this as *mut _);
        drop(boxed);
    }
}