const_type_layout/
lib.rs

1//! [![CI Status]][workflow] [![MSRV]][repo] [![Latest Version]][crates.io]
2//! [![Rust Doc Crate]][docs.rs] [![Rust Doc Main]][docs]
3//! [![License Status]][fossa] [![Code Coverage]][codecov]
4//! [![Gitpod Ready-to-Code]][gitpod]
5//!
6//! [CI Status]: https://img.shields.io/github/actions/workflow/status/juntyr/const-type-layout/ci.yml?branch=main
7//! [workflow]: https://github.com/juntyr/const-type-layout/actions/workflows/ci.yml?query=branch%3Amain
8//!
9//! [MSRV]: https://img.shields.io/badge/MSRV-1.78.0--nightly-orange
10//! [repo]: https://github.com/juntyr/const-type-layout
11//!
12//! [Latest Version]: https://img.shields.io/crates/v/const-type-layout
13//! [crates.io]: https://crates.io/crates/const-type-layout
14//!
15//! [Rust Doc Crate]: https://img.shields.io/docsrs/const-type-layout
16//! [docs.rs]: https://docs.rs/const-type-layout/
17//!
18//! [Rust Doc Main]: https://img.shields.io/badge/docs-main-blue
19//! [docs]: https://juntyr.github.io/const-type-layout/const_type_layout
20//!
21//! [License Status]: https://app.fossa.com/api/projects/custom%2B26490%2Fgithub.com%2Fjuntyr%2Fconst-type-layout.svg?type=shield
22//! [fossa]: https://app.fossa.com/projects/custom%2B26490%2Fgithub.com%2Fjuntyr%2Fconst-type-layout?ref=badge_shield
23//!
24//! [Code Coverage]: https://img.shields.io/codecov/c/github/juntyr/const-type-layout?token=J39WVBIMZX
25//! [codecov]: https://codecov.io/gh/juntyr/const-type-layout
26//!
27//! [Gitpod Ready-to-Code]: https://img.shields.io/badge/Gitpod-ready-blue?logo=gitpod
28//! [gitpod]: https://gitpod.io/#https://github.com/juntyr/const-type-layout
29//!
30//! `const-type-layout` is a type layout comparison aid, providing a
31//! [`#[derive]`](const_type_layout_derive::TypeLayout)able [`TypeLayout`] trait
32//! that provides a const [`TypeLayoutInfo`] struct containing:
33//! - The type's name, size, and minimum alignment
34//! - The type's structure, i.e. struct vs. union vs. enum
35//! - Each field's name and offset
36//! - Each variant's name and discriminant
37//! - Whether each variant / field is inhabited or uninhabited
38//!
39//! The auto-implemented [`TypeGraphLayout`] trait also provides a const
40//! [`TypeLayoutGraph`] struct that describes the deep type layout, including
41//! the layouts of all the types mentioned by this type, e.g. in its fields.
42//!
43//! This crate heavily builds on the original runtime [type-layout](https://github.com/LPGhatguy/type-layout) crate by Lucien Greathouse.
44#![cfg_attr(
45    feature = "derive",
46    doc = r##"
47## Examples
48
49The layout of types is only defined if they're `#[repr(C)]`. This crate works
50on non-`#[repr(C)]` types, but their layout is unpredictable.
51
52```rust
53# #![feature(const_type_name)]
54# #![feature(offset_of)]
55# #![feature(offset_of_enum)]
56use const_type_layout::TypeLayout;
57
58#[derive(TypeLayout)]
59#[repr(C)]
60struct Foo {
61    a: u8,
62    b: u32,
63}
64
65assert_eq!(
66    format!("{:#?}", Foo::TYPE_LAYOUT),
67r#"TypeLayoutInfo {
68    name: "rust_out::main::_doctest_main_src_lib_rs_49_0::Foo",
69    size: 8,
70    alignment: 4,
71    structure: Struct {
72        repr: "C",
73        fields: [
74            Field {
75                name: "a",
76                offset: Inhabited(
77                    0,
78                ),
79                ty: "u8",
80            },
81            Field {
82                name: "b",
83                offset: Inhabited(
84                    4,
85                ),
86                ty: "u32",
87            },
88        ],
89    },
90}"#
91)
92```
93
94Over-aligned types have trailing padding, which can be a source of bugs in some
95FFI scenarios:
96
97```rust
98# #![feature(const_type_name)]
99# #![feature(offset_of)]
100# #![feature(offset_of_enum)]
101use const_type_layout::TypeLayout;
102
103#[derive(TypeLayout)]
104#[repr(C, align(128))]
105struct OverAligned {
106    value: u8,
107}
108
109assert_eq!(
110    format!("{:#?}", OverAligned::TYPE_LAYOUT),
111r#"TypeLayoutInfo {
112    name: "rust_out::main::_doctest_main_src_lib_rs_94_0::OverAligned",
113    size: 128,
114    alignment: 128,
115    structure: Struct {
116        repr: "C,align(128)",
117        fields: [
118            Field {
119                name: "value",
120                offset: Inhabited(
121                    0,
122                ),
123                ty: "u8",
124            },
125        ],
126    },
127}"#
128)
129```
130"##
131)]
132#![deny(clippy::complexity)]
133#![deny(clippy::correctness)]
134#![warn(clippy::nursery)]
135#![warn(clippy::pedantic)]
136#![deny(clippy::perf)]
137#![deny(clippy::style)]
138#![deny(clippy::suspicious)]
139#![deny(clippy::default_union_representation)]
140#![deny(clippy::multiple_unsafe_ops_per_block)]
141#![deny(clippy::undocumented_unsafe_blocks)]
142#![deny(unused_unsafe)]
143#![deny(missing_docs)]
144#![no_std]
145#![feature(const_type_name)]
146#![cfg_attr(not(version("1.83")), feature(const_mut_refs))]
147#![feature(cfg_target_has_atomic)]
148#![feature(decl_macro)]
149#![feature(never_type)]
150#![feature(c_variadic)]
151#![feature(discriminant_kind)]
152#![feature(offset_of_enum)]
153#![feature(sync_unsafe_cell)]
154#![feature(exclusive_wrapper)]
155#![feature(doc_auto_cfg)]
156#![feature(cfg_version)]
157#![cfg_attr(not(version("1.82")), feature(offset_of_nested))]
158#![feature(freeze)]
159#![allow(incomplete_features)]
160#![feature(generic_const_exprs)]
161#![feature(specialization)]
162#![cfg_attr(
163    all(doc, not(docsrs)),
164    doc(html_root_url = "https://juntyr.github.io/const-type-layout")
165)]
166#![cfg_attr(feature = "serde", allow(clippy::type_repetition_in_bounds))]
167
168extern crate alloc;
169
170use alloc::fmt;
171use core::ops::Deref;
172
173#[cfg(feature = "derive")]
174pub use const_type_layout_derive::TypeLayout;
175
176mod impls;
177pub mod inhabited;
178mod ser;
179pub mod typeset;
180
181#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
182#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
183#[cfg_attr(feature = "serde", derive(::serde::Deserialize))]
184/// Optional value that exists if some other type is
185/// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited).
186pub enum MaybeUninhabited<T> {
187    /// The type is [uninhabited](https://doc.rust-lang.org/reference/glossary.html#uninhabited),
188    /// no value.
189    Uninhabited,
190    /// The type is [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited),
191    /// some value of type `T`.
192    Inhabited(T),
193}
194
195impl<T: Copy> MaybeUninhabited<T> {
196    #[must_use]
197    /// Construct [`MaybeUninhabited::Inhabited`] iff [`<U as
198    /// TypeLayout>::Inhabited`](TypeLayout::Inhabited) is
199    /// [`inhabited::Inhabited`], [`MaybeUninhabited::Uninhabited`]
200    /// otherwise.
201    pub const fn new<U: TypeLayout>(v: T) -> Self {
202        if <U::Inhabited as Same<inhabited::Inhabited>>::EQ {
203            Self::Inhabited(v)
204        } else {
205            Self::Uninhabited
206        }
207    }
208}
209
210impl<T: Default> Default for MaybeUninhabited<T> {
211    fn default() -> Self {
212        Self::Inhabited(T::default())
213    }
214}
215
216/// Utility trait that provides the shallow layout of a type.
217///
218/// # Safety
219///
220/// It is only safe to implement this trait if it accurately describes the
221///  type's layout. Use
222/// [`#[derive(TypeLayout)]`](const_type_layout_derive::TypeLayout) instead.
223///
224/// # Example
225///
226/// The struct `Foo` with `u8` and `u16` fields implements [`TypeLayout`] as
227/// follows:
228///
229/// ```rust
230/// # #![feature(const_type_name)]
231/// # #![feature(offset_of)]
232/// # use const_type_layout::{
233/// #    Field, MaybeUninhabited, TypeLayout, TypeLayoutInfo, TypeStructure,
234/// # };
235/// # use const_type_layout::inhabited;
236/// # use const_type_layout::typeset::{ComputeTypeSet, ExpandTypeSet, tset};
237/// struct Foo {
238///     a: u8,
239///     b: u16,
240/// }
241///
242/// unsafe impl TypeLayout for Foo {
243///     type Inhabited = inhabited::all![u8, u16];
244///
245///     const TYPE_LAYOUT: TypeLayoutInfo<'static> = TypeLayoutInfo {
246///         name: ::core::any::type_name::<Self>(),
247///         size: ::core::mem::size_of::<Self>(),
248///         alignment: ::core::mem::align_of::<Self>(),
249///         structure: TypeStructure::Struct {
250///             repr: "",
251///             fields: &[
252///                 Field {
253///                     name: "a",
254///                     offset: MaybeUninhabited::new::<u8>(::core::mem::offset_of!(Self, a)),
255///                     ty: ::core::any::type_name::<u8>(),
256///                 },
257///                 Field {
258///                     name: "b",
259///                     offset: MaybeUninhabited::new::<u16>(::core::mem::offset_of!(Self, b)),
260///                     ty: ::core::any::type_name::<u16>(),
261///                 },
262///             ],
263///         },
264///     };
265/// }
266/// ```
267///
268/// Note that if you implement [`TypeLayout`], you should also implement
269/// [`typeset::ComputeTypeSet`] for it.
270pub unsafe trait TypeLayout: Sized {
271    /// Marker type for whether the type is
272    /// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited) or
273    /// [uninhabited](https://doc.rust-lang.org/reference/glossary.html#uninhabited).
274    /// The associated type must be either [`inhabited::Inhabited`]
275    /// or [`inhabited::Uninhabited`].
276    type Inhabited: inhabited::OutputMaybeInhabited;
277
278    /// Shallow layout of the type.
279    const TYPE_LAYOUT: TypeLayoutInfo<'static>;
280}
281
282/// Utility trait that provides the deep layout of a type.
283pub trait TypeGraphLayout: TypeLayout + typeset::ComputeTypeSet {
284    /// Shallow layout of the type.
285    const TYPE_GRAPH: TypeLayoutGraph<'static>;
286}
287
288impl<T: TypeLayout + typeset::ComputeTypeSet> TypeGraphLayout for T {
289    const TYPE_GRAPH: TypeLayoutGraph<'static> = TypeLayoutGraph::new::<T>();
290}
291
292#[must_use]
293/// Compute the number of bytes that this type's [`TypeLayoutGraph`] serialises
294/// into.
295pub const fn serialised_type_graph_len<T: TypeGraphLayout>() -> usize {
296    T::TYPE_GRAPH.serialised_len()
297}
298
299#[must_use]
300/// Serialise this type's [`TypeLayoutGraph`] into an array of bytes of length
301/// [`serialised_type_graph_len`].
302pub const fn serialise_type_graph<T: TypeGraphLayout>() -> [u8; serialised_type_graph_len::<T>()] {
303    let mut bytes = [0_u8; serialised_type_graph_len::<T>()];
304
305    T::TYPE_GRAPH.serialise(&mut bytes);
306
307    bytes
308}
309
310#[must_use]
311/// Hash this type's [`TypeLayoutGraph`] using the provided `seed`.
312///
313/// The hash is produced over the serialised form of the [`TypeLayoutGraph`], as
314/// computed by [`serialise_type_graph`].
315pub const fn hash_type_graph<T: TypeGraphLayout>(seed: u64) -> u64 {
316    T::TYPE_GRAPH.hash(seed)
317}
318
319#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
320#[cfg_attr(feature = "serde", allow(clippy::unsafe_derive_deserialize))]
321#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
322/// Description of the deep layout of a type.
323pub struct TypeLayoutGraph<
324    'a,
325    F: Deref<Target = [Field<'a>]> = &'a [Field<'a>],
326    V: Deref<Target = [Variant<'a, F>]> = &'a [Variant<'a, F>],
327    I: Deref<Target = TypeLayoutInfo<'a, F, V>> = &'a TypeLayoutInfo<'a, F, V>,
328    G: Deref<Target = [I]> = &'a [I],
329> {
330    /// The type's fully-qualified name.
331    #[cfg_attr(feature = "serde", serde(borrow))]
332    pub ty: &'a str,
333    /// The list of types that make up the complete graph describing the deep
334    /// layout of this type.
335    pub tys: G,
336}
337
338#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
339#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
340/// Description of the shallow layout of a type.
341pub struct TypeLayoutInfo<
342    'a,
343    F: Deref<Target = [Field<'a>]> = &'a [Field<'a>],
344    V: Deref<Target = [Variant<'a, F>]> = &'a [Variant<'a, F>],
345> {
346    /// The type's fully-qualified name.
347    #[cfg_attr(feature = "serde", serde(borrow))]
348    pub name: &'a str,
349    /// The type's size.
350    pub size: usize,
351    /// The type's minimum alignment.
352    pub alignment: usize,
353    /// The type's shallow structure.
354    #[cfg_attr(feature = "serde", serde(borrow))]
355    pub structure: TypeStructure<'a, F, V>,
356}
357
358#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
359#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
360/// Description of the shallow structure of a type.
361pub enum TypeStructure<
362    'a,
363    F: Deref<Target = [Field<'a>]> = &'a [Field<'a>],
364    V: Deref<Target = [Variant<'a, F>]> = &'a [Variant<'a, F>],
365> {
366    /// A primitive type, e.g. `()`, `u8`, `*const i32`, `&mut bool`, `[char;
367    /// 4]`, or `fn(f32) -> !`.
368    Primitive,
369    /// A struct-like type, including unit structs, tuple structs, structs, and
370    /// tuples.
371    Struct {
372        /// The string representation of the type's `#[repr(...)]` attributes.
373        #[cfg_attr(feature = "serde", serde(borrow))]
374        repr: &'a str,
375        /// The fields of the struct.
376        fields: F,
377    },
378    /// A union type.
379    Union {
380        /// The string representation of the type's `#[repr(...)]` attributes.
381        #[cfg_attr(feature = "serde", serde(borrow))]
382        repr: &'a str,
383        /// The fields of the union.
384        fields: F,
385    },
386    /// An enum type.
387    Enum {
388        /// The string representation of the type's `#[repr(...)]` attributes.
389        #[cfg_attr(feature = "serde", serde(borrow))]
390        repr: &'a str,
391        /// The variants of the union.
392        variants: V,
393    },
394}
395
396#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
397#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
398/// Description of the shallow layout of a variant
399pub struct Variant<'a, F: Deref<Target = [Field<'a>]> = &'a [Field<'a>]> {
400    /// The variant's name.
401    #[cfg_attr(feature = "serde", serde(borrow))]
402    pub name: &'a str,
403    /// The variant's descriminant, iff the variant is
404    /// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited).
405    pub discriminant: MaybeUninhabited<Discriminant>,
406    /// The variant's fields.
407    pub fields: F,
408}
409
410#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
411#[cfg_attr(feature = "serde", allow(clippy::unsafe_derive_deserialize))]
412#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
413/// Discriminant value of a type.
414pub enum Discriminant {
415    /// `#[repr(i8)]` discriminant.
416    I8(i8),
417    /// `#[repr(i16)]` discriminant.
418    I16(i16),
419    /// `#[repr(i32)]` discriminant.
420    I32(i32),
421    /// `#[repr(i64)]` discriminant.
422    I64(i64),
423    /// `#[repr(i128)]` discriminant.
424    I128(i128),
425    /// `#[repr(isize)]` discriminant (default).
426    Isize(isize),
427    /// `#[repr(u8)]` discriminant.
428    U8(u8),
429    /// `#[repr(u16)]` discriminant.
430    U16(u16),
431    /// `#[repr(u32)]` discriminant.
432    U32(u32),
433    /// `#[repr(u64)]` discriminant.
434    U64(u64),
435    /// `#[repr(u128)]` discriminant.
436    U128(u128),
437    /// `#[repr(usize)]` discriminant.
438    Usize(usize),
439}
440
441impl Discriminant {
442    #[allow(clippy::missing_panics_doc)]
443    #[must_use]
444    /// Constructs a [`Discriminant`] value with the given value `v` of the type
445    /// `T`'s [`core::marker::DiscriminantKind::Discriminant`].
446    pub const fn new<T: ExtractDiscriminant>(v: T::Discriminant) -> Self {
447        #[repr(C)]
448        union Transmute<T: Copy> {
449            v: T,
450            i8: i8,
451            i16: i16,
452            i32: i32,
453            i64: i64,
454            i128: i128,
455            isize: isize,
456            u8: u8,
457            u16: u16,
458            u32: u32,
459            u64: u64,
460            u128: u128,
461            usize: usize,
462        }
463
464        if <T::Discriminant as Same<i8>>::EQ {
465            // SAFETY: v is of type T::TY which is equivalent to i8
466            return Self::I8(unsafe { Transmute { v }.i8 });
467        } else if <T::Discriminant as Same<i16>>::EQ {
468            // SAFETY: v is of type T::TY which is equivalent to i16
469            return Self::I16(unsafe { Transmute { v }.i16 });
470        } else if <T::Discriminant as Same<i32>>::EQ {
471            // SAFETY: v is of type T::TY which is equivalent to i32
472            return Self::I32(unsafe { Transmute { v }.i32 });
473        } else if <T::Discriminant as Same<i64>>::EQ {
474            // SAFETY: v is of type T::TY which is equivalent to i64
475            return Self::I64(unsafe { Transmute { v }.i64 });
476        } else if <T::Discriminant as Same<i128>>::EQ {
477            // SAFETY: v is of type T::TY which is equivalent to i128
478            return Self::I128(unsafe { Transmute { v }.i128 });
479        } else if <T::Discriminant as Same<isize>>::EQ {
480            // SAFETY: v is of type T::TY which is equivalent to isize
481            return Self::Isize(unsafe { Transmute { v }.isize });
482        } else if <T::Discriminant as Same<u8>>::EQ {
483            // SAFETY: v is of type T::TY which is equivalent to u8
484            return Self::U8(unsafe { Transmute { v }.u8 });
485        } else if <T::Discriminant as Same<u16>>::EQ {
486            // SAFETY: v is of type T::TY which is equivalent to u16
487            return Self::U16(unsafe { Transmute { v }.u16 });
488        } else if <T::Discriminant as Same<u32>>::EQ {
489            // SAFETY: v is of type T::TY which is equivalent to u32
490            return Self::U32(unsafe { Transmute { v }.u32 });
491        } else if <T::Discriminant as Same<u64>>::EQ {
492            // SAFETY: v is of type T::TY which is equivalent to u64
493            return Self::U64(unsafe { Transmute { v }.u64 });
494        } else if <T::Discriminant as Same<u128>>::EQ {
495            // SAFETY: v is of type T::TY which is equivalent to u128
496            return Self::U128(unsafe { Transmute { v }.u128 });
497        } else if <T::Discriminant as Same<usize>>::EQ {
498            // SAFETY: v is of type T::TY which is equivalent to usize
499            return Self::Usize(unsafe { Transmute { v }.usize });
500        }
501
502        panic!("bug: unknown discriminant kind")
503    }
504}
505
506trait Same<T> {
507    const EQ: bool;
508}
509
510impl<T, U> Same<U> for T {
511    default const EQ: bool = false;
512}
513
514impl<T> Same<T> for T {
515    const EQ: bool = true;
516}
517
518/// Helper trait to extract the [`core::marker::DiscriminantKind::Discriminant`]
519/// of a type.
520///
521/// Implementing this trait also guarantees that the
522/// [`core::marker::DiscriminantKind::Discriminant`] implements
523/// [`typeset::ComputeTypeSet`] and that its values can be represented by
524/// [`ExtractDiscriminant::Discriminant`].
525pub trait ExtractDiscriminant {
526    /// The type of the discriminant, which must satisfy the trait bounds
527    /// required by [`core::mem::Discriminant`].
528    ///
529    /// Enums implementing [`TypeLayout`] and [`typeset::ComputeTypeSet`]
530    /// manually should include [`ExtractDiscriminant::Discriminant`] in
531    /// their [`typeset::ComputeTypeSet::Output`] using the [`typeset::tset`]
532    /// helper macro.
533    type Discriminant: Clone
534        + Copy
535        + fmt::Debug
536        + Eq
537        + PartialEq
538        + core::hash::Hash
539        + Send
540        + Sync
541        + Unpin
542        + TypeGraphLayout;
543}
544
545impl<T> ExtractDiscriminant for T {
546    type Discriminant =
547        <T as ExtractDiscriminantSpec<<T as core::marker::DiscriminantKind>::Discriminant>>::Ty;
548}
549
550#[doc(hidden)]
551pub trait ExtractDiscriminantSpec<T> {
552    type Ty: Clone
553        + Copy
554        + fmt::Debug
555        + Eq
556        + PartialEq
557        + core::hash::Hash
558        + Send
559        + Sync
560        + Unpin
561        + TypeGraphLayout;
562}
563
564impl<T> ExtractDiscriminantSpec<<T as core::marker::DiscriminantKind>::Discriminant> for T {
565    default type Ty = !;
566}
567
568macro_rules! impl_extract_discriminant {
569    ($variant:ident($ty:ty)) => {
570        impl<T: core::marker::DiscriminantKind<Discriminant = $ty>> ExtractDiscriminantSpec<$ty> for T {
571            type Ty = $ty;
572        }
573    };
574    ($($variant:ident($ty:ty)),*) => {
575        $(impl_extract_discriminant! { $variant($ty) })*
576    };
577}
578
579impl_extract_discriminant! {
580    I8(i8), I16(i16), I32(i32), I64(i64), I128(i128), Isize(isize),
581    U8(u8), U16(u16), U32(u32), U64(u64), U128(u128), Usize(usize)
582}
583
584#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
585#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
586/// Descriptor of the shallow layout of a field.
587pub struct Field<'a> {
588    /// The field's name.
589    #[cfg_attr(feature = "serde", serde(borrow))]
590    pub name: &'a str,
591    /// The field's byte offset, iff the field is
592    /// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited).
593    pub offset: MaybeUninhabited<usize>,
594    /// The fully-qualified name of the field's type. This is used as a key
595    /// inside [`TypeLayoutGraph::tys`] to find the field's type's layout by
596    /// its [`TypeLayoutInfo::name`].
597    #[cfg_attr(feature = "serde", serde(borrow))]
598    pub ty: &'a str,
599}
600
601impl TypeLayoutGraph<'static> {
602    #[must_use]
603    /// Construct the deep type layout descriptor for a type `T`.
604    pub const fn new<T: TypeLayout + typeset::ComputeTypeSet>() -> Self {
605        Self {
606            ty: <T as TypeLayout>::TYPE_LAYOUT.name,
607            // SAFETY:
608            // - ComputeSet is a sealed trait and its TYS const is always a HList made of only Cons
609            //   of &'static TypeLayoutInfo and Empty
610            // - Cons is a repr(C) struct with a head followed by a tail, Empty is a zero-sized
611            //   repr(C) struct
612            // - the HList is layout-equivalent to an array of the same length as ComputeSet::LEN
613            // - ComputeSet::TYS provides a static non-dangling reference that we can use to produce
614            //   the data pointer for a slice
615            tys: unsafe {
616                core::slice::from_raw_parts(
617                    core::ptr::from_ref(<typeset::TypeSet<T> as typeset::ComputeSet>::TYS).cast(),
618                    <typeset::TypeSet<T> as typeset::ComputeSet>::LEN,
619                )
620            },
621        }
622    }
623}
624
625impl<
626        'a,
627        // F: Deref<Target = [Field<'a>]>,
628        // V: Deref<Target = [Variant<'a, F>]>,
629        // P: Deref<Target = [&'a str]>,
630        // I: Deref<Target = TypeLayoutInfo<'a, F, V, P>>,
631        // G: Deref<Target = [I]>,
632    >
633    TypeLayoutGraph<
634        'a,
635        // F, V, P, I, G,
636    >
637{
638    #[must_use]
639    /// Compute the number of bytes that this [`TypeLayoutGraph`] serialises
640    /// into.
641    pub const fn serialised_len(&self) -> usize
642// where
643    //     F: ~const Deref<Target = [Field<'a>]>,
644    //     V: ~const Deref<Target = [Variant<'a, F>]>,
645    //     P: ~const Deref<Target = [&'a str]>,
646    //     I: ~const Deref<Target = TypeLayoutInfo<'a, F, V, P>>,
647    //     G: ~const Deref<Target = [I]>,
648    {
649        let mut counter = ser::Serialiser::counter(0);
650        counter.serialise_type_layout_graph(self);
651        let len = counter.cursor();
652
653        let mut last_full_len = len;
654
655        let mut counter = ser::Serialiser::counter(len);
656        counter.serialise_usize(last_full_len);
657        let mut full_len = counter.cursor();
658
659        while full_len != last_full_len {
660            last_full_len = full_len;
661
662            let mut counter = ser::Serialiser::counter(len);
663            counter.serialise_usize(last_full_len);
664            full_len = counter.cursor();
665        }
666
667        full_len
668    }
669
670    /// Serialise this [`TypeLayoutGraph`] into the mutable byte slice.
671    /// `bytes` must have a length of at least [`Self::serialised_len`].
672    ///
673    /// Use [`serialise_type_graph`] instead to serialise the
674    /// [`TypeLayoutGraph`] of a type `T` into a byte array of the
675    /// appropriate length.
676    ///
677    /// # Panics
678    ///
679    /// This method panics iff `bytes` has a length of less than
680    /// [`Self::serialised_len`].
681    pub const fn serialise(&self, bytes: &mut [u8])
682    // where
683    //     F: ~const Deref<Target = [Field<'a>]>,
684    //     V: ~const Deref<Target = [Variant<'a, F>]>,
685    //     P: ~const Deref<Target = [&'a str]>,
686    //     I: ~const Deref<Target = TypeLayoutInfo<'a, F, V, P>>,
687    //     G: ~const Deref<Target = [I]>,
688    {
689        let mut writer = ser::Serialiser::writer(bytes, 0);
690        writer.serialise_usize(self.serialised_len());
691        writer.serialise_type_layout_graph(self);
692    }
693
694    #[must_use]
695    /// Hash this [`TypeLayoutGraph`] using the provided `hasher`.
696    ///
697    /// The hash is produced over the serialised form of this
698    /// [`TypeLayoutGraph`], as computed by [`Self::serialise`].
699    pub const fn hash(&self, seed: u64) -> u64
700// where
701    //     F: ~const Deref<Target = [Field<'a>]>,
702    //     V: ~const Deref<Target = [Variant<'a, F>]>,
703    //     P: ~const Deref<Target = [&'a str]>,
704    //     I: ~const Deref<Target = TypeLayoutInfo<'a, F, V, P>>,
705    //     G: ~const Deref<Target = [I]>,
706    {
707        let mut hasher = ser::Serialiser::hasher(seed);
708
709        hasher.serialise_usize(self.serialised_len());
710        hasher.serialise_type_layout_graph(self);
711
712        hasher.hash()
713    }
714}
715
716impl<
717        'a,
718        F: Deref<Target = [Field<'a>]> + fmt::Debug,
719        V: Deref<Target = [Variant<'a, F>]> + fmt::Debug,
720        I: Deref<Target = TypeLayoutInfo<'a, F, V>> + fmt::Debug,
721        G: Deref<Target = [I]> + fmt::Debug,
722    > fmt::Debug for TypeLayoutGraph<'a, F, V, I, G>
723{
724    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
725        fmt.write_fmt(format_args!("TypeLayoutGraph<{}>({:?})", self.ty, self.tys))
726    }
727}