diff --git a/const-type-layout-derive/src/lib.rs b/const-type-layout-derive/src/lib.rs index 53858bf..cf2fe9d 100644 --- a/const-type-layout-derive/src/lib.rs +++ b/const-type-layout-derive/src/lib.rs @@ -78,22 +78,18 @@ pub fn derive_type_layout(input: TokenStream) -> TokenStream { let inhabited = inhabited_for_type(&crate_path, &input.data); let layout = layout_of_type(&crate_path, &ty_name, &ty_generics, &input.data, &reprs); - let inner_types = extract_inner_types(&input.data); - - let discriminant_ty = if let syn::Data::Enum(_) = input.data { - Some(quote! { ::core::mem::Discriminant, }) - } else { - None - }; - - let Generics { - type_layout_input_generics, - type_set_input_generics, - } = generate_generics(&crate_path, &input.generics, &extra_bounds, &type_params); + let mut inner_types = extract_inner_types(&input.data); + + let discriminant_ty: syn::Type; + if let syn::Data::Enum(_) = input.data { + discriminant_ty = syn::parse_quote! { ::core::mem::Discriminant }; + inner_types.push(&discriminant_ty); + } + + let type_layout_input_generics = + 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) = - type_set_input_generics.split_for_impl(); quote! { unsafe impl #type_layout_impl_generics #crate_path::TypeLayout for @@ -109,15 +105,8 @@ pub fn derive_type_layout(input: TokenStream) -> TokenStream { structure: #layout, } }; - } - unsafe impl #type_set_impl_generics #crate_path::typeset::ComputeTypeSet for - #ty_name #type_set_ty_generics #type_set_where_clause - { - type Output<__TypeSetRest: #crate_path::typeset::ExpandTypeSet> = - #crate_path::typeset::tset![ - #(#inner_types,)* #discriminant_ty .. @ __TypeSetRest - ]; + type TypeGraphEdges = #crate_path::graph::hlist![#(#inner_types),*]; } } .into() @@ -308,19 +297,13 @@ fn extract_inner_types(data: &syn::Data) -> Vec<&syn::Type> { inner_types } -struct Generics { - type_layout_input_generics: syn::Generics, - type_set_input_generics: syn::Generics, -} - fn generate_generics( crate_path: &syn::Path, generics: &syn::Generics, extra_bounds: &[syn::WherePredicate], type_params: &[&syn::Ident], -) -> Generics { +) -> syn::Generics { let mut type_layout_input_generics = generics.clone(); - let mut type_set_input_generics = generics.clone(); for ty in type_params { type_layout_input_generics @@ -329,13 +312,6 @@ fn generate_generics( .push(syn::parse_quote! { #ty: #crate_path::TypeLayout }); - - type_set_input_generics - .make_where_clause() - .predicates - .push(syn::parse_quote! { - #ty: #crate_path::typeset::ComputeTypeSet - }); } for bound in extra_bounds { @@ -343,17 +319,9 @@ fn generate_generics( .make_where_clause() .predicates .push(bound.clone()); - - type_set_input_generics - .make_where_clause() - .predicates - .push(bound.clone()); } - Generics { - type_layout_input_generics, - type_set_input_generics, - } + type_layout_input_generics } fn layout_of_type( diff --git a/src/graph.rs b/src/graph.rs new file mode 100644 index 0000000..56f6f26 --- /dev/null +++ b/src/graph.rs @@ -0,0 +1,276 @@ +#![allow(missing_docs)] // FIXME + +use core::{marker::Freeze, mem::MaybeUninit}; + +use crate::{TypeLayout, TypeLayoutInfo}; + +pub(crate) use private::TypeHList; + +pub macro hlist { + () => { private::Empty }, + ($H:ty $(, $R:ty)*) => { + private::Cons<$H, hlist![$($R),*]> + }, +} + +#[allow(clippy::module_name_repetitions)] +#[must_use] +pub const fn type_layout_graph() -> &'static [&'static TypeLayoutInfo<'static>] { + expand_type_layout_stack_graph_into_static_slice::(None) +} + +// compute the type graph by keeping an on-stack linked list of already-seen +// types +// as the stack graph is computed, accumulate the hlist type that is layout- +// equivalent to an array storing all of the type layouts +// once the graph is computed on the stack, recompute it inside a const using +// the now-known type of the hlist +// a static slice to the array of type layouts is returned +const fn expand_type_layout_stack_graph_into_static_slice< + GraphRoot: TypeLayout, + GraphNodesArray: 'static + Copy + Freeze + private::HList, + T: TypeLayout, + RemainingTypes: private::TypeHList, +>( + tys: Option<&GraphStackNode>, +) -> &'static [&'static TypeLayoutInfo<'static>] { + let layout = &T::TYPE_LAYOUT; + + // check if this type has already been inserted into the graph + let mut it = &tys; + while let Some(i) = it { + if type_layout_info_eq(i.ty, layout) { + // if no types remain, continue by computing the graph again, this + // time in a const with the now-known array hlist type + if RemainingTypes::LEN == 0 { + return compute_type_layout_graph_static_slice::(); + } + + // if more types remain, continue with recursion + return expand_type_layout_stack_graph_into_static_slice::< + GraphRoot, + GraphNodesArray, + RemainingTypes::Head, + RemainingTypes::Tail, + >(tys); + } + + it = &i.next; + } + + if <::Concat as private::HList>::LEN + == 0 + { + // if no types remain, also considering the links from T, continue by + // computing the graph again, this time in a const with the now-known + // array hlist type + // the GraphNodesArray HList is extended by one element for T + return compute_type_layout_graph_static_slice::< + GraphRoot, + private::Cons<&'static TypeLayoutInfo<'static>, GraphNodesArray>, + >(); + } + + // if more types remain, continue with recursion, adding the links from T + // to the stack of remaining types + // the GraphNodesArray HList is extended by one element for T + expand_type_layout_stack_graph_into_static_slice::< + GraphRoot, + private::Cons<&'static TypeLayoutInfo<'static>, GraphNodesArray>, + <::Concat as private::TypeHList>::Head, + <::Concat as private::TypeHList>::Tail, + >(Some(&GraphStackNode { + ty: layout, + next: tys, + })) +} + +// on-stack linked list node that stores one type layout +struct GraphStackNode<'a> { + ty: &'static TypeLayoutInfo<'static>, + next: Option<&'a Self>, +} + +// transform the static reference to the hlist that's layout-equivalent to the +// array storing all type layouts into a static slice to the same array +const fn compute_type_layout_graph_static_slice< + GraphRoot: TypeLayout, + GraphNodesArray: 'static + Copy + Freeze + private::HList, +>() -> &'static [&'static TypeLayoutInfo<'static>] { + // SAFETY: + // - HList is a sealed trait and is constructed here to be made of only Cons of + // TypeLayoutInfo and Empty + // - Cons is a repr(C) struct with a head followed by a tail, Empty is a + // zero-sized repr(C) struct + // - the HList is layout-equivalent to an array of the same length as HList::LEN + // - fill_type_layout_graph_erased_reference provides a static non-dangling + // reference that we can use to produce the data pointer for a slice + unsafe { + core::slice::from_raw_parts( + core::ptr::from_ref(compute_type_layout_graph_static_array_ref::< + GraphRoot, + GraphNodesArray, + >()) + .cast(), + GraphNodesArray::LEN, + ) + } +} + +// create a static reference to the type layout hlist using an inline const +const fn compute_type_layout_graph_static_array_ref< + GraphRoot: TypeLayout, + GraphNodesArray: 'static + Copy + Freeze + private::HList, +>() -> &'static GraphNodesArray { + &const { compute_type_layout_graph_array::() } +} + +// create the hlist that's layout-equivalent to the array storing all type +// layouts and fill it with these type layouts +const fn compute_type_layout_graph_array( +) -> GraphNodesArray { + // layout-compatible with MaybeUninit::<[_; LEN]>::uninit() + let mut graph = MaybeUninit::::uninit(); + + // SAFETY: + // - HList is a sealed trait and is constructed here to be made of only Cons of + // TypeLayoutInfo and Empty + // - Cons is a repr(C) struct with a head followed by a tail, Empty is a + // zero-sized repr(C) struct + // - the HList is layout-equivalent to an array of the same length as HList::LEN + // - the mutable slice is to a slice of uninit elements, and an uninit array can + // always be accessed as an array of uninit elements + let graph_slice = unsafe { + core::slice::from_raw_parts_mut( + core::ptr::from_mut(&mut graph).cast(), + GraphNodesArray::LEN, + ) + }; + let graph_len = fill_type_layout_graph_slice::(graph_slice, 0); + + assert!( + graph_len == GraphNodesArray::LEN, + "bug: initialized graph has the wrong size" + ); + + // Safety: we have just checked that all array elements have been initialized + unsafe { graph.assume_init() } +} + +// compute the type graph by filling a slice of uninitialized type layouts and +// using it to check which types have already been seen +// once the graph is computed, return the number of elements initialized +const fn fill_type_layout_graph_slice( + tys: &mut [MaybeUninit<&'static TypeLayoutInfo<'static>>], + init_tys_len: usize, +) -> usize { + let layout = &T::TYPE_LAYOUT; + + // check if this type has already been inserted into the graph + let mut i = 0; + while i < init_tys_len { + // Safety: tys has been initialized for 0..tys_len + if type_layout_info_eq(unsafe { tys[i].assume_init_ref() }, layout) { + // if no types remain, return the initialized length of the array + if Remaining::LEN == 0 { + return init_tys_len; + } + + // if more types remain, continue with recursion + return fill_type_layout_graph_slice::( + tys, + init_tys_len, + ); + } + i += 1; + } + + // push the type layout into the slice to initialize the next element + assert!(init_tys_len < tys.len(), "bug: type layout graph too small"); + tys[init_tys_len] = MaybeUninit::new(layout); + + if <::Concat as private::HList>::LEN == 0 { + // if no types remain, also considering the links from T, return the + // initialized length of the array + return init_tys_len + 1; + } + + // if more types remain, continue with recursion, adding the links from T + // to the stack of remaining types + fill_type_layout_graph_slice::< + <::Concat as private::TypeHList>::Head, + <::Concat as private::TypeHList>::Tail, + >(tys, init_tys_len + 1) +} + +// simple type layout info equality by checking the equality of their type names +const fn type_layout_info_eq(a: &TypeLayoutInfo, b: &TypeLayoutInfo) -> bool { + str_eq(a.name, b.name) +} + +const fn str_eq(a: &str, b: &str) -> bool { + if a.len() != b.len() { + return false; + } + + let (a, b) = (a.as_bytes(), b.as_bytes()); + + let mut i = 0; + + while i < a.len() { + if a[i] != b[i] { + return false; + } + + i += 1; + } + + true +} + +mod private { + use crate::TypeLayout; + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Empty; + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Cons { + head: H, + tail: T, + } + + pub trait HList { + const LEN: usize; + } + + impl HList for Empty { + const LEN: usize = 0; + } + + impl HList for Cons { + const LEN: usize = 1 + T::LEN; + } + + pub trait TypeHList: HList { + type Head: TypeLayout; + type Tail: TypeHList; + + type Concat: TypeHList; + } + + impl TypeHList for Empty { + type Concat = L; + // Empty's head can be anything since we never use it + type Head = (); + type Tail = Self; + } + + impl TypeHList for Cons { + type Concat = Cons>; + type Head = H; + type Tail = T; + } +} diff --git a/src/impls/core/array.rs b/src/impls/core/array.rs index f29092d..b2200b1 100644 --- a/src/impls/core/array.rs +++ b/src/impls/core/array.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for [T; N] { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -12,7 +11,3 @@ unsafe impl TypeLayout for [T; N] { structure: TypeStructure::Primitive, }; } - -unsafe impl ComputeTypeSet for [T; N] { - type Output = tset![T, .. @ R]; -} diff --git a/src/impls/core/cell.rs b/src/impls/core/cell.rs index aed83df..0f2c3d7 100644 --- a/src/impls/core/cell.rs +++ b/src/impls/core/cell.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for core::cell::UnsafeCell { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -20,11 +19,9 @@ unsafe impl TypeLayout for core::cell::UnsafeCell { }; } -unsafe impl ComputeTypeSet for core::cell::UnsafeCell { - type Output = tset![T, .. @ R]; -} - unsafe impl TypeLayout for core::cell::Cell { + type TypeGraphEdges = hlist![core::cell::UnsafeCell]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -41,12 +38,10 @@ unsafe impl TypeLayout for core::cell::Cell { }; } -unsafe impl ComputeTypeSet for core::cell::Cell { - type Output = tset![core::cell::UnsafeCell, .. @ R]; -} - #[cfg(feature = "impl-sync-unsafe-cell")] unsafe impl TypeLayout for core::cell::SyncUnsafeCell { + type TypeGraphEdges = hlist![core::cell::UnsafeCell]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -63,12 +58,9 @@ unsafe impl TypeLayout for core::cell::SyncUnsafeCell { }; } -#[cfg(feature = "impl-sync-unsafe-cell")] -unsafe impl ComputeTypeSet for core::cell::SyncUnsafeCell { - type Output = tset![core::cell::UnsafeCell, .. @ R]; -} - unsafe impl TypeLayout for core::cell::OnceCell { + type TypeGraphEdges = hlist![core::cell::UnsafeCell>]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -84,7 +76,3 @@ unsafe impl TypeLayout for core::cell::OnceCell { }, }; } - -unsafe impl ComputeTypeSet for core::cell::OnceCell { - type Output = tset![core::cell::UnsafeCell>, .. @ R]; -} diff --git a/src/impls/core/cmp.rs b/src/impls/core/cmp.rs index dd35acf..1f1477c 100644 --- a/src/impls/core/cmp.rs +++ b/src/impls/core/cmp.rs @@ -1,9 +1,10 @@ use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, + graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, }; unsafe impl TypeLayout for core::cmp::Reverse { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -20,11 +21,9 @@ unsafe impl TypeLayout for core::cmp::Reverse { }; } -unsafe impl ComputeTypeSet for core::cmp::Reverse { - type Output = tset![T, .. @ R]; -} - unsafe impl TypeLayout for core::cmp::Ordering { + type TypeGraphEdges = hlist![::core::mem::Discriminant]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -52,9 +51,3 @@ unsafe impl TypeLayout for core::cmp::Ordering { }, }; } - -unsafe impl ComputeTypeSet for core::cmp::Ordering { - type Output = tset![ - ::core::mem::Discriminant, .. @ R - ]; -} diff --git a/src/impls/core/convert.rs b/src/impls/core/convert.rs index 1897d92..86f3ec5 100644 --- a/src/impls/core/convert.rs +++ b/src/impls/core/convert.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for core::convert::Infallible { + type TypeGraphEdges = hlist![]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::any![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -15,7 +14,3 @@ unsafe impl TypeLayout for core::convert::Infallible { }, }; } - -unsafe impl ComputeTypeSet for core::convert::Infallible { - type Output = tset![.. @ T]; -} diff --git a/src/impls/core/ffi.rs b/src/impls/core/ffi.rs index 1c09ddf..d4b26aa 100644 --- a/src/impls/core/ffi.rs +++ b/src/impls/core/ffi.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for core::ffi::c_void { + type TypeGraphEdges = hlist![]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -15,7 +14,3 @@ unsafe impl TypeLayout for core::ffi::c_void { }, }; } - -unsafe impl ComputeTypeSet for core::ffi::c_void { - type Output = tset![.. @ T]; -} diff --git a/src/impls/core/fn.rs b/src/impls/core/fn.rs index cf5890a..6d13822 100644 --- a/src/impls/core/fn.rs +++ b/src/impls/core/fn.rs @@ -1,7 +1,4 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, TypeLayout, TypeLayoutInfo, TypeStructure}; macro_rules! impl_fn_pointer_type_layout { (impl extern $abi:literal fn($($T:ident),*) -> $R:ident) => { @@ -28,10 +25,8 @@ macro_rules! impl_fn_pointer_type_layout { alignment: ::core::mem::align_of::(), structure: TypeStructure::Primitive, }; - } - unsafe impl<$R: ComputeTypeSet, $($T: ComputeTypeSet),*> ComputeTypeSet for $ty { - type Output = tset![$R $(, $T)*, .. @ Z]; + type TypeGraphEdges = hlist![$R $(, $T)*]; } }; ($(fn($($T:ident),*) -> $R:ident),*) => { @@ -71,12 +66,8 @@ macro_rules! impl_variadic_extern_fn_pointer_type_layout { alignment: ::core::mem::align_of::(), structure: TypeStructure::Primitive, }; - } - unsafe impl<$R: ComputeTypeSet, $($T: ComputeTypeSet),*> ComputeTypeSet - for unsafe extern $abi fn($($T),*, ...) -> $R - { - type Output = tset![$R $(, $T)*, .. @ Z]; + type TypeGraphEdges = hlist![$R $(, $T)*]; } }; ($(unsafe extern "C" fn($($T:ident),+, ...) -> $R:ident),*) => { diff --git a/src/impls/core/marker.rs b/src/impls/core/marker.rs index 05b1bd9..fcc8d3b 100644 --- a/src/impls/core/marker.rs +++ b/src/impls/core/marker.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for core::marker::PhantomData { + type TypeGraphEdges = hlist![]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -16,11 +15,9 @@ unsafe impl TypeLayout for core::marker::PhantomData { }; } -unsafe impl ComputeTypeSet for core::marker::PhantomData { - type Output = tset![.. @ R]; -} - unsafe impl TypeLayout for core::marker::PhantomPinned { + type TypeGraphEdges = hlist![]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -32,7 +29,3 @@ unsafe impl TypeLayout for core::marker::PhantomPinned { }, }; } - -unsafe impl ComputeTypeSet for core::marker::PhantomPinned { - type Output = tset![.. @ T]; -} diff --git a/src/impls/core/mem.rs b/src/impls/core/mem.rs index d57104a..c528730 100644 --- a/src/impls/core/mem.rs +++ b/src/impls/core/mem.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for core::mem::ManuallyDrop { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -20,11 +19,9 @@ unsafe impl TypeLayout for core::mem::ManuallyDrop { }; } -unsafe impl ComputeTypeSet for core::mem::ManuallyDrop { - type Output = tset![T, .. @ R]; -} - unsafe impl TypeLayout for core::mem::MaybeUninit { + type TypeGraphEdges = hlist![(), core::mem::ManuallyDrop]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -48,11 +45,9 @@ unsafe impl TypeLayout for core::mem::MaybeUninit { }; } -unsafe impl ComputeTypeSet for core::mem::MaybeUninit { - type Output = tset![(), core::mem::ManuallyDrop, .. @ R]; -} - unsafe impl TypeLayout for core::mem::Discriminant { + type TypeGraphEdges = hlist![]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -61,7 +56,3 @@ unsafe impl TypeLayout for core::mem::Discriminant { structure: TypeStructure::Primitive, }; } - -unsafe impl ComputeTypeSet for core::mem::Discriminant { - type Output = tset![.. @ R]; -} diff --git a/src/impls/core/num.rs b/src/impls/core/num.rs index b6ca5d1..257073b 100644 --- a/src/impls/core/num.rs +++ b/src/impls/core/num.rs @@ -1,7 +1,4 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; macro_rules! impl_nonzero_type_layout { (impl $nz:ident => $ty:ty) => { @@ -23,10 +20,8 @@ macro_rules! impl_nonzero_type_layout { ], }, }; - } - unsafe impl ComputeTypeSet for core::num::$nz { - type Output = tset![$ty, .. @ T]; + type TypeGraphEdges = hlist![$ty]; } }; ($($nz:ident => $ty:ty),*) => { @@ -42,6 +37,8 @@ impl_nonzero_type_layout! { } unsafe impl TypeLayout for core::num::Wrapping { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -58,11 +55,9 @@ unsafe impl TypeLayout for core::num::Wrapping { }; } -unsafe impl ComputeTypeSet for core::num::Wrapping { - type Output = tset![T, .. @ R]; -} - unsafe impl TypeLayout for core::num::Saturating { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -78,7 +73,3 @@ unsafe impl TypeLayout for core::num::Saturating { }, }; } - -unsafe impl ComputeTypeSet for core::num::Saturating { - type Output = tset![T, .. @ R]; -} diff --git a/src/impls/core/ops.rs b/src/impls/core/ops.rs index 5038ec8..184712d 100644 --- a/src/impls/core/ops.rs +++ b/src/impls/core/ops.rs @@ -1,9 +1,10 @@ use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, + graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, }; unsafe impl TypeLayout for core::ops::Range { + type TypeGraphEdges = hlist![Idx]; + const INHABITED: crate::MaybeUninhabited = Idx::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -27,11 +28,9 @@ unsafe impl TypeLayout for core::ops::Range { }; } -unsafe impl ComputeTypeSet for core::ops::Range { - type Output = tset![Idx, .. @ R]; -} - unsafe impl TypeLayout for core::ops::RangeFrom { + type TypeGraphEdges = hlist![Idx]; + const INHABITED: crate::MaybeUninhabited = Idx::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -48,11 +47,9 @@ unsafe impl TypeLayout for core::ops::RangeFrom { }; } -unsafe impl ComputeTypeSet for core::ops::RangeFrom { - type Output = tset![Idx, .. @ R]; -} - unsafe impl TypeLayout for core::ops::RangeFull { + type TypeGraphEdges = hlist![]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -65,11 +62,9 @@ unsafe impl TypeLayout for core::ops::RangeFull { }; } -unsafe impl ComputeTypeSet for core::ops::RangeFull { - type Output = tset![.. @ R]; -} - unsafe impl TypeLayout for core::ops::RangeTo { + type TypeGraphEdges = hlist![Idx]; + const INHABITED: crate::MaybeUninhabited = Idx::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -86,11 +81,9 @@ unsafe impl TypeLayout for core::ops::RangeTo { }; } -unsafe impl ComputeTypeSet for core::ops::RangeTo { - type Output = tset![Idx, .. @ R]; -} - unsafe impl TypeLayout for core::ops::RangeToInclusive { + type TypeGraphEdges = hlist![Idx]; + const INHABITED: crate::MaybeUninhabited = Idx::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -107,11 +100,9 @@ unsafe impl TypeLayout for core::ops::RangeToInclusive { }; } -unsafe impl ComputeTypeSet for core::ops::RangeToInclusive { - type Output = tset![Idx, .. @ R]; -} - unsafe impl TypeLayout for core::ops::Bound { + type TypeGraphEdges = hlist![T, ::core::mem::Discriminant]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -152,13 +143,9 @@ unsafe impl TypeLayout for core::ops::Bound { }; } -unsafe impl ComputeTypeSet for core::ops::Bound { - type Output = tset![ - T, ::core::mem::Discriminant, .. @ R - ]; -} - unsafe impl TypeLayout for core::ops::ControlFlow { + type TypeGraphEdges = hlist![B, C, ::core::mem::Discriminant]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::any![B, C]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -191,9 +178,3 @@ unsafe impl TypeLayout for core::ops::ControlFlow< }, }; } - -unsafe impl ComputeTypeSet for core::ops::ControlFlow { - type Output = tset![ - B, C, ::core::mem::Discriminant, .. @ R - ]; -} diff --git a/src/impls/core/option.rs b/src/impls/core/option.rs index bb47a2e..6966dc6 100644 --- a/src/impls/core/option.rs +++ b/src/impls/core/option.rs @@ -1,9 +1,10 @@ use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, + graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, }; unsafe impl TypeLayout for core::option::Option { + type TypeGraphEdges = hlist![T, ::core::mem::Discriminant]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -30,9 +31,3 @@ unsafe impl TypeLayout for core::option::Option { }, }; } - -unsafe impl ComputeTypeSet for core::option::Option { - type Output = tset![ - T, ::core::mem::Discriminant, .. @ R - ]; -} diff --git a/src/impls/core/pin.rs b/src/impls/core/pin.rs index 6d9ea6c..48a5c0d 100644 --- a/src/impls/core/pin.rs +++ b/src/impls/core/pin.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for core::pin::Pin { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -19,7 +18,3 @@ unsafe impl TypeLayout for core::pin::Pin { }, }; } - -unsafe impl ComputeTypeSet for core::pin::Pin { - type Output = tset![T, .. @ R]; -} diff --git a/src/impls/core/primitive.rs b/src/impls/core/primitive.rs index 528acd0..53b7241 100644 --- a/src/impls/core/primitive.rs +++ b/src/impls/core/primitive.rs @@ -1,7 +1,4 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, TypeLayout, TypeLayoutInfo, TypeStructure}; macro_rules! impl_primitive_type_layout { (impl $ty:ty => $val:expr) => { @@ -14,10 +11,8 @@ macro_rules! impl_primitive_type_layout { alignment: ::core::mem::align_of::(), structure: TypeStructure::Primitive, }; - } - unsafe impl ComputeTypeSet for $ty { - type Output = tset![.. @ T]; + type TypeGraphEdges = hlist![]; } }; ($($ty:ty => $val:expr),*) => { @@ -34,6 +29,8 @@ impl_primitive_type_layout! { #[cfg(feature = "impl-never")] unsafe impl TypeLayout for ! { + type TypeGraphEdges = hlist![]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::any![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -42,8 +39,3 @@ unsafe impl TypeLayout for ! { structure: TypeStructure::Primitive, }; } - -#[cfg(feature = "impl-never")] -unsafe impl ComputeTypeSet for ! { - type Output = tset![.. @ T]; -} diff --git a/src/impls/core/ptr.rs b/src/impls/core/ptr.rs index 1bf5a79..f111cf4 100644 --- a/src/impls/core/ptr.rs +++ b/src/impls/core/ptr.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl TypeLayout for *const T { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -13,11 +12,9 @@ unsafe impl TypeLayout for *const T { }; } -unsafe impl ComputeTypeSet for *const T { - type Output = tset![T, .. @ R]; -} - unsafe impl TypeLayout for *mut T { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -27,11 +24,9 @@ unsafe impl TypeLayout for *mut T { }; } -unsafe impl ComputeTypeSet for *mut T { - type Output = tset![T, .. @ R]; -} - unsafe impl TypeLayout for core::ptr::NonNull { + type TypeGraphEdges = hlist![*const T]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -47,7 +42,3 @@ unsafe impl TypeLayout for core::ptr::NonNull { }, }; } - -unsafe impl ComputeTypeSet for core::ptr::NonNull { - type Output = tset![*const T, .. @ R]; -} diff --git a/src/impls/core/ref.rs b/src/impls/core/ref.rs index 8087752..497a29f 100644 --- a/src/impls/core/ref.rs +++ b/src/impls/core/ref.rs @@ -1,9 +1,8 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, TypeLayout, TypeLayoutInfo, TypeStructure}; unsafe impl<'a, T: TypeLayout + 'a> TypeLayout for &'a T { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -13,11 +12,9 @@ unsafe impl<'a, T: TypeLayout + 'a> TypeLayout for &'a T { }; } -unsafe impl<'a, T: ComputeTypeSet + 'a> ComputeTypeSet for &'a T { - type Output = tset![T, .. @ R]; -} - unsafe impl<'a, T: TypeLayout + 'a> TypeLayout for &'a mut T { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::all![]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -26,7 +23,3 @@ unsafe impl<'a, T: TypeLayout + 'a> TypeLayout for &'a mut T { structure: TypeStructure::Primitive, }; } - -unsafe impl<'a, T: ComputeTypeSet + 'a> ComputeTypeSet for &'a mut T { - type Output = tset![T, .. @ R]; -} diff --git a/src/impls/core/result.rs b/src/impls/core/result.rs index 3df460a..fb07d2e 100644 --- a/src/impls/core/result.rs +++ b/src/impls/core/result.rs @@ -1,9 +1,10 @@ use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, + graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, Variant, }; unsafe impl TypeLayout for core::result::Result { + type TypeGraphEdges = hlist![T, E, ::core::mem::Discriminant]; + const INHABITED: crate::MaybeUninhabited = crate::inhabited::any![T, E]; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -34,9 +35,3 @@ unsafe impl TypeLayout for core::result::Result ComputeTypeSet for core::result::Result { - type Output = tset![ - T, E, ::core::mem::Discriminant, .. @ R - ]; -} diff --git a/src/impls/core/sync/atomic.rs b/src/impls/core/sync/atomic.rs index 037bd88..95cd46d 100644 --- a/src/impls/core/sync/atomic.rs +++ b/src/impls/core/sync/atomic.rs @@ -1,7 +1,4 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; macro_rules! impl_atomic_int_layout { (impl $at:ident ( $align:literal : $cfg:literal ) => $ty:ty => $val:literal) => { @@ -24,11 +21,8 @@ macro_rules! impl_atomic_int_layout { ], }, }; - } - #[cfg(target_has_atomic_load_store = $cfg)] - unsafe impl ComputeTypeSet for core::sync::atomic::$at { - type Output = tset![core::cell::UnsafeCell<$ty>, .. @ T]; + type TypeGraphEdges = hlist![core::cell::UnsafeCell<$ty>]; } }; ($($at:ident ( $align:literal : $cfg:literal ) => $ty:ty => $val:literal),*) => { @@ -71,12 +65,8 @@ macro_rules! impl_atomic_int_ptr_sized_layout { ], }, }; - } - #[cfg(target_has_atomic_load_store = "ptr")] - #[cfg(target_pointer_width = $cfg)] - unsafe impl ComputeTypeSet for core::sync::atomic::$at { - type Output = tset![core::cell::UnsafeCell<$ty>, .. @ T]; + type TypeGraphEdges = hlist![core::cell::UnsafeCell<$ty>]; } }; ($($at:ident ( $align:literal : $cfg:literal ) => $ty:ty => $val:literal),*) => { @@ -113,12 +103,8 @@ macro_rules! impl_atomic_ptr_layout { ], }, }; - } - #[cfg(target_has_atomic_load_store = "ptr")] - #[cfg(target_pointer_width = $cfg)] - unsafe impl ComputeTypeSet for core::sync::atomic::AtomicPtr { - type Output = tset![core::cell::UnsafeCell, .. @ R]; + type TypeGraphEdges = hlist![core::cell::UnsafeCell]; } }; ($(( $align:literal : $cfg:literal )),*) => { diff --git a/src/impls/core/sync/mod.rs b/src/impls/core/sync/mod.rs index 1d1748f..b075d44 100644 --- a/src/impls/core/sync/mod.rs +++ b/src/impls/core/sync/mod.rs @@ -1,14 +1,13 @@ #[cfg(feature = "impl-sync-exclusive")] -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; #[cfg(feature = "impl-atomics")] mod atomic; #[cfg(feature = "impl-sync-exclusive")] unsafe impl TypeLayout for core::sync::Exclusive { + type TypeGraphEdges = hlist![T]; + const INHABITED: crate::MaybeUninhabited = T::INHABITED; const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { name: ::core::any::type_name::(), @@ -24,8 +23,3 @@ unsafe impl TypeLayout for core::sync::Exclusive { }, }; } - -#[cfg(feature = "impl-sync-exclusive")] -unsafe impl ComputeTypeSet for core::sync::Exclusive { - type Output = tset![T, .. @ R]; -} diff --git a/src/impls/core/tuple.rs b/src/impls/core/tuple.rs index 778280e..48e26df 100644 --- a/src/impls/core/tuple.rs +++ b/src/impls/core/tuple.rs @@ -1,7 +1,4 @@ -use crate::{ - typeset::{tset, ComputeTypeSet, ExpandTypeSet}, - Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -}; +use crate::{graph::hlist, Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure}; macro_rules! impl_tuple_type_layout { (impl ($($a:tt => $T:ident),+)) => { @@ -22,10 +19,8 @@ macro_rules! impl_tuple_type_layout { }),*], }, }; - } - unsafe impl<$($T: ComputeTypeSet),*> ComputeTypeSet for ($($T,)*) { - type Output = tset![$($T),*, .. @ T]; + type TypeGraphEdges = hlist![$($T),*]; } }; ($(($($a:tt => $T:ident),+)),*) => { diff --git a/src/lib.rs b/src/lib.rs index 3cdd206..7ecf5e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,6 +130,8 @@ r#"TypeLayoutInfo { #![feature(offset_of_enum)] // required, soon-stabilized features #![cfg_attr(not(version("1.83")), feature(const_mut_refs))] +#![cfg_attr(not(version("1.83")), feature(const_slice_from_raw_parts_mut))] +#![cfg_attr(not(version("1.79")), feature(inline_const))] #![cfg_attr(not(version("1.82")), feature(offset_of_nested))] // docs-specific features #![cfg_attr(doc, feature(doc_auto_cfg))] @@ -143,12 +145,10 @@ r#"TypeLayoutInfo { #![cfg_attr(feature = "impl-never", feature(never_type))] #![cfg_attr(feature = "impl-sync-exclusive", feature(exclusive_wrapper))] #![cfg_attr(feature = "impl-sync-unsafe-cell", feature(sync_unsafe_cell))] -// required INCOMPLETE features -#![allow(incomplete_features)] -#![feature(specialization)] // optional feature-gated INCOMPLETE features #![cfg_attr( feature = "serialize-to-generic-const-array", + allow(incomplete_features), feature(generic_const_exprs) )] // further crate attributes @@ -167,10 +167,10 @@ use core::ops::Deref; pub use const_type_layout_derive::TypeLayout; mod discriminant; +pub mod graph; mod impls; pub mod inhabited; mod ser; -pub mod typeset; pub use discriminant::Discriminant; @@ -262,8 +262,7 @@ impl Default for MaybeUninhabited { /// # use const_type_layout::{ /// # Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, /// # }; -/// # use const_type_layout::inhabited; -/// # use const_type_layout::typeset::{ComputeTypeSet, ExpandTypeSet, tset}; +/// # use const_type_layout::{graph, inhabited}; /// struct Foo { /// a: u8, /// b: u16, @@ -292,11 +291,10 @@ impl Default for MaybeUninhabited { /// ], /// }, /// }; +/// +/// type TypeGraphEdges = graph::hlist![u8, u16]; /// } /// ``` -/// -/// Note that if you implement [`TypeLayout`], you should also implement -/// [`typeset::ComputeTypeSet`] for it. pub unsafe trait TypeLayout: Sized { /// Marker for whether the type is /// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited) or @@ -305,15 +303,18 @@ pub unsafe trait TypeLayout: Sized { /// Shallow layout of the type. const TYPE_LAYOUT: TypeLayoutInfo<'static>; + + #[allow(missing_docs)] // FIXME + type TypeGraphEdges: graph::TypeHList; } /// Utility trait that provides the deep layout of a type. -pub trait TypeGraphLayout: TypeLayout + typeset::ComputeTypeSet { +pub trait TypeGraphLayout: TypeLayout { /// Shallow layout of the type. const TYPE_GRAPH: TypeLayoutGraph<'static>; } -impl TypeGraphLayout for T { +impl TypeGraphLayout for T { const TYPE_GRAPH: TypeLayoutGraph<'static> = TypeLayoutGraph::new::(); } @@ -464,23 +465,10 @@ pub struct Field<'a> { impl TypeLayoutGraph<'static> { #[must_use] /// Construct the deep type layout descriptor for a type `T`. - pub const fn new() -> Self { + pub const fn new() -> Self { Self { ty: ::TYPE_LAYOUT.name, - // SAFETY: - // - ComputeSet is a sealed trait and its TYS const is always a HList made of only Cons - // of &'static TypeLayoutInfo and Empty - // - Cons is a repr(C) struct with a head followed by a tail, Empty is a zero-sized - // repr(C) struct - // - the HList is layout-equivalent to an array of the same length as ComputeSet::LEN - // - ComputeSet::TYS provides a static non-dangling reference that we can use to produce - // the data pointer for a slice - tys: unsafe { - core::slice::from_raw_parts( - core::ptr::from_ref( as typeset::ComputeSet>::TYS).cast(), - as typeset::ComputeSet>::LEN, - ) - }, + tys: graph::type_layout_graph::(), } } } diff --git a/src/typeset.rs b/src/typeset.rs deleted file mode 100644 index 9d8ac60..0000000 --- a/src/typeset.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! Helper module to compute the set of types that a type links to and expand it -//! into the complete type graph. - -#[doc(hidden)] -pub trait ComputeSet: sealed::ComputeSet { - const LEN: usize; - type Len; - - type Output: ExpandTypeSet; - - type TyHList: 'static + Copy + core::marker::Freeze; - const TYS: &'static Self::TyHList; -} - -mod sealed { - pub trait ComputeSet {} - - impl ComputeSet for super::private::Empty {} - impl ComputeSet for super::private::Cons {} -} - -type Set = ::Output; - -/// Computes the set of types that a type links to. -/// -/// # Safety -/// -/// It is only safe to implement this trait if it accurately includes -/// all inner component types that are referenced by this type's layout. Use -/// [`#[derive(TypeLayout)]`](const_type_layout_derive::TypeLayout) instead. -/// -/// # Example -/// -/// The struct `Foo` with `u8` and `u16` fields links to `u8` and `u16`: -/// -/// ```rust -/// # #![feature(const_type_name)] -/// # #![feature(offset_of)] -/// # use const_type_layout::{ -/// # Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure, -/// # }; -/// # use const_type_layout::inhabited; -/// # use const_type_layout::typeset::{ComputeTypeSet, ExpandTypeSet, tset}; -/// struct Foo { -/// a: u8, -/// b: u16, -/// } -/// -/// # unsafe impl TypeLayout for Foo { -/// # const INHABITED: MaybeUninhabited = inhabited::all![u8, u16]; -/// # -/// # const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo { -/// # name: ::core::any::type_name::(), -/// # size: ::core::mem::size_of::(), -/// # alignment: ::core::mem::align_of::(), -/// # structure: TypeStructure::Struct { -/// # repr: "", -/// # fields: &[ -/// # Field { -/// # name: "a", -/// # offset: MaybeUninhabited::new::(::core::mem::offset_of!(Self, a)), -/// # ty: ::core::any::type_name::(), -/// # }, -/// # Field { -/// # name: "b", -/// # offset: MaybeUninhabited::new::(::core::mem::offset_of!(Self, b)), -/// # ty: ::core::any::type_name::(), -/// # }, -/// # ], -/// # }, -/// # }; -/// # } -/// -/// unsafe impl ComputeTypeSet for Foo { -/// type Output = tset![u8, u16]; -/// } -/// ``` -/// -/// Note that to you implement [`ComputeTypeSet`] you must also implement -/// [`crate::TypeLayout`] for it. -pub unsafe trait ComputeTypeSet: crate::TypeLayout { - /// Extend the set `T` into a (larger) set containing also the types this - /// type links to. - /// - /// Enums implementing [`crate::TypeLayout`] and [`ComputeTypeSet`] - /// manually should include [`core::mem::Discriminant`] in - /// their [`ComputeTypeSet::Output`] using the [`tset`] helper macro. - type Output: ExpandTypeSet; -} - -/// Helper macro to expand a list of types, e.g. `H, R1, R2`, and an optional -/// tail, `.. @ T`, into a set of types. -/// -/// This macro is used when implementing the [`ComputeTypeSet::Output`] -/// associated type to specify the list of types a type links to. -pub macro tset { - () => { private::Empty }, - (.. @ $T:tt) => { $T }, - ($H:ty $(, $R:ty)*) => { - Set<$H, tset![$($R),*]> - }, - ($H:ty, $($R:ty,)* .. @ $T:ty ) => { - Set<$H, tset![$($R,)* .. @ $T]> - }, -} - -#[doc(hidden)] -pub trait ExpandTypeSet: ComputeSet { - type Output: ExpandTypeSet; -} - -impl ExpandTypeSet for private::Empty { - type Output = T; -} - -impl ExpandTypeSet for private::Cons { - type Output = - ::Output::Output>>; -} - -#[doc(hidden)] -pub trait TypeSetFixedPoint: ExpandTypeSet { - type Output: ExpandTypeSet; -} - -impl TypeSetFixedPoint for T { - type Output = ::Output, - >>::Output; -} - -mod private { - use super::{sealed, ComputeSet, ComputeTypeSet, ExpandTypeSet, Set}; - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Empty; - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Cons { - head: H, - tail: T, - } - - impl ComputeSet for Empty { - type Len = Self; - type Output = Cons; - type TyHList = Self; - - const LEN: usize = 0; - const TYS: &'static Self::TyHList = &Self; - } - - impl ComputeSet for Cons { - type Len = Cons<(), T::Len>; - type Output = >::Output; - type TyHList = Cons<&'static crate::TypeLayoutInfo<'static>, T::TyHList>; - - const LEN: usize = T::LEN + 1; - const TYS: &'static Self::TyHList = &Cons { - head: &H2::TYPE_LAYOUT, - tail: *T::TYS, - }; - } - - pub trait ComputeCons: sealed::ComputeSet { - type Output: ExpandTypeSet; - } - - impl ComputeCons for Empty { - type Output = Cons; - } - - impl ComputeCons for Cons { - type Output = Self; - } - - impl ComputeCons

for Cons { - default type Output = Cons>; - } - - pub trait ComputeTypeSetFixedPoint: ExpandTypeSet { - type Output: ExpandTypeSet; - } - - trait Same {} - impl Same for T {} - - impl ComputeTypeSetFixedPoint for T - where - T::Len: Same, - { - type Output = Self; - } - - impl ComputeTypeSetFixedPoint for T { - default type Output = ::Output>>::Output; - } -} - -pub(super) type TypeSet = - ::Output> as TypeSetFixedPoint>::Output;