Skip to main content

core/mem/
type_info.rs

1//! MVP for exposing compile-time information about types in a
2//! runtime or const-eval processable way.
3
4use crate::any::TypeId;
5use crate::fmt;
6use crate::intrinsics::{self, type_id, type_of};
7use crate::marker::PointeeSized;
8use crate::ptr::DynMetadata;
9
10/// Compile-time type information.
11#[derive(Debug)]
12#[non_exhaustive]
13#[lang = "type_info"]
14#[unstable(feature = "type_info", issue = "146922")]
15pub struct Type {
16    /// Per-type information
17    pub kind: TypeKind,
18}
19
20/// Info of a trait implementation, you can retrieve the vtable with [Self::get_vtable]
21#[derive(Debug, PartialEq, Eq)]
22#[unstable(feature = "type_info", issue = "146922")]
23#[non_exhaustive]
24pub struct TraitImpl<T: PointeeSized> {
25    pub(crate) vtable: DynMetadata<T>,
26}
27
28impl<T: PointeeSized> TraitImpl<T> {
29    /// Gets the raw vtable for type reflection mapping
30    pub const fn get_vtable(&self) -> DynMetadata<T> {
31        self.vtable
32    }
33}
34
35impl TypeId {
36    /// Compute the type information of a concrete type.
37    /// It can only be called at compile time.
38    #[unstable(feature = "type_info", issue = "146922")]
39    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
40    #[rustc_comptime]
41    pub fn info(self) -> Type {
42        type_of(self)
43    }
44}
45
46impl Type {
47    /// Returns the type information of the generic type parameter.
48    ///
49    /// Note: Unlike `TypeId`s obtained via `TypeId::of`, the `Type`
50    /// struct and its fields contain `TypeId`s that are not necessarily
51    /// derived from types that outlive `'static`. This means that using
52    /// the `TypeId`s (transitively) obtained from this function will
53    /// be able to break invariants that other `TypeId` consuming crates
54    /// may have assumed to hold.
55    #[unstable(feature = "type_info", issue = "146922")]
56    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
57    pub const fn of<T: ?Sized>() -> Self {
58        const { type_id::<T>().info() }
59    }
60}
61
62/// Compile-time type information.
63#[derive(Debug)]
64#[non_exhaustive]
65#[unstable(feature = "type_info", issue = "146922")]
66pub enum TypeKind {
67    /// Tuples.
68    Tuple(Tuple),
69    /// Arrays.
70    Array(Array),
71    /// Slices.
72    Slice(Slice),
73    /// Dynamic Traits.
74    DynTrait(DynTrait),
75    /// Structs.
76    Struct(Struct),
77    /// Enums.
78    Enum(Enum),
79    /// Unions.
80    Union(Union),
81    /// Primitive boolean type.
82    Bool(Bool),
83    /// Primitive character type.
84    Char(Char),
85    /// Primitive signed and unsigned integer type.
86    Int(Int),
87    /// Primitive floating-point type.
88    Float(Float),
89    /// String slice type.
90    Str(Str),
91    /// References.
92    Reference(Reference),
93    /// Pointers.
94    Pointer(Pointer),
95    /// Function pointers.
96    FnPtr(FnPtr),
97    /// FIXME(#146922): add all the common types
98    Other,
99}
100
101/// Compile-time type information about tuples.
102#[derive(Debug)]
103#[non_exhaustive]
104#[unstable(feature = "type_info", issue = "146922")]
105pub struct Tuple {
106    /// All fields of a tuple.
107    pub fields: &'static [Field],
108}
109
110/// Compile-time type information about fields of tuples, structs and enum variants.
111#[derive(Debug)]
112#[non_exhaustive]
113#[unstable(feature = "type_info", issue = "146922")]
114pub struct Field {
115    /// The name of the field.
116    pub name: &'static str,
117    /// The field's type.
118    pub ty: TypeId,
119    /// Offset in bytes from the parent type
120    pub offset: usize,
121}
122
123/// Compile-time type information about arrays.
124#[derive(Debug)]
125#[non_exhaustive]
126#[unstable(feature = "type_info", issue = "146922")]
127pub struct Array {
128    /// The type of each element in the array.
129    pub element_ty: TypeId,
130    /// The length of the array.
131    pub len: usize,
132}
133
134/// Compile-time type information about slices.
135#[derive(Debug)]
136#[non_exhaustive]
137#[unstable(feature = "type_info", issue = "146922")]
138pub struct Slice {
139    /// The type of each element in the slice.
140    pub element_ty: TypeId,
141}
142
143/// Compile-time type information about dynamic traits.
144/// FIXME(#146922): Add super traits and generics
145#[derive(Debug)]
146#[non_exhaustive]
147#[unstable(feature = "type_info", issue = "146922")]
148pub struct DynTrait {
149    /// The predicates of  a dynamic trait.
150    pub predicates: &'static [DynTraitPredicate],
151}
152
153/// Compile-time type information about a dynamic trait predicate.
154#[derive(Debug)]
155#[non_exhaustive]
156#[unstable(feature = "type_info", issue = "146922")]
157pub struct DynTraitPredicate {
158    /// The type of the trait as a dynamic trait type.
159    pub trait_ty: Trait,
160}
161
162/// Compile-time type information about a trait.
163#[derive(Debug)]
164#[non_exhaustive]
165#[unstable(feature = "type_info", issue = "146922")]
166pub struct Trait {
167    /// The TypeId of the trait as a dynamic type
168    pub ty: TypeId,
169    /// Whether the trait is an auto trait
170    pub is_auto: bool,
171}
172
173/// Compile-time type information about structs.
174#[derive(Debug)]
175#[non_exhaustive]
176#[unstable(feature = "type_info", issue = "146922")]
177pub struct Struct {
178    /// Instantiated generics of the struct.
179    pub generics: &'static [Generic],
180    /// All fields of the struct.
181    pub fields: &'static [Field],
182    /// Whether the struct field list is non-exhaustive.
183    pub non_exhaustive: bool,
184}
185
186/// Compile-time type information about unions.
187#[derive(Debug)]
188#[non_exhaustive]
189#[unstable(feature = "type_info", issue = "146922")]
190pub struct Union {
191    /// Instantiated generics of the union.
192    pub generics: &'static [Generic],
193    /// All fields of the union.
194    pub fields: &'static [Field],
195}
196
197/// Compile-time type information about enums.
198#[derive(Debug)]
199#[non_exhaustive]
200#[unstable(feature = "type_info", issue = "146922")]
201pub struct Enum {
202    /// Instantiated generics of the enum.
203    pub generics: &'static [Generic],
204    /// All variants of the enum.
205    pub variants: &'static [Variant],
206    /// Whether the enum variant list is non-exhaustive.
207    pub non_exhaustive: bool,
208}
209
210/// Compile-time type information about variants of enums.
211#[derive(Debug)]
212#[non_exhaustive]
213#[unstable(feature = "type_info", issue = "146922")]
214pub struct Variant {
215    /// The name of the variant.
216    pub name: &'static str,
217    /// All fields of the variant.
218    pub fields: &'static [Field],
219    /// Whether the enum variant fields are non-exhaustive.
220    pub non_exhaustive: bool,
221}
222
223/// Compile-time type information about instantiated generics of structs, enum and union variants.
224#[derive(Debug)]
225#[non_exhaustive]
226#[unstable(feature = "type_info", issue = "146922")]
227#[lang = "type_info_generic"]
228pub enum Generic {
229    /// Lifetimes.
230    Lifetime(Lifetime),
231    /// Types.
232    Type(GenericType),
233    /// Const parameters.
234    Const(Const),
235}
236
237/// Compile-time type information about generic lifetimes.
238#[derive(Debug)]
239#[non_exhaustive]
240#[unstable(feature = "type_info", issue = "146922")]
241pub struct Lifetime {
242    // No additional information to provide for now.
243}
244
245/// Compile-time type information about instantiated generic types.
246#[derive(Debug)]
247#[non_exhaustive]
248#[unstable(feature = "type_info", issue = "146922")]
249pub struct GenericType {
250    /// The type itself.
251    pub ty: TypeId,
252}
253
254/// Compile-time type information about generic const parameters.
255#[derive(Debug)]
256#[non_exhaustive]
257#[unstable(feature = "type_info", issue = "146922")]
258pub struct Const {
259    /// The const's type.
260    pub ty: TypeId,
261}
262
263/// Compile-time type information about `bool`.
264#[derive(Debug)]
265#[non_exhaustive]
266#[unstable(feature = "type_info", issue = "146922")]
267pub struct Bool {
268    // No additional information to provide for now.
269}
270
271/// Compile-time type information about `char`.
272#[derive(Debug)]
273#[non_exhaustive]
274#[unstable(feature = "type_info", issue = "146922")]
275pub struct Char {
276    // No additional information to provide for now.
277}
278
279/// Compile-time type information about signed and unsigned integer types.
280#[derive(Debug)]
281#[non_exhaustive]
282#[unstable(feature = "type_info", issue = "146922")]
283pub struct Int {
284    /// The bit width of the signed integer type.
285    pub bits: u32,
286    /// Whether the integer type is signed.
287    pub signed: bool,
288}
289
290/// Compile-time type information about floating-point types.
291#[derive(Debug)]
292#[non_exhaustive]
293#[unstable(feature = "type_info", issue = "146922")]
294pub struct Float {
295    /// The bit width of the floating-point type.
296    pub bits: u32,
297}
298
299/// Compile-time type information about string slice types.
300#[derive(Debug)]
301#[non_exhaustive]
302#[unstable(feature = "type_info", issue = "146922")]
303pub struct Str {
304    // No additional information to provide for now.
305}
306
307/// Compile-time type information about references.
308#[derive(Debug)]
309#[non_exhaustive]
310#[unstable(feature = "type_info", issue = "146922")]
311pub struct Reference {
312    /// The type of the value being referred to.
313    pub pointee: TypeId,
314    /// Whether this reference is mutable or not.
315    pub mutable: bool,
316}
317
318/// Compile-time type information about pointers.
319#[derive(Debug)]
320#[non_exhaustive]
321#[unstable(feature = "type_info", issue = "146922")]
322pub struct Pointer {
323    /// The type of the value being pointed to.
324    pub pointee: TypeId,
325    /// Whether this pointer is mutable or not.
326    pub mutable: bool,
327}
328
329#[derive(Debug)]
330#[unstable(feature = "type_info", issue = "146922")]
331/// Function pointer, e.g. fn(u8),
332pub struct FnPtr {
333    /// Unsafety, true is unsafe
334    pub unsafety: bool,
335
336    /// Abi, e.g. extern "C"
337    pub abi: Abi,
338
339    /// Function inputs
340    pub inputs: &'static [TypeId],
341
342    /// Function return type, default is TypeId::of::<()>
343    pub output: TypeId,
344
345    /// Vardiadic function, e.g. extern "C" fn add(n: usize, mut args: ...);
346    pub variadic: bool,
347
348    // FIXME(splat): should these fields be private, or merged into an Option<u8/u16>?
349    /// Is any function argument splatted?
350    pub is_splatted: bool,
351
352    /// The index of the splatted function argument in `inputs`, only valid if `is_splatted` is true.
353    /// e.g. in `fn overload(a: u8, #[rustc_splat] b: (f32, usize))` the index is 1, and it can be called
354    /// as `overload(a, 1.0, 2)`.
355    pub splatted_index: u8,
356}
357
358impl FnPtr {
359    /// Returns the splatted function argument index, or `None` if no argument is splatted.
360    pub const fn splatted(&self) -> Option<u8> {
361        if self.is_splatted { Some(self.splatted_index) } else { None }
362    }
363}
364
365#[derive(Debug, Default)]
366#[non_exhaustive]
367#[unstable(feature = "type_info", issue = "146922")]
368/// Abi of [FnPtr]
369pub enum Abi {
370    /// Named abi, e.g. extern "custom", "stdcall" etc.
371    Named(&'static str),
372
373    /// Default
374    #[default]
375    ExternRust,
376
377    /// C-calling convention
378    ExternC,
379}
380
381impl TypeId {
382    /// Returns the size of the type represented by this `TypeId`. `None` if it is unsized.
383    ///
384    /// # Examples
385    ///
386    /// ```
387    /// #![feature(type_info)]
388    /// use std::any::TypeId;
389    ///
390    /// assert_eq!(const { TypeId::of::<u32>().size() }, Some(4));
391    /// assert_eq!(const { TypeId::of::<[u8; 16]>().size() }, Some(16));
392    /// ```
393    #[unstable(feature = "type_info", issue = "146922")]
394    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
395    #[rustc_comptime]
396    pub fn size(self) -> Option<usize> {
397        intrinsics::size_of_type_id(self)
398    }
399
400    /// Returns the number of variants of the type represented by this `TypeId`.
401    ///
402    /// For enums, this is the number of variants. For structs and unions, this is always 1.
403    ///
404    /// ```
405    /// #![feature(type_info)]
406    /// use std::any::TypeId;
407    ///
408    /// assert_eq!(const { TypeId::of::<Option<()>>().variants() }, 2);
409    ///
410    /// struct Unit;
411    /// struct Point {
412    ///     x: u32,
413    ///     y: u32,
414    /// }
415    /// assert_eq!(const { TypeId::of::<Unit>().variants() }, 1);
416    /// assert_eq!(const { TypeId::of::<Point>().variants() }, 1);
417    /// assert_eq!(const { TypeId::of::<(f32, f32)>().variants() }, 1);
418    /// ```
419    #[unstable(feature = "type_info", issue = "146922")]
420    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
421    #[rustc_comptime]
422    pub fn variants(self) -> usize {
423        intrinsics::type_id_variants(self)
424    }
425
426    /// Returns the number of fields at the given `variant_index` of the type represented by this `TypeId`.
427    ///
428    /// ```
429    /// #![feature(type_info)]
430    /// use std::any::TypeId;
431    ///
432    /// assert_eq!(const { TypeId::of::<u32>().fields(0) }, 0);
433    ///
434    /// struct Point {
435    ///     x: u32,
436    ///     y: u32,
437    /// }
438    /// assert_eq!(const { TypeId::of::<Point>().fields(0) }, 2);
439    ///
440    /// enum Enum {
441    ///     Unit,
442    ///     Tuple(u32, u64),
443    ///     Struct { x: u32, y: u32, z: String },
444    /// }
445    /// assert_eq!(const { TypeId::of::<Enum>().fields(0) }, 0);
446    /// assert_eq!(const { TypeId::of::<Enum>().fields(1) }, 2);
447    /// assert_eq!(const { TypeId::of::<Enum>().fields(2) }, 3);
448    /// ```
449    ///
450    /// The variant index refers to the source order index of a variant in a type.
451    ///
452    /// For enums, these are always `0..variant_count`, regardless of any custom discriminants that may have been defined.
453    /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero.
454    ///
455    /// ```
456    /// enum Number {
457    ///     Seven = 7, // variant index == 0
458    ///     Six = 6,   // variant index == 1
459    /// }
460    /// ```
461    ///
462    /// Out-of-bounds indexing will be treated as a compile-time error.
463    ///
464    /// ```compile_fail,E0080
465    /// # #![feature(type_info)]
466    /// # use std::any::TypeId;
467    /// #
468    /// # struct Point {
469    /// #     x: u32,
470    /// #     y: u32,
471    /// # }
472    /// # enum Enum {
473    /// #     Unit,
474    /// #     Tuple(u32, u64),
475    /// #     Struct { x: u32, y: u32, z: String },
476    /// # }
477    /// const {
478    ///     _ = TypeId::of::<Point>().fields(10); // error: indexing out of bounds: the len is 2 but the index is 10
479    ///     _ = TypeId::of::<Enum>().fields(10); // error: indexing out of bounds: the len is 3 but the index is 10
480    /// }
481    /// ```
482    #[unstable(feature = "type_info", issue = "146922")]
483    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
484    #[rustc_comptime]
485    // FIXME(type_info): Add enum variant pattern types and use them to represent individual variants
486    // Then add a `variant` method to get a wrapper around such a pattern type (similar to the FRT
487    // type we have) and add methods on that. It's the only way to really sensibly represent
488    // things like `non_exhaustive` which can be applied to variants as well.
489    pub fn fields(self, variant_index: usize) -> usize {
490        intrinsics::type_id_fields(self, variant_index)
491    }
492
493    /// Returns the field representing type at the given index of the type represented by this `TypeId`.
494    ///
495    /// ```
496    /// #![feature(type_info)]
497    /// use std::any::TypeId;
498    ///
499    /// struct Point {
500    ///     x: u32,
501    ///     y: u32,
502    /// }
503    /// assert_eq!(const { TypeId::of::<Point>().field(0, 0).type_id() }, TypeId::of::<u32>());
504    /// assert_eq!(const { TypeId::of::<Point>().field(0, 1).type_id() }, TypeId::of::<u32>());
505    ///
506    /// enum Enum {
507    ///     Unit,
508    ///     Tuple(u32, u64),
509    ///     Struct { x: u32, y: u32, z: String },
510    /// }
511    /// assert_eq!(const { TypeId::of::<Enum>().field(1, 0).type_id() }, TypeId::of::<u32>());
512    /// assert_eq!(const { TypeId::of::<Enum>().field(2, 2).type_id() }, TypeId::of::<String>());
513    /// ```
514    ///
515    /// The variant index and field index refer to the source order index of a variant in a type and
516    /// the source order index of a field in a variant, respectively.
517    ///
518    /// For enums, variant indexes are always `0..variant_count`, regardless of any custom discriminants that may have been defined.
519    /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero.
520    ///
521    /// As for field indexes, they may not be the same as the layout order for `repr(Rust)` types, but they are for `repr(C)` types.
522    ///
523    /// ```
524    /// enum Enum {
525    ///     Foo,  // variant index == 0
526    ///     Bar { // variant index == 1
527    ///         a: (), // field index == 0 in `Bar`
528    ///         b: (), // field index == 1 in `Bar`
529    ///     }
530    /// }
531    /// ```
532    ///
533    /// Out-of-bounds indexing will be treated as a compile-time error.
534    ///
535    /// ```compile_fail,E0080
536    /// # #![feature(type_info)]
537    /// # use std::any::TypeId;
538    /// #
539    /// # struct Point {
540    /// #     x: u32,
541    /// #     y: u32,
542    /// # }
543    /// # enum Enum {
544    /// #     Unit,
545    /// #     Tuple(u32, u64),
546    /// #     Struct { x: u32, y: u32, z: String },
547    /// # }
548    /// const {
549    ///     _ = TypeId::of::<Point>().field(0, 10); // error: indexing out of bounds: the len is 2 but the index is 10
550    ///     _ = TypeId::of::<Enum>().field(2, 10); // error: indexing out of bounds: the len is 3 but the index is 10
551    /// }
552    /// ```
553    #[unstable(feature = "type_info", issue = "146922")]
554    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
555    #[rustc_comptime]
556    pub fn field(self, variant_index: usize, field_index: usize) -> FieldId {
557        FieldId {
558            frt_type_id: intrinsics::type_id_field_representing_type(
559                self,
560                variant_index,
561                field_index,
562            ),
563        }
564    }
565
566    /// Returns whether a type is marked with `#[non_exhaustive]`.
567    /// Returns `false` for everything but adts.
568    #[unstable(feature = "type_info", issue = "146922")]
569    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
570    #[rustc_comptime]
571    pub fn non_exhaustive(self) -> bool {
572        intrinsics::non_exhaustive(self)
573    }
574
575    /// Returns a list of generic parameters of the type.
576    /// Returns an empty slice for everything that doesn't have generics.
577    #[unstable(feature = "type_info", issue = "146922")]
578    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
579    #[rustc_comptime]
580    pub fn generics(self) -> &'static [Generic] {
581        intrinsics::type_id_generics(self)
582    }
583}
584
585/// Field representing type ID. Representing a field of a struct, tuple or enum variant.
586#[derive(Copy, PartialOrd, Ord, Hash)]
587#[derive_const(Clone, PartialEq, Eq)]
588#[unstable(feature = "type_info", issue = "146922")]
589pub struct FieldId {
590    frt_type_id: TypeId,
591}
592
593#[unstable(feature = "type_info", issue = "146922")]
594impl fmt::Debug for FieldId {
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        write!(f, "FieldId({:#034x})", self.frt_type_id.as_u128())
597    }
598}
599
600impl FieldId {
601    /// Returns the `TypeId` of the actual field type.
602    ///
603    /// ```
604    /// #![feature(type_info)]
605    /// use std::any::TypeId;
606    ///
607    /// struct Point {
608    ///     x: u32,
609    ///     y: u32,
610    /// }
611    /// assert_eq!(
612    ///     const { TypeId::of::<Point>().field(0, 0).type_id() },
613    ///     TypeId::of::<u32>()
614    /// );
615    /// ```
616    #[unstable(feature = "type_info", issue = "146922")]
617    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
618    #[rustc_comptime]
619    pub fn type_id(self) -> TypeId {
620        intrinsics::field_representing_type_actual_type_id(self.frt_type_id)
621    }
622
623    /// Returns the name of the field.
624    ///
625    /// ```
626    /// #![feature(type_info)]
627    /// use std::any::TypeId;
628    ///
629    /// struct Point {
630    ///     x: u32,
631    ///     y: u32,
632    /// }
633    /// assert_eq!(
634    ///     const { TypeId::of::<Point>().field(0, 0).name() },
635    ///     "x",
636    /// );
637    /// ```
638    #[unstable(feature = "type_info", issue = "146922")]
639    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
640    #[rustc_comptime]
641    pub fn name(self) -> &'static str {
642        intrinsics::field_representing_type_name(self.frt_type_id)
643    }
644    /// Returns the offset of the field wrt to its containing type.
645    ///
646    /// ```
647    /// #![feature(type_info)]
648    /// use std::any::TypeId;
649    ///
650    /// #[repr(C)]
651    /// struct Point {
652    ///     x: u32,
653    ///     y: u32,
654    /// }
655    /// assert_eq!(
656    ///     const { TypeId::of::<Point>().field(0, 1).offset() },
657    ///     4,
658    /// );
659    /// ```
660    #[unstable(feature = "type_info", issue = "146922")]
661    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
662    #[rustc_comptime]
663    pub fn offset(self) -> usize {
664        intrinsics::field_representing_type_offset(self.frt_type_id)
665    }
666}