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    pub const 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")]
226pub enum Generic {
227    /// Lifetimes.
228    Lifetime(Lifetime),
229    /// Types.
230    Type(GenericType),
231    /// Const parameters.
232    Const(Const),
233}
234
235/// Compile-time type information about generic lifetimes.
236#[derive(Debug)]
237#[non_exhaustive]
238#[unstable(feature = "type_info", issue = "146922")]
239pub struct Lifetime {
240    // No additional information to provide for now.
241}
242
243/// Compile-time type information about instantiated generic types.
244#[derive(Debug)]
245#[non_exhaustive]
246#[unstable(feature = "type_info", issue = "146922")]
247pub struct GenericType {
248    /// The type itself.
249    pub ty: TypeId,
250}
251
252/// Compile-time type information about generic const parameters.
253#[derive(Debug)]
254#[non_exhaustive]
255#[unstable(feature = "type_info", issue = "146922")]
256pub struct Const {
257    /// The const's type.
258    pub ty: TypeId,
259}
260
261/// Compile-time type information about `bool`.
262#[derive(Debug)]
263#[non_exhaustive]
264#[unstable(feature = "type_info", issue = "146922")]
265pub struct Bool {
266    // No additional information to provide for now.
267}
268
269/// Compile-time type information about `char`.
270#[derive(Debug)]
271#[non_exhaustive]
272#[unstable(feature = "type_info", issue = "146922")]
273pub struct Char {
274    // No additional information to provide for now.
275}
276
277/// Compile-time type information about signed and unsigned integer types.
278#[derive(Debug)]
279#[non_exhaustive]
280#[unstable(feature = "type_info", issue = "146922")]
281pub struct Int {
282    /// The bit width of the signed integer type.
283    pub bits: u32,
284    /// Whether the integer type is signed.
285    pub signed: bool,
286}
287
288/// Compile-time type information about floating-point types.
289#[derive(Debug)]
290#[non_exhaustive]
291#[unstable(feature = "type_info", issue = "146922")]
292pub struct Float {
293    /// The bit width of the floating-point type.
294    pub bits: u32,
295}
296
297/// Compile-time type information about string slice types.
298#[derive(Debug)]
299#[non_exhaustive]
300#[unstable(feature = "type_info", issue = "146922")]
301pub struct Str {
302    // No additional information to provide for now.
303}
304
305/// Compile-time type information about references.
306#[derive(Debug)]
307#[non_exhaustive]
308#[unstable(feature = "type_info", issue = "146922")]
309pub struct Reference {
310    /// The type of the value being referred to.
311    pub pointee: TypeId,
312    /// Whether this reference is mutable or not.
313    pub mutable: bool,
314}
315
316/// Compile-time type information about pointers.
317#[derive(Debug)]
318#[non_exhaustive]
319#[unstable(feature = "type_info", issue = "146922")]
320pub struct Pointer {
321    /// The type of the value being pointed to.
322    pub pointee: TypeId,
323    /// Whether this pointer is mutable or not.
324    pub mutable: bool,
325}
326
327#[derive(Debug)]
328#[unstable(feature = "type_info", issue = "146922")]
329/// Function pointer, e.g. fn(u8),
330pub struct FnPtr {
331    /// Unsafety, true is unsafe
332    pub unsafety: bool,
333
334    /// Abi, e.g. extern "C"
335    pub abi: Abi,
336
337    /// Function inputs
338    pub inputs: &'static [TypeId],
339
340    /// Function return type, default is TypeId::of::<()>
341    pub output: TypeId,
342
343    /// Vardiadic function, e.g. extern "C" fn add(n: usize, mut args: ...);
344    pub variadic: bool,
345
346    // FIXME(splat): should these fields be private, or merged into an Option<u8/u16>?
347    /// Is any function argument splatted?
348    pub is_splatted: bool,
349
350    /// The index of the splatted function argument in `inputs`, only valid if `is_splatted` is true.
351    /// e.g. in `fn overload(a: u8, #[splat] b: (f32, usize))` the index is 1, and it can be called
352    /// as `overload(a, 1.0, 2)`.
353    pub splatted_index: u8,
354}
355
356impl FnPtr {
357    /// Returns the splatted function argument index, or `None` if no argument is splatted.
358    pub const fn splatted(&self) -> Option<u8> {
359        if self.is_splatted { Some(self.splatted_index) } else { None }
360    }
361}
362
363#[derive(Debug, Default)]
364#[non_exhaustive]
365#[unstable(feature = "type_info", issue = "146922")]
366/// Abi of [FnPtr]
367pub enum Abi {
368    /// Named abi, e.g. extern "custom", "stdcall" etc.
369    Named(&'static str),
370
371    /// Default
372    #[default]
373    ExternRust,
374
375    /// C-calling convention
376    ExternC,
377}
378
379impl TypeId {
380    /// Returns the size of the type represented by this `TypeId`. `None` if it is unsized.
381    ///
382    /// # Examples
383    ///
384    /// ```
385    /// #![feature(type_info)]
386    /// use std::any::TypeId;
387    ///
388    /// assert_eq!(const { TypeId::of::<u32>().size() }, Some(4));
389    /// assert_eq!(const { TypeId::of::<[u8; 16]>().size() }, Some(16));
390    /// ```
391    #[unstable(feature = "type_info", issue = "146922")]
392    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
393    #[rustc_comptime]
394    pub fn size(self) -> Option<usize> {
395        intrinsics::size_of_type_id(self)
396    }
397
398    /// Returns the number of variants of the type represented by this `TypeId`.
399    ///
400    /// For enums, this is the number of variants. For structs and unions, this is always 1.
401    ///
402    /// ```
403    /// #![feature(type_info)]
404    /// use std::any::TypeId;
405    ///
406    /// assert_eq!(const { TypeId::of::<Option<()>>().variants() }, 2);
407    ///
408    /// struct Unit;
409    /// struct Point {
410    ///     x: u32,
411    ///     y: u32,
412    /// }
413    /// assert_eq!(const { TypeId::of::<Unit>().variants() }, 1);
414    /// assert_eq!(const { TypeId::of::<Point>().variants() }, 1);
415    /// assert_eq!(const { TypeId::of::<(f32, f32)>().variants() }, 1);
416    /// ```
417    #[unstable(feature = "type_info", issue = "146922")]
418    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
419    #[rustc_comptime]
420    pub fn variants(self) -> usize {
421        intrinsics::type_id_variants(self)
422    }
423
424    /// Returns the number of fields at the given `variant_index` of the type represented by this `TypeId`.
425    ///
426    /// ```
427    /// #![feature(type_info)]
428    /// use std::any::TypeId;
429    ///
430    /// assert_eq!(const { TypeId::of::<u32>().fields(0) }, 0);
431    ///
432    /// struct Point {
433    ///     x: u32,
434    ///     y: u32,
435    /// }
436    /// assert_eq!(const { TypeId::of::<Point>().fields(0) }, 2);
437    ///
438    /// enum Enum {
439    ///     Unit,
440    ///     Tuple(u32, u64),
441    ///     Struct { x: u32, y: u32, z: String },
442    /// }
443    /// assert_eq!(const { TypeId::of::<Enum>().fields(0) }, 0);
444    /// assert_eq!(const { TypeId::of::<Enum>().fields(1) }, 2);
445    /// assert_eq!(const { TypeId::of::<Enum>().fields(2) }, 3);
446    /// ```
447    ///
448    /// The variant index refers to the source order index of a variant in a type.
449    ///
450    /// For enums, these are always `0..variant_count`, regardless of any custom discriminants that may have been defined.
451    /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero.
452    ///
453    /// ```
454    /// enum Number {
455    ///     Seven = 7, // variant index == 0
456    ///     Six = 6,   // variant index == 1
457    /// }
458    /// ```
459    ///
460    /// Out-of-bounds indexing will be treated as a compile-time error.
461    ///
462    /// ```compile_fail,E0080
463    /// # #![feature(type_info)]
464    /// # use std::any::TypeId;
465    /// #
466    /// # struct Point {
467    /// #     x: u32,
468    /// #     y: u32,
469    /// # }
470    /// # enum Enum {
471    /// #     Unit,
472    /// #     Tuple(u32, u64),
473    /// #     Struct { x: u32, y: u32, z: String },
474    /// # }
475    /// const {
476    ///     _ = TypeId::of::<Point>().fields(10); // error: indexing out of bounds: the len is 2 but the index is 10
477    ///     _ = TypeId::of::<Enum>().fields(10); // error: indexing out of bounds: the len is 3 but the index is 10
478    /// }
479    /// ```
480    #[unstable(feature = "type_info", issue = "146922")]
481    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
482    #[rustc_comptime]
483    pub fn fields(self, variant_index: usize) -> usize {
484        intrinsics::type_id_fields(self, variant_index)
485    }
486
487    /// Returns the field representing type at the given index of the type represented by this `TypeId`.
488    ///
489    /// ```
490    /// #![feature(type_info)]
491    /// use std::any::TypeId;
492    ///
493    /// struct Point {
494    ///     x: u32,
495    ///     y: u32,
496    /// }
497    /// assert_eq!(const { TypeId::of::<Point>().field(0, 0).type_id() }, TypeId::of::<u32>());
498    /// assert_eq!(const { TypeId::of::<Point>().field(0, 1).type_id() }, TypeId::of::<u32>());
499    ///
500    /// enum Enum {
501    ///     Unit,
502    ///     Tuple(u32, u64),
503    ///     Struct { x: u32, y: u32, z: String },
504    /// }
505    /// assert_eq!(const { TypeId::of::<Enum>().field(1, 0).type_id() }, TypeId::of::<u32>());
506    /// assert_eq!(const { TypeId::of::<Enum>().field(2, 2).type_id() }, TypeId::of::<String>());
507    /// ```
508    ///
509    /// The variant index and field index refer to the source order index of a variant in a type and
510    /// the source order index of a field in a variant, respectively.
511    ///
512    /// For enums, variant indexes are always `0..variant_count`, regardless of any custom discriminants that may have been defined.
513    /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero.
514    ///
515    /// 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.
516    ///
517    /// ```
518    /// enum Enum {
519    ///     Foo,  // variant index == 0
520    ///     Bar { // variant index == 1
521    ///         a: (), // field index == 0 in `Bar`
522    ///         b: (), // field index == 1 in `Bar`
523    ///     }
524    /// }
525    /// ```
526    ///
527    /// Out-of-bounds indexing will be treated as a compile-time error.
528    ///
529    /// ```compile_fail,E0080
530    /// # #![feature(type_info)]
531    /// # use std::any::TypeId;
532    /// #
533    /// # struct Point {
534    /// #     x: u32,
535    /// #     y: u32,
536    /// # }
537    /// # enum Enum {
538    /// #     Unit,
539    /// #     Tuple(u32, u64),
540    /// #     Struct { x: u32, y: u32, z: String },
541    /// # }
542    /// const {
543    ///     _ = TypeId::of::<Point>().field(0, 10); // error: indexing out of bounds: the len is 2 but the index is 10
544    ///     _ = TypeId::of::<Enum>().field(2, 10); // error: indexing out of bounds: the len is 3 but the index is 10
545    /// }
546    /// ```
547    #[unstable(feature = "type_info", issue = "146922")]
548    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
549    #[rustc_comptime]
550    pub fn field(self, variant_index: usize, field_index: usize) -> FieldId {
551        FieldId {
552            frt_type_id: intrinsics::type_id_field_representing_type(
553                self,
554                variant_index,
555                field_index,
556            ),
557        }
558    }
559}
560
561/// Field representing type ID. Representing a field of a struct, tuple or enum variant.
562#[derive(Copy, PartialOrd, Ord, Hash)]
563#[derive_const(Clone, PartialEq, Eq)]
564#[unstable(feature = "type_info", issue = "146922")]
565pub struct FieldId {
566    frt_type_id: TypeId,
567}
568
569#[unstable(feature = "type_info", issue = "146922")]
570impl fmt::Debug for FieldId {
571    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
572        write!(f, "FieldId({:#034x})", self.frt_type_id.as_u128())
573    }
574}
575
576impl FieldId {
577    /// Returns the `TypeId` of the actual field type.
578    ///
579    /// ```
580    /// #![feature(type_info)]
581    /// use std::any::TypeId;
582    ///
583    /// struct Point {
584    ///     x: u32,
585    ///     y: u32,
586    /// }
587    /// assert_eq!(
588    ///     const { TypeId::of::<Point>().field(0, 0).type_id() },
589    ///     TypeId::of::<u32>()
590    /// );
591    /// ```
592    #[unstable(feature = "type_info", issue = "146922")]
593    #[rustc_const_unstable(feature = "type_info", issue = "146922")]
594    #[rustc_comptime]
595    pub fn type_id(self) -> TypeId {
596        intrinsics::field_representing_type_actual_type_id(self.frt_type_id)
597    }
598}