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