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}