use std::{
marker::PhantomData,
mem,
};
use crate::{
abi_stability::{
type_layout::{TypeLayout,TLField,TLData},
},
ignored_wrapper::CmpIgnored,
marker_type::NotCopyNotClone,
std_types::{StaticSlice,StaticStr},
utils::leak_value,
version::VersionStrings,
};
use core_extensions::SelfOps;
pub unsafe trait PrefixTypeTrait:Sized{
const METADATA:WithMetadataFor<Self,Self::Prefix>=WithMetadataFor{
_prefix_type_field_count:Self::PT_FIELD_COUNT,
_prefix_type_layout:Self::PT_LAYOUT,
_marker:PhantomData,
};
const PT_LAYOUT:&'static PTStructLayout;
const PT_FIELD_COUNT:usize;
type Prefix;
fn into_with_metadata(self)->WithMetadata<Self>{
WithMetadata::new(Self::METADATA,self)
}
fn leak_into_prefix<'a>(self)->&'a Self::Prefix
where
Self:'a,
Self::Prefix:'a
{
self.into_with_metadata()
.piped(leak_value)
.as_prefix()
}
}
pub type WithMetadata<T>=
WithMetadata_<T,<T as PrefixTypeTrait>::Prefix>;
#[repr(C)]
pub struct WithMetadata_<T,P>{
#[inline(doc)]
pub _prefix_type_field_count:usize,
#[inline(doc)]
pub _prefix_type_layout:&'static PTStructLayout,
pub original:T,
_marker:PhantomData<P>,
unbounds:NotCopyNotClone,
}
impl<T,P> WithMetadata_<T,P> {
pub const fn new(metadata:WithMetadataFor<T,P>,value:T)->Self{
Self{
_prefix_type_field_count:metadata._prefix_type_field_count,
_prefix_type_layout :metadata._prefix_type_layout,
original:value,
_marker:PhantomData,
unbounds:NotCopyNotClone,
}
}
pub fn as_prefix(&self)->&P {
unsafe{
&*self.as_prefix_raw()
}
}
pub const fn as_prefix_raw(&self)->*const P {
unsafe{
self as *const Self as *const P
}
}
}
#[repr(C)]
pub struct WithMetadataFor<T,P>{
#[inline(doc)]
_prefix_type_field_count:usize,
#[inline(doc)]
_prefix_type_layout:&'static PTStructLayout,
_marker:PhantomData<fn()->(T,P)>,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, StableAbi)]
#[sabi(inside_abi_stable_crate)]
pub struct PTStructLayout {
pub name: StaticStr,
pub generics:CmpIgnored<StaticStr>,
pub package: StaticStr,
pub package_version: VersionStrings,
pub file:CmpIgnored<StaticStr>,
pub line:CmpIgnored<u32>,
pub size: usize,
pub alignment: usize,
pub fields:StaticSlice<PTField>,
}
pub struct PTStructLayoutParams{
pub name: &'static str,
pub generics:&'static str,
pub package: &'static str,
pub package_version: VersionStrings,
pub file:&'static str,
pub line:u32,
pub fields:&'static [PTField],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, StableAbi)]
#[sabi(inside_abi_stable_crate)]
pub struct PTField {
pub name:StaticStr,
pub ty:CmpIgnored<StaticStr>,
pub size:usize,
pub alignment:usize,
}
impl PTStructLayout{
pub const fn new<T>(params:PTStructLayoutParams)->Self{
Self{
name:StaticStr::new(params.name),
generics:CmpIgnored::new(StaticStr::new(params.generics)),
package:StaticStr::new(params.package),
package_version:params.package_version,
file:CmpIgnored::new(StaticStr::new(params.file)),
line:CmpIgnored::new(params.line),
size:mem::size_of::<T>(),
alignment:mem::align_of::<T>(),
fields:StaticSlice::new(params.fields),
}
}
}
impl PTField{
pub const fn new<T>(name:&'static str ,ty:&'static str)->Self{
Self{
name:StaticStr::new(name),
ty:CmpIgnored::new(StaticStr::new(ty)),
size:mem::size_of::<T>(),
alignment:mem::align_of::<T>(),
}
}
}
#[derive(Debug,Copy,Clone)]
pub struct PrefixTypeMetadata{
pub prefix_field_count:usize,
pub fields:StaticSlice<TLField>,
pub layout:&'static TypeLayout,
}
impl PrefixTypeMetadata{
pub fn new(layout:&'static TypeLayout)->Self{
let (first_suffix_field,fields)=match layout.data {
TLData::PrefixType{first_suffix_field,fields}=>
(first_suffix_field,fields),
_=>panic!(
"Attempting to construct a PrefixTypeMetadata from a \
TypeLayout of a non-prefix-type.\n\
Type:{}\nDataVariant:{:?}\nPackage:{}",
layout.full_type,
layout.data.discriminant(),
layout.package,
),
};
Self{
fields:fields,
prefix_field_count:first_suffix_field,
layout,
}
}
pub fn max(self,other:Self)->Self{
if self.fields.len() < other.fields.len() {
other
}else{
self
}
}
pub fn min_max(self,other:Self)->(Self,Self){
if self.fields.len() < other.fields.len() {
(self,other)
}else{
(other,self)
}
}
}
#[cold]
#[inline(never)]
pub fn panic_on_missing_field_ty<T>(field_index:usize,actual_layout:&'static PTStructLayout)->!
where T:PrefixTypeTrait
{
panic_on_missing_field_val(field_index,T::PT_LAYOUT,actual_layout)
}
#[cold]
#[inline(never)]
pub fn panic_on_missing_field_val(
field_index:usize,
expected:&'static PTStructLayout,
actual:&'static PTStructLayout,
)->! {
let field=expected.fields[field_index];
panic!("\n
Attempting to access nonexistent field:
index:{index}
named:{field_named}
type(as declared):{field_type}
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.as_str(),
field_type=field.ty.as_str(),
struct_name=expected.name.as_str(),
struct_generics=expected.generics.as_str(),
package=expected.package,
expected_package_version =expected.package_version ,
expected_field_count=expected.fields.len(),
actual_package_version =actual.package_version ,
actual_field_count=actual.fields.len(),
);
}