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 is 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
347#[derive(Debug, Default)]
348#[non_exhaustive]
349#[unstable(feature = "type_info", issue = "146922")]
350/// Abi of [FnPtr]
351pub enum Abi {
352 /// Named abi, e.g. extern "custom", "stdcall" etc.
353 Named(&'static str),
354
355 /// Default
356 #[default]
357 ExternRust,
358
359 /// C-calling convention
360 ExternC,
361}
362
363impl TypeId {
364 /// Returns the size of the type represented by this `TypeId`. `None` if it is unsized.
365 ///
366 /// # Examples
367 ///
368 /// ```
369 /// #![feature(type_info)]
370 /// use std::any::TypeId;
371 ///
372 /// assert_eq!(const { TypeId::of::<u32>().size() }, Some(4));
373 /// assert_eq!(const { TypeId::of::<[u8; 16]>().size() }, Some(16));
374 /// ```
375 #[unstable(feature = "type_info", issue = "146922")]
376 #[rustc_const_unstable(feature = "type_info", issue = "146922")]
377 #[rustc_comptime]
378 pub fn size(self) -> Option<usize> {
379 intrinsics::size_of_type_id(self)
380 }
381
382 /// Returns the number of variants of the type represented by this `TypeId`.
383 ///
384 /// For enums, this is the number of variants. For structs and unions, this is always 1.
385 ///
386 /// ```
387 /// #![feature(type_info)]
388 /// use std::any::TypeId;
389 ///
390 /// assert_eq!(const { TypeId::of::<Option<()>>().variants() }, 2);
391 ///
392 /// struct Unit;
393 /// struct Point {
394 /// x: u32,
395 /// y: u32,
396 /// }
397 /// assert_eq!(const { TypeId::of::<Unit>().variants() }, 1);
398 /// assert_eq!(const { TypeId::of::<Point>().variants() }, 1);
399 /// assert_eq!(const { TypeId::of::<(f32, f32)>().variants() }, 1);
400 /// ```
401 #[unstable(feature = "type_info", issue = "146922")]
402 #[rustc_const_unstable(feature = "type_info", issue = "146922")]
403 #[rustc_comptime]
404 pub fn variants(self) -> usize {
405 intrinsics::type_id_variants(self)
406 }
407
408 /// Returns the number of fields at the given `variant_index` of the type represented by this `TypeId`.
409 ///
410 /// ```
411 /// #![feature(type_info)]
412 /// use std::any::TypeId;
413 ///
414 /// assert_eq!(const { TypeId::of::<u32>().fields(0) }, 0);
415 ///
416 /// struct Point {
417 /// x: u32,
418 /// y: u32,
419 /// }
420 /// assert_eq!(const { TypeId::of::<Point>().fields(0) }, 2);
421 ///
422 /// enum Enum {
423 /// Unit,
424 /// Tuple(u32, u64),
425 /// Struct { x: u32, y: u32, z: String },
426 /// }
427 /// assert_eq!(const { TypeId::of::<Enum>().fields(0) }, 0);
428 /// assert_eq!(const { TypeId::of::<Enum>().fields(1) }, 2);
429 /// assert_eq!(const { TypeId::of::<Enum>().fields(2) }, 3);
430 /// ```
431 ///
432 /// The variant index refers to the source order index of a variant in a type.
433 ///
434 /// For enums, these are always `0..variant_count`, regardless of any custom discriminants that may have been defined.
435 /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero.
436 ///
437 /// ```
438 /// enum Number {
439 /// Seven = 7, // variant index == 0
440 /// Six = 6, // variant index == 1
441 /// }
442 /// ```
443 ///
444 /// Out-of-bounds indexing will be treated as a compile-time error.
445 ///
446 /// ```compile_fail,E0080
447 /// # #![feature(type_info)]
448 /// # use std::any::TypeId;
449 /// #
450 /// # struct Point {
451 /// # x: u32,
452 /// # y: u32,
453 /// # }
454 /// # enum Enum {
455 /// # Unit,
456 /// # Tuple(u32, u64),
457 /// # Struct { x: u32, y: u32, z: String },
458 /// # }
459 /// const {
460 /// _ = TypeId::of::<Point>().fields(10); // error: indexing out of bounds: the len is 2 but the index is 10
461 /// _ = TypeId::of::<Enum>().fields(10); // error: indexing out of bounds: the len is 3 but the index is 10
462 /// }
463 /// ```
464 #[unstable(feature = "type_info", issue = "146922")]
465 #[rustc_const_unstable(feature = "type_info", issue = "146922")]
466 #[rustc_comptime]
467 pub fn fields(self, variant_index: usize) -> usize {
468 intrinsics::type_id_fields(self, variant_index)
469 }
470
471 /// Returns the field representing type at the given index of the type represented by this `TypeId`.
472 ///
473 /// ```
474 /// #![feature(type_info)]
475 /// use std::any::TypeId;
476 ///
477 /// struct Point {
478 /// x: u32,
479 /// y: u32,
480 /// }
481 /// assert_eq!(const { TypeId::of::<Point>().field(0, 0).type_id() }, TypeId::of::<u32>());
482 /// assert_eq!(const { TypeId::of::<Point>().field(0, 1).type_id() }, TypeId::of::<u32>());
483 ///
484 /// enum Enum {
485 /// Unit,
486 /// Tuple(u32, u64),
487 /// Struct { x: u32, y: u32, z: String },
488 /// }
489 /// assert_eq!(const { TypeId::of::<Enum>().field(1, 0).type_id() }, TypeId::of::<u32>());
490 /// assert_eq!(const { TypeId::of::<Enum>().field(2, 2).type_id() }, TypeId::of::<String>());
491 /// ```
492 ///
493 /// The variant index and field index refer to the source order index of a variant in a type and
494 /// the source order index of a field in a variant, respectively.
495 ///
496 /// For enums, variant indexes are always `0..variant_count`, regardless of any custom discriminants that may have been defined.
497 /// `struct`s, `tuples`, and `unions`s are considered to have a single variant with variant index zero.
498 ///
499 /// 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.
500 ///
501 /// ```
502 /// enum Enum {
503 /// Foo, // variant index == 0
504 /// Bar { // variant index == 1
505 /// a: (), // field index == 0 in `Bar`
506 /// b: (), // field index == 1 in `Bar`
507 /// }
508 /// }
509 /// ```
510 ///
511 /// Out-of-bounds indexing will be treated as a compile-time error.
512 ///
513 /// ```compile_fail,E0080
514 /// # #![feature(type_info)]
515 /// # use std::any::TypeId;
516 /// #
517 /// # struct Point {
518 /// # x: u32,
519 /// # y: u32,
520 /// # }
521 /// # enum Enum {
522 /// # Unit,
523 /// # Tuple(u32, u64),
524 /// # Struct { x: u32, y: u32, z: String },
525 /// # }
526 /// const {
527 /// _ = TypeId::of::<Point>().field(0, 10); // error: indexing out of bounds: the len is 2 but the index is 10
528 /// _ = TypeId::of::<Enum>().field(2, 10); // error: indexing out of bounds: the len is 3 but the index is 10
529 /// }
530 /// ```
531 #[unstable(feature = "type_info", issue = "146922")]
532 #[rustc_const_unstable(feature = "type_info", issue = "146922")]
533 #[rustc_comptime]
534 pub fn field(self, variant_index: usize, field_index: usize) -> FieldId {
535 FieldId {
536 frt_type_id: intrinsics::type_id_field_representing_type(
537 self,
538 variant_index,
539 field_index,
540 ),
541 }
542 }
543}
544
545/// Field representing type ID. Representing a field of a struct, tuple or enum variant.
546#[derive(Copy, PartialOrd, Ord, Hash)]
547#[derive_const(Clone, PartialEq, Eq)]
548#[unstable(feature = "type_info", issue = "146922")]
549pub struct FieldId {
550 frt_type_id: TypeId,
551}
552
553#[unstable(feature = "type_info", issue = "146922")]
554impl fmt::Debug for FieldId {
555 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
556 write!(f, "FieldId({:#034x})", self.frt_type_id.as_u128())
557 }
558}
559
560impl FieldId {
561 /// Returns the `TypeId` of the actual field type.
562 ///
563 /// ```
564 /// #![feature(type_info)]
565 /// use std::any::TypeId;
566 ///
567 /// struct Point {
568 /// x: u32,
569 /// y: u32,
570 /// }
571 /// assert_eq!(
572 /// const { TypeId::of::<Point>().field(0, 0).type_id() },
573 /// TypeId::of::<u32>()
574 /// );
575 /// ```
576 #[unstable(feature = "type_info", issue = "146922")]
577 #[rustc_const_unstable(feature = "type_info", issue = "146922")]
578 #[rustc_comptime]
579 pub fn type_id(self) -> TypeId {
580 intrinsics::field_representing_type_actual_type_id(self.frt_type_id)
581 }
582}