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}