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}