use super::*;
use crate::{
abi_stability::abi_checking::{push_err, AbiInstability},
const_utils::log2_usize,
std_types::{RSlice, RString, RVec},
};
#[repr(C)]
#[derive(Copy, Clone, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct MonoTLEnum {
field_count: *const u8,
field_count_len: u16,
variant_names: StartLen,
pub(super) fields: CompTLFields,
}
unsafe impl Sync for MonoTLEnum {}
unsafe impl Send for MonoTLEnum {}
impl MonoTLEnum {
pub const fn new(
variant_names: StartLen,
field_count: RSlice<'static, u8>,
fields: CompTLFields,
) -> Self {
Self {
field_count: field_count.as_ptr(),
field_count_len: field_count.len() as u16,
variant_names,
fields,
}
}
pub const fn variant_count(&self) -> usize {
self.field_count_len as usize
}
pub const fn field_count(&self) -> RSlice<'static, u8> {
unsafe { RSlice::from_raw_parts(self.field_count, self.field_count_len as usize) }
}
pub fn expand(self, other: GenericTLEnum, shared_vars: &'static SharedVars) -> TLEnum {
TLEnum {
field_count: self.field_count(),
variant_names: (&shared_vars.strings()[self.variant_names.to_range()]).into(),
fields: self.fields.expand(shared_vars),
exhaustiveness: other.exhaustiveness,
discriminants: other.discriminants,
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct GenericTLEnum {
exhaustiveness: IsExhaustive,
discriminants: TLDiscriminants,
}
impl GenericTLEnum {
pub const fn new(exhaustiveness: IsExhaustive, discriminants: TLDiscriminants) -> Self {
Self {
exhaustiveness,
discriminants,
}
}
pub const fn exhaustive(discriminants: TLDiscriminants) -> Self {
Self::new(IsExhaustive::exhaustive(), discriminants)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TLEnum {
pub field_count: RSlice<'static, u8>,
pub variant_names: RStr<'static>,
pub fields: TLFields,
pub exhaustiveness: IsExhaustive,
pub discriminants: TLDiscriminants,
}
impl TLEnum {
pub const fn variant_count(&self) -> usize {
self.field_count.len()
}
pub fn variant_names_iter(
&self,
) -> impl ExactSizeIterator<Item = &'static str> + Clone + Debug + 'static {
GetVariantNames {
split: self.variant_names.as_str().split(';'),
length: self.field_count.len(),
current: 0,
}
}
pub const fn max_min<'a>(&'a self, other: &'a TLEnum) -> (&'a TLEnum, &'a TLEnum) {
if self.variant_count() < other.variant_count() {
(self, other)
} else {
(other, self)
}
}
}
impl Display for TLEnum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "variants:{:?}", self.variant_names)?;
writeln!(
f,
"fields(all variants combined):\n{}",
self.fields.to_string().left_padder(4)
)?;
writeln!(f, "field counts(per-variant):{:?}", self.field_count)?;
writeln!(f, "exhaustiveness:{:?}", self.exhaustiveness)?;
writeln!(f, "discriminants:{:?}", self.discriminants)?;
Ok(())
}
}
macro_rules! declare_tl_discriminants {
(
$((
$(#[$variant_attr:meta])*
$variant:ident ( $ty:ty ),
$single:ident,
$(#[$method_attr:meta])*
$method:ident
))*
) => (
/// The discriminants of an enum.
#[repr(C)]
#[derive(Copy, Clone, StableAbi)]
pub struct TLDiscriminants{
inner:TLDiscrsInner,
}
unsafe impl Sync for TLDiscriminants {}
unsafe impl Send for TLDiscriminants {}
#[repr(u8)]
#[derive(Copy, Clone, StableAbi)]
enum TLDiscrsInner{
$(
$(#[$variant_attr])*
$variant{
len:u16,
discriminants:*const $ty,
},
)*
}
impl Debug for TLDiscriminants{
fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{
match self.inner {
$(
TLDiscrsInner::$variant{discriminants,len}=>unsafe{
let slice=std::slice::from_raw_parts(discriminants,len as usize);
Debug::fmt(slice,f)
}
)*
}
}
}
impl PartialEq for TLDiscriminants {
fn eq(&self,other:&Self)->bool{
match (self.inner,other.inner) {
$(
(
TLDiscrsInner::$variant{discriminants: t_discr_ptr, len:t_len },
TLDiscrsInner::$variant{discriminants: o_discr_ptr, len:o_len }
)=>{
let t_discrs=unsafe{
RSlice::from_raw_parts(t_discr_ptr,t_len as usize)
};
let o_discrs=unsafe{
RSlice::from_raw_parts(o_discr_ptr,o_len as usize)
};
t_discrs==o_discrs
}
)*
_=>false,
}
}
}
impl Eq for TLDiscriminants{}
impl TLDiscriminants{
$(
$(#[$method_attr])*
pub const fn $method(arr:RSlice<'static,$ty>)->Self{
let inner=TLDiscrsInner::$variant{
len:arr.len() as u16,
discriminants:arr.as_ptr(),
};
TLDiscriminants{inner}
}
)*
pub const fn discriminant_repr(&self)->DiscriminantRepr{
match self.inner {
$(
TLDiscrsInner::$variant{..}=>DiscriminantRepr::$variant,
)*
}
}
pub fn compare(&self,other:&Self)->Result<(),RVec<AbiInstability>>{
let mut errs=RVec::new();
match (self.inner,other.inner) {
$(
(
TLDiscrsInner::$variant{discriminants: t_discr_ptr, len:t_len },
TLDiscrsInner::$variant{discriminants: o_discr_ptr, len:o_len }
)=>{
let t_discrs=unsafe{
RSlice::from_raw_parts(t_discr_ptr,t_len as usize)
};
let o_discrs=unsafe{
RSlice::from_raw_parts(o_discr_ptr,o_len as usize)
};
for (&t_discr,&o_discr) in
t_discrs.as_slice().iter().zip(o_discrs.as_slice())
{
if t_discr!=o_discr {
push_err(
&mut errs,
t_discr,
o_discr,
|x| TLDiscriminant::$single(x as _),
AbiInstability::EnumDiscriminant,
);
}
}
}
)*
_=>{
push_err(
&mut errs,
self,
other,
|x| ReprAttr::Int(x.discriminant_repr()),
AbiInstability::ReprAttr
);
}
}
if errs.is_empty(){
Ok(())
}else{
Err(errs)
}
}
}
)
}
declare_tl_discriminants! {
(
U8(u8) ,
Signed ,
from_u8_slice
)
(
I8(i8) ,
Unsigned,
from_i8_slice
)
(
U16(u16) ,
Signed ,
from_u16_slice
)
(
I16(i16) ,
Unsigned,
from_i16_slice
)
(
U32(u32) ,
Signed ,
from_u32_slice
)
(
I32(i32) ,
Unsigned,
from_i32_slice
)
(
U64(u64) ,
Signed ,
from_u64_slice
)
(
I64(i64) ,
Unsigned,
from_i64_slice
)
(
Usize(usize) ,
Usize,
from_usize_slice
)
(
Isize(isize) ,
Isize,
from_isize_slice
)
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub enum TLDiscriminant {
Isize(isize),
Usize(usize),
Signed(i64),
Unsigned(u64),
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub enum DiscriminantRepr {
U8,
I8,
U16,
I16,
U32,
I32,
U64,
I64,
U128,
I128,
Usize,
Isize,
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct IsExhaustive {
value: Option<&'static TLNonExhaustive>,
}
impl IsExhaustive {
pub const fn exhaustive() -> IsExhaustive {
IsExhaustive { value: None }
}
pub const fn nonexhaustive(nonexhaustive: &'static TLNonExhaustive) -> IsExhaustive {
IsExhaustive {
value: Some(nonexhaustive),
}
}
pub const fn is_exhaustive(&self) -> bool {
self.value.is_none()
}
pub const fn is_nonexhaustive(&self) -> bool {
self.value.is_some()
}
pub const fn as_nonexhaustive(&self) -> Option<&'static TLNonExhaustive> {
self.value
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct TLNonExhaustive {
original_size: usize,
original_alignment_pow2: u8,
}
impl TLNonExhaustive {
pub const fn new<T>() -> Self {
Self {
original_size: std::mem::size_of::<T>(),
original_alignment_pow2: log2_usize(mem::align_of::<T>()),
}
}
#[inline]
const fn original_size(&self) -> usize {
self.original_size
}
#[inline]
const fn original_alignment(&self) -> usize {
1_usize << (self.original_alignment_pow2 as u32)
}
pub fn check_compatible(
&self,
layout: &TypeLayout,
) -> Result<(), IncompatibleWithNonExhaustive> {
let err =
layout.size() < self.original_size() || layout.alignment() < self.original_alignment();
if err {
Err(IncompatibleWithNonExhaustive {
full_type: layout.full_type().to_string().into(),
module_path: layout.mod_path(),
type_size: self.original_size(),
type_alignment: self.original_alignment(),
storage_size: layout.size(),
storage_alignment: layout.alignment(),
})
} else {
Ok(())
}
}
}
#[doc(hidden)]
pub struct MakeTLNonExhaustive<T>(T);
impl<T> MakeTLNonExhaustive<T> {
pub const NEW: TLNonExhaustive = TLNonExhaustive::new::<T>();
}
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Eq, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct IncompatibleWithNonExhaustive {
full_type: RString,
module_path: ModPath,
type_size: usize,
type_alignment: usize,
storage_size: usize,
storage_alignment: usize,
}
impl Display for IncompatibleWithNonExhaustive {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Type '{ty}' has an incompatible layout for the storage.\n\
Type size:{t_size} alignment:{t_align}
Storage size:{s_size} alignment:{s_align}
module_path:{mod_}
",
ty = self.full_type,
t_size = self.type_size,
t_align = self.type_alignment,
s_size = self.storage_size,
s_align = self.storage_alignment,
mod_ = self.module_path,
)
}
}
impl std::error::Error for IncompatibleWithNonExhaustive {}
#[derive(Debug, Clone)]
struct GetVariantNames {
split: std::str::Split<'static, char>,
length: usize,
current: usize,
}
impl Iterator for GetVariantNames {
type Item = &'static str;
fn next(&mut self) -> Option<Self::Item> {
if self.length == self.current {
return None;
}
let current = self.current;
self.current += 1;
match self.split.next().filter(|&x| !x.is_empty() || x == "_") {
Some(x) => Some(x),
None => Some(VARIANT_INDEX[current]),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.length - self.current;
(len, Some(len))
}
fn count(self) -> usize {
self.length - self.current
}
}
impl std::iter::ExactSizeIterator for GetVariantNames {}
static VARIANT_INDEX: [&str; 68] = [
"Variant0",
"Variant1",
"Variant2",
"Variant3",
"Variant4",
"Variant5",
"Variant6",
"Variant7",
"Variant8",
"Variant9",
"Variant10",
"Variant11",
"Variant12",
"Variant13",
"Variant14",
"Variant15",
"Variant16",
"Variant17",
"Variant18",
"Variant19",
"Variant20",
"Variant21",
"Variant22",
"Variant23",
"Variant24",
"Variant25",
"Variant26",
"Variant27",
"Variant28",
"Variant29",
"Variant30",
"Variant31",
"Variant32",
"Variant33",
"Variant34",
"Variant35",
"Variant36",
"Variant37",
"Variant38",
"Variant39",
"Variant40",
"Variant41",
"Variant42",
"Variant43",
"Variant44",
"Variant45",
"Variant46",
"Variant47",
"Variant48",
"Variant49",
"Variant50",
"Variant51",
"Variant52",
"Variant53",
"Variant54",
"Variant55",
"Variant56",
"Variant57",
"Variant58",
"Variant59",
"Variant60",
"Variant61",
"Variant62",
"Variant63",
"Variant64",
"Variant65",
"Variant66",
"Variant67",
];