Skip to content

Commit

Permalink
Improve enum discriminant descriptor
Browse files Browse the repository at this point in the history
  • Loading branch information
juntyr committed Dec 8, 2023
1 parent ac5ad2c commit 6ae83c1
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 180 deletions.
37 changes: 8 additions & 29 deletions const-type-layout-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,16 @@ pub fn derive_type_layout(input: TokenStream) -> TokenStream {

let inner_types = extract_inner_types(&input.data);

let discriminant_ty = if let syn::Data::Enum(_) = input.data {
Some(quote! { <Self as #crate_path::ExtractDiscriminant>::Ty, })
} else {
None
};

let Generics {
type_layout_input_generics,
type_set_input_generics,
} = generate_generics(
&crate_path,
&ty_name,
&ty_generics,
&input.generics,
matches!(input.data, syn::Data::Enum(_)),
&extra_bounds,
&type_params,
);
} = generate_generics(&crate_path, &input.generics, &extra_bounds, &type_params);
let (type_layout_impl_generics, type_layout_ty_generics, type_layout_where_clause) =
type_layout_input_generics.split_for_impl();
let (type_set_impl_generics, type_set_ty_generics, type_set_where_clause) =
Expand Down Expand Up @@ -84,7 +82,7 @@ pub fn derive_type_layout(input: TokenStream) -> TokenStream {
{
type Output<__TypeSetRest: #crate_path::typeset::ExpandTypeSet> =
#crate_path::typeset::Set<Self, #crate_path::typeset::tset![
#(#inner_types,)* .. @ __TypeSetRest
#(#inner_types,)* #discriminant_ty .. @ __TypeSetRest
]>;
}
}
Expand Down Expand Up @@ -383,32 +381,13 @@ struct Generics {

fn generate_generics(
crate_path: &syn::Path,
ty_name: &syn::Ident,
ty_generics: &syn::TypeGenerics,
generics: &syn::Generics,
is_enum: bool,
extra_bounds: &[syn::WherePredicate],
type_params: &[&syn::Ident],
) -> Generics {
let mut type_layout_input_generics = generics.clone();
let mut type_set_input_generics = generics.clone();

if is_enum {
type_layout_input_generics
.make_where_clause()
.predicates
.push(syn::parse_quote! {
[u8; ::core::mem::size_of::<::core::mem::Discriminant<#ty_name #ty_generics>>()]:
});

type_set_input_generics
.make_where_clause()
.predicates
.push(syn::parse_quote! {
[u8; ::core::mem::size_of::<::core::mem::Discriminant<#ty_name #ty_generics>>()]:
});
}

for ty in type_params {
type_layout_input_generics
.make_where_clause()
Expand Down
17 changes: 8 additions & 9 deletions src/impls/core/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ use crate::{
Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant,
};

unsafe impl<T: ~const TypeLayout> const TypeLayout for core::option::Option<T>
where
[u8; core::mem::size_of::<core::mem::Discriminant<Self>>()]:,
{
unsafe impl<T: ~const TypeLayout> const TypeLayout for core::option::Option<T> {
const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo {
name: ::core::any::type_name::<Self>(),
size: ::core::mem::size_of::<Self>(),
Expand Down Expand Up @@ -41,9 +38,11 @@ where
}
}

unsafe impl<T: ComputeTypeSet> ComputeTypeSet for core::option::Option<T>
where
[u8; core::mem::size_of::<core::mem::Discriminant<Self>>()]:,
{
type Output<R: ExpandTypeSet> = Set<Self, tset![T, .. @ R]>;
unsafe impl<T: ComputeTypeSet> ComputeTypeSet for core::option::Option<T> {
type Output<R: ExpandTypeSet> = Set<
Self,
tset![
T, <Self as crate::ExtractDiscriminant>::Ty, .. @ R
],
>;
}
14 changes: 7 additions & 7 deletions src/impls/core/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use crate::{

unsafe impl<T: ~const TypeLayout, E: ~const TypeLayout> const TypeLayout
for core::result::Result<T, E>
where
[u8; core::mem::size_of::<core::mem::Discriminant<Self>>()]:,
{
const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo {
name: ::core::any::type_name::<Self>(),
Expand Down Expand Up @@ -58,9 +56,11 @@ where
}
}

unsafe impl<T: ComputeTypeSet, E: ComputeTypeSet> ComputeTypeSet for core::result::Result<T, E>
where
[u8; core::mem::size_of::<core::mem::Discriminant<Self>>()]:,
{
type Output<R: ExpandTypeSet> = Set<Self, tset![E, .. @ R]>;
unsafe impl<T: ComputeTypeSet, E: ComputeTypeSet> ComputeTypeSet for core::result::Result<T, E> {
type Output<R: ExpandTypeSet> = Set<
Self,
tset![
T, E, <Self as crate::ExtractDiscriminant>::Ty, .. @ R
],
>;
}
223 changes: 95 additions & 128 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
#![feature(const_maybe_uninit_array_assume_init)]
#![feature(c_variadic)]
#![feature(ptr_from_ref)]
#![feature(discriminant_kind)]
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
#![feature(specialization)]
Expand Down Expand Up @@ -355,15 +356,77 @@ pub enum TypeStructure<
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
pub struct Variant<'a, F: Deref<Target = [Field<'a>]> = &'a [Field<'a>]> {
pub name: &'a str,
pub discriminant: MaybeUninhabited<Discriminant<'a>>,
pub discriminant: MaybeUninhabited<Discriminant>,
pub fields: F,
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
#[repr(transparent)]
pub struct Discriminant<'a> {
pub big_endian_bytes: &'a [u8],
pub enum Discriminant {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
Isize(isize),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
Usize(usize),
}

#[const_trait]
pub trait ExtractDiscriminant {
type Ty: typeset::ComputeTypeSet;

fn discriminant(&self) -> Discriminant;
}

impl<T> const ExtractDiscriminant for T {
type Ty =
<T as ExtractDiscriminantSpec<<T as core::marker::DiscriminantKind>::Discriminant>>::Ty;

fn discriminant(&self) -> Discriminant {
<T as ExtractDiscriminantSpec<<T as core::marker::DiscriminantKind>::Discriminant>>::discriminant(self)
}
}

#[doc(hidden)]
#[const_trait]
pub trait ExtractDiscriminantSpec<T> {
type Ty: typeset::ComputeTypeSet;

fn discriminant(&self) -> Discriminant;
}

impl<T> const ExtractDiscriminantSpec<<T as core::marker::DiscriminantKind>::Discriminant> for T {
default type Ty = !;

default fn discriminant(&self) -> Discriminant {
panic!("bug: unknown discriminant kind")
}
}

macro_rules! impl_extract_discriminant {
($variant:ident($ty:ty)) => {
impl<T: core::marker::DiscriminantKind<Discriminant = $ty>> const ExtractDiscriminantSpec<$ty> for T {
type Ty = $ty;

fn discriminant(&self) -> Discriminant {
Discriminant::$variant(core::intrinsics::discriminant_value(self))
}
}
};
($($variant:ident($ty:ty)),*) => {
$(impl_extract_discriminant! { $variant($ty) })*
};
}

impl_extract_discriminant! {
I8(i8), I16(i16), I32(i32), I64(i64), I128(i128), Isize(isize),
U8(u8), U16(u16), U32(u32), U64(u64), U128(u128), Usize(usize)
}

#[derive(Clone, Copy, Debug, Hash)]
Expand Down Expand Up @@ -468,28 +531,6 @@ impl<'a, F: Deref<Target = [Field<'a>]> + PartialOrd> PartialOrd for Variant<'a,
}
}

impl<'a> fmt::Debug for Discriminant<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "0x")?;

let mut is_zero = true;

for byte in self.big_endian_bytes.iter().copied() {
if byte != 0_u8 {
is_zero = false;

write!(fmt, "{byte:x}")?;
}
}

if is_zero {
write!(fmt, "0")?;
}

Ok(())
}
}

impl<'a> PartialEq for Field<'a> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.offset == other.offset && core::ptr::eq(self.ty, other.ty)
Expand Down Expand Up @@ -541,81 +582,33 @@ pub macro struct_field_offset($ty_name:ident => $ty:ty => (*$base:ident).$field:
#[doc(hidden)]
#[allow_internal_unstable(const_discriminant)]
pub macro struct_variant_discriminant {
($ty_name:ident => $ty:ty => $variant_name:ident) => {
$crate::MaybeUninhabited::Inhabited {
0: $crate::Discriminant {
big_endian_bytes: &{
let uninit: $ty = $ty_name::$variant_name;

let system_endian_bytes: [u8; ::core::mem::size_of::<::core::mem::Discriminant<$ty>>()] = unsafe {
::core::mem::transmute(::core::mem::discriminant(&uninit))
};
($ty_name:ident => $ty:ty => $variant_name:ident) => {{
let uninit: $ty = $ty_name::$variant_name;

#[allow(clippy::forget_non_drop, clippy::forget_copy)]
::core::mem::forget(uninit);
let discriminant = <$ty as $crate::ExtractDiscriminant>::discriminant(&uninit);

let mut big_endian_bytes = [0_u8; ::core::mem::size_of::<::core::mem::Discriminant<$ty>>()];
#[allow(clippy::forget_non_drop, clippy::forget_copy)]
::core::mem::forget(uninit);

let mut i = 0;

while i < system_endian_bytes.len() {
big_endian_bytes[i] = system_endian_bytes[if cfg!(target_endian = "big") {
i
} else {
system_endian_bytes.len() - i - 1
}];

i += 1;
}

big_endian_bytes
},
},
}
},
$crate::MaybeUninhabited::Inhabited(discriminant)
}},
($ty_name:ident => $ty:ty => $variant_name:ident($($field_name:ident: $field_ty:ty),* $(,)?)) => {{
#[allow(unused_parens)]
if let (
$($crate::MaybeUninhabited::Inhabited($field_name)),*
) = (
$(unsafe { <$field_ty as $crate::TypeLayout>::uninit() }),*
) {
$crate::MaybeUninhabited::Inhabited {
0: $crate::Discriminant {
big_endian_bytes: {
let uninit: $ty = $ty_name::$variant_name(
$(unsafe { $field_name.assume_init() }),*
);

let system_endian_bytes: [u8; ::core::mem::size_of::<::core::mem::Discriminant<$ty>>()] = unsafe {
::core::mem::transmute(::core::mem::discriminant(&uninit))
};

#[allow(clippy::forget_non_drop, clippy::forget_copy)]
::core::mem::forget(uninit);

let big_endian_bytes = unsafe {
&mut *$crate::impls::leak_uninit_ptr::<
[u8; ::core::mem::size_of::<::core::mem::Discriminant<$ty>>()]
>()
};

let mut i = 0;

while i < system_endian_bytes.len() {
(*big_endian_bytes)[i] = system_endian_bytes[if cfg!(target_endian = "big") {
i
} else {
system_endian_bytes.len() - i - 1
}];

i += 1;
}

big_endian_bytes
}
},
}
let uninit: $ty = $ty_name::$variant_name(
$(unsafe { $field_name.assume_init() }),*
);

let discriminant = <$ty as $crate::ExtractDiscriminant>::discriminant(&uninit);

#[allow(clippy::forget_non_drop, clippy::forget_copy)]
::core::mem::forget(uninit);

$crate::MaybeUninhabited::Inhabited(discriminant)
} else {
$crate::MaybeUninhabited::Uninhabited
}
Expand All @@ -627,42 +620,16 @@ pub macro struct_variant_discriminant {
) = (
$(unsafe { <$field_ty as $crate::TypeLayout>::uninit() }),*
) {
$crate::MaybeUninhabited::Inhabited {
0: $crate::Discriminant {
big_endian_bytes: {
let uninit: $ty = $ty_name::$variant_name {
$($field_name: unsafe { $field_name.assume_init() }),*
};

let system_endian_bytes: [u8; ::core::mem::size_of::<::core::mem::Discriminant<$ty>>()] = unsafe {
::core::mem::transmute(::core::mem::discriminant(&uninit))
};

#[allow(clippy::forget_non_drop, clippy::forget_copy)]
::core::mem::forget(uninit);

let big_endian_bytes = unsafe {
&mut *$crate::impls::leak_uninit_ptr::<
[u8; ::core::mem::size_of::<::core::mem::Discriminant<$ty>>()]
>()
};

let mut i = 0;

while i < system_endian_bytes.len() {
(*big_endian_bytes)[i] = system_endian_bytes[if cfg!(target_endian = "big") {
i
} else {
system_endian_bytes.len() - i - 1
}];

i += 1;
}

big_endian_bytes
}
},
}
let uninit: $ty = $ty_name::$variant_name {
$($field_name: unsafe { $field_name.assume_init() }),*
};

let discriminant = <$ty as $crate::ExtractDiscriminant>::discriminant(&uninit);

#[allow(clippy::forget_non_drop, clippy::forget_copy)]
::core::mem::forget(uninit);

$crate::MaybeUninhabited::Inhabited(discriminant)
} else {
$crate::MaybeUninhabited::Uninhabited
}
Expand Down
Loading

0 comments on commit 6ae83c1

Please sign in to comment.