use std::marker::PhantomData;
use crate::{
inline_storage::alignment::AlignToUsize, marker_type::NotCopyNotClone,
pointer_trait::ImmutableRef, sabi_types::StaticRef, utils::Transmuter,
};
#[allow(unused_imports)]
use core_extensions::SelfOps;
use repr_offset::offset_calc::next_field_offset;
mod accessible_fields;
mod layout;
mod prefix_ref;
mod pt_metadata;
#[cfg(test)]
mod tests;
pub use self::{
accessible_fields::{FieldAccessibility, FieldConditionality, IsAccessible, IsConditional},
layout::PTStructLayout,
prefix_ref::PrefixRef,
};
#[doc(hidden)]
pub use self::pt_metadata::__PrefixTypeMetadata;
pub unsafe trait PrefixTypeTrait: Sized {
const PT_LAYOUT: &'static PTStructLayout;
const PT_FIELD_ACCESSIBILITY: FieldAccessibility;
fn leak_into_prefix(self) -> Self::PrefixRef {
let x = WithMetadata::new(self);
let x = StaticRef::leak_value(x);
let x = PrefixRef::from_staticref(x);
<Self::PrefixRef as PrefixRefTrait>::from_prefix_ref(x)
}
type PrefixFields;
type PrefixRef: PrefixRefTrait<
PtrTarget = WithMetadata_<Self::PrefixFields, Self::PrefixFields>,
PrefixFields = Self::PrefixFields,
>;
}
pub unsafe trait PrefixRefTrait:
Sized + ImmutableRef<PtrTarget = WithMetadata_<Self::PrefixFields, Self::PrefixFields>>
{
type PrefixFields;
#[inline]
fn from_prefix_ref(this: PrefixRef<Self::PrefixFields>) -> Self {
unsafe { Transmuter { from: this }.to }
}
#[inline]
fn to_prefix_ref(self) -> PrefixRef<Self::PrefixFields> {
unsafe { Transmuter { from: self }.to }
}
}
pub type WithMetadata<T, P = <T as PrefixTypeTrait>::PrefixFields> = WithMetadata_<T, P>;
#[repr(C)]
pub struct WithMetadata_<T, P> {
field_accessibility: FieldAccessibility,
type_layout: &'static PTStructLayout,
pub value: AlignToUsize<T>,
unbounds: NotCopyNotClone,
_prefix: PhantomData<P>,
}
#[doc(hidden)]
impl<T, P> WithMetadata_<T, P> {
pub const __VALUE_OFFSET: usize = {
let tl_offset = next_field_offset::<Self, FieldAccessibility, &'static PTStructLayout>(0);
next_field_offset::<Self, &'static PTStructLayout, AlignToUsize<T>>(tl_offset)
};
}
impl<T, P> WithMetadata_<T, P> {
#[inline]
pub const fn new(value: T) -> Self
where
T: PrefixTypeTrait<PrefixFields = P>,
{
Self {
field_accessibility: T::PT_FIELD_ACCESSIBILITY,
type_layout: T::PT_LAYOUT,
value: AlignToUsize(value),
unbounds: NotCopyNotClone,
_prefix: PhantomData,
}
}
#[inline]
pub const fn field_accessibility(&self) -> FieldAccessibility {
self.field_accessibility
}
#[inline]
pub const fn type_layout(&self) -> &'static PTStructLayout {
self.type_layout
}
#[inline]
pub const unsafe fn raw_as_prefix(this: *const Self) -> PrefixRef<P> {
unsafe { PrefixRef::from_raw(this) }
}
#[inline]
pub const unsafe fn as_prefix(&self) -> PrefixRef<P> {
unsafe { PrefixRef::from_raw(self) }
}
#[inline]
pub const fn static_as_prefix(&'static self) -> PrefixRef<P> {
PrefixRef::from_ref(self)
}
}
impl<T, P> StaticRef<WithMetadata_<T, P>> {
pub const fn as_prefix(self) -> PrefixRef<P> {
PrefixRef::from_staticref(self)
}
}
#[cold]
#[inline(never)]
pub fn panic_on_missing_field_ty<T>(field_index: usize, actual_layout: &'static PTStructLayout) -> !
where
T: PrefixTypeTrait,
{
#[inline(never)]
fn inner(
field_index: usize,
expected_layout: &'static PTStructLayout,
actual_layout: &'static PTStructLayout,
) -> ! {
let field = expected_layout
.get_field_name(field_index)
.unwrap_or("<unavailable>");
panic_on_missing_field_val(field_index, field, expected_layout, actual_layout)
}
inner(field_index, T::PT_LAYOUT, actual_layout)
}
#[cold]
#[inline(never)]
pub fn panic_on_missing_fieldname<T>(field_index: u8, actual_layout: &'static PTStructLayout) -> !
where
T: PrefixTypeTrait,
{
#[inline(never)]
fn inner(
field_index: usize,
expected_layout: &'static PTStructLayout,
actual_layout: &'static PTStructLayout,
) -> ! {
let fieldname = expected_layout
.get_field_name(field_index)
.unwrap_or("<unavaiable>");
panic_on_missing_field_val(field_index, fieldname, expected_layout, actual_layout)
}
inner(field_index as usize, T::PT_LAYOUT, actual_layout)
}
#[inline(never)]
fn panic_on_missing_field_val(
field_index: usize,
field_name: &'static str,
expected: &'static PTStructLayout,
actual: &'static PTStructLayout,
) -> ! {
panic!(
"\n
Attempting to access nonexistent field:
index:{index}
named:{field_named}
Inside of:{struct_name}{struct_generics}
Package:'{package}'
Expected:
Version:{expected_package_version} (or compatible version number)
Field count:{expected_field_count}
Found:
Version:{actual_package_version}
Field count:{actual_field_count}
\n",
index = field_index,
field_named = field_name,
struct_name = expected.mono_layout.name(),
struct_generics = expected.generics.as_str(),
package = expected.mono_layout.item_info().package(),
expected_package_version = expected.mono_layout.item_info().version(),
expected_field_count = expected.get_field_names().count(),
actual_package_version = actual.mono_layout.item_info().version(),
actual_field_count = actual.get_field_names().count(),
);
}