use std::{
alloc::Layout,
any::{TypeId, type_name},
marker::PhantomData,
mem::MaybeUninit,
ptr, slice,
sync::atomic::{AtomicPtr, AtomicUsize, Ordering::*},
};
use crate::{LateField, LateLayoutInitToken, LateStruct};
#[derive(Debug)]
pub struct RawLateStructDescriptor {
pub(crate) size: AtomicUsize,
pub(crate) align: AtomicUsize,
pub(crate) fields: AtomicPtr<&'static [&'static RawLateFieldDescriptor]>,
type_name: fn() -> &'static str,
type_id: fn() -> TypeId,
}
impl RawLateStructDescriptor {
pub(crate) const fn new<S: LateStruct>() -> Self {
Self {
size: AtomicUsize::new(0),
align: AtomicUsize::new(0),
fields: AtomicPtr::new(ptr::null_mut()),
type_name: type_name::<S>,
type_id: TypeId::of::<S>,
}
}
pub fn type_name(&self) -> &'static str {
(self.type_name)()
}
pub fn type_id(&self) -> TypeId {
(self.type_id)()
}
pub fn layout(&self, token: LateLayoutInitToken) -> Layout {
let _ = token;
unsafe {
Layout::from_size_align_unchecked(self.size.load(Relaxed), self.align.load(Relaxed))
}
}
pub fn fields(&self, token: LateLayoutInitToken) -> &'static [&'static RawLateFieldDescriptor] {
let _ = token;
unsafe { &**self.fields.load(Relaxed) }
}
pub fn typed<S: LateStruct>(&self) -> &LateStructDescriptor<S> {
LateStructDescriptor::wrap(self)
}
pub unsafe fn typed_unchecked<S: LateStruct>(&self) -> &LateStructDescriptor<S> {
unsafe { LateStructDescriptor::wrap_unchecked(self) }
}
}
#[derive(Debug)]
pub struct RawLateFieldDescriptor {
pub(crate) index: AtomicUsize,
pub(crate) offset: AtomicUsize,
layout: Layout,
init: unsafe fn(*mut u8),
drop: unsafe fn(*mut u8),
as_erased: fn(*mut u8, *mut ()),
key_type_name: fn() -> &'static str,
key_type_id: fn() -> TypeId,
parent_struct: fn() -> &'static RawLateStructDescriptor,
}
impl RawLateFieldDescriptor {
pub(crate) const fn new<S, F>() -> Self
where
S: LateStruct,
F: LateField<S>,
{
Self {
index: AtomicUsize::new(usize::MAX),
offset: AtomicUsize::new(usize::MAX),
layout: Layout::new::<F::Value>(),
init: |ptr| unsafe { ptr.cast::<F::Value>().write(<F::Value>::default()) },
drop: |ptr| unsafe { ptr.cast::<F::Value>().drop_in_place() },
as_erased: |ptr, write_out| unsafe {
write_out
.cast::<*mut S::EraseTo>()
.write(F::coerce(ptr.cast::<F::Value>()));
},
key_type_name: type_name::<F>,
key_type_id: TypeId::of::<F>,
parent_struct: S::raw_descriptor,
}
}
pub fn parent_struct(&self) -> &'static RawLateStructDescriptor {
(self.parent_struct)()
}
pub fn index(&self, token: LateLayoutInitToken) -> usize {
let _ = token;
self.index.load(Relaxed)
}
pub fn offset(&self, token: LateLayoutInitToken) -> usize {
let _ = token;
self.offset.load(Relaxed)
}
pub fn layout(&self) -> Layout {
self.layout
}
pub unsafe fn init(&self, value: *mut u8) {
unsafe { (self.init)(value) }
}
pub unsafe fn drop(&self, value: *mut u8) {
unsafe { (self.drop)(value) }
}
pub unsafe fn erase_value<S: LateStruct>(&self, value: *mut u8) -> *mut S::EraseTo {
debug_assert_eq!(TypeId::of::<S>(), self.parent_struct().type_id());
let mut out = MaybeUninit::<*mut S::EraseTo>::uninit();
unsafe {
(self.as_erased)(value, out.as_mut_ptr().cast());
out.assume_init()
}
}
pub fn key_type_name(&self) -> &'static str {
(self.key_type_name)()
}
pub fn key_type_id(&self) -> TypeId {
(self.key_type_id)()
}
pub fn typed<S: LateStruct>(&self) -> &LateFieldDescriptor<S> {
LateFieldDescriptor::wrap(self)
}
pub unsafe fn typed_unchecked<S: LateStruct>(&self) -> &LateFieldDescriptor<S> {
unsafe { LateFieldDescriptor::wrap_unchecked(self) }
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct LateStructDescriptor<S: LateStruct> {
_ty: PhantomData<fn(S) -> S>,
raw: RawLateStructDescriptor,
}
impl<S: LateStruct> LateStructDescriptor<S> {
fn wrap(raw: &RawLateStructDescriptor) -> &LateStructDescriptor<S> {
assert_eq!(raw.type_id(), TypeId::of::<S>());
unsafe { Self::wrap_unchecked(raw) }
}
const unsafe fn wrap_unchecked(raw: &RawLateStructDescriptor) -> &LateStructDescriptor<S> {
unsafe { &*(raw as *const RawLateStructDescriptor as *const LateStructDescriptor<S>) }
}
pub const fn raw(&self) -> &RawLateStructDescriptor {
&self.raw
}
}
impl<S: LateStruct> LateStructDescriptor<S> {
pub fn layout(&self, token: LateLayoutInitToken) -> Layout {
self.raw.layout(token)
}
pub fn fields(&self, token: LateLayoutInitToken) -> &'static [&'static LateFieldDescriptor<S>] {
unsafe { LateFieldDescriptor::wrap_slice_unchecked(self.raw.fields(token)) }
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct LateFieldDescriptor<S: LateStruct> {
_ty: PhantomData<fn(S) -> S>,
raw: RawLateFieldDescriptor,
}
impl<S: LateStruct> LateFieldDescriptor<S> {
fn wrap(raw: &RawLateFieldDescriptor) -> &LateFieldDescriptor<S> {
assert_eq!(raw.parent_struct().type_id(), TypeId::of::<S>());
unsafe { Self::wrap_unchecked(raw) }
}
const unsafe fn wrap_unchecked(raw: &RawLateFieldDescriptor) -> &LateFieldDescriptor<S> {
unsafe { &*(raw as *const RawLateFieldDescriptor as *const LateFieldDescriptor<S>) }
}
const unsafe fn wrap_slice_unchecked<'a, 'b>(
raw: &'a [&'b RawLateFieldDescriptor],
) -> &'a [&'b LateFieldDescriptor<S>] {
unsafe {
slice::from_raw_parts(raw.as_ptr().cast::<&'b LateFieldDescriptor<S>>(), raw.len())
}
}
pub const fn raw(&self) -> &RawLateFieldDescriptor {
&self.raw
}
}
impl<S: LateStruct> LateFieldDescriptor<S> {
pub fn index(&self, token: LateLayoutInitToken) -> usize {
self.raw.index(token)
}
pub fn offset(&self, token: LateLayoutInitToken) -> usize {
self.raw.offset(token)
}
pub fn layout(&self) -> Layout {
self.raw.layout()
}
pub unsafe fn init(&self, value: *mut u8) {
unsafe { self.raw.init(value) }
}
pub unsafe fn drop(&self, value: *mut u8) {
unsafe { self.raw.drop(value) }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn erase_value(&self, value: *mut u8) -> *mut S::EraseTo {
unsafe { self.raw.erase_value::<S>(value) }
}
pub fn key_type_name(&self) -> &'static str {
self.raw.key_type_name()
}
pub fn key_type_id(&self) -> TypeId {
self.raw.key_type_id()
}
pub fn parent_struct(&self) -> &'static LateStructDescriptor<S> {
unsafe { self.raw.parent_struct().typed_unchecked() }
}
}