1//! Field Reflection
23use crate::fmt;
4use crate::hash::{Hash, Hasher};
5use crate::marker::PhantomData;
67/// Field Representing Type
8#[unstable(feature = "field_representing_type_raw", issue = "none")]
9#[lang = "field_representing_type"]
10#[fundamental]
11pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> {
12// We want this type to be invariant over `T`, because otherwise `field_of!(Struct<'short>,
13 // field)` is a subtype of `field_of!(Struct<'long>, field)`. This subtype relationship does not
14 // have an immediately obvious meaning and we want to prevent people from relying on it.
15_phantom: PhantomData<fn(T) -> T>,
16}
1718impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> fmt::Debug19for FieldRepresentingType<T, VARIANT, FIELD>
20{
21fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22enum Member {
23 Name(&'static str),
24 Index(u32),
25 }
26impl fmt::Displayfor Member {
27fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28match self {
29Self::Name(name) => fmt::Display::fmt(name, f),
30Self::Index(idx) => fmt::Display::fmt(idx, f),
31 }
32 }
33 }
34let (variant, field) = const {
35use crate::mem::type_info::{Type, TypeKind};
36match Type::of::<T>().kind {
37 TypeKind::Struct(struct_) => {
38 (None, Member::Name(struct_.fields[FIELDas usize].name))
39 }
40 TypeKind::Tuple(_) => (None, Member::Index(FIELD)),
41 TypeKind::Enum(enum_) => {
42let variant = &enum_.variants[VARIANTas usize];
43 (Some(variant.name), Member::Name(variant.fields[FIELDas usize].name))
44 }
45 TypeKind::Union(union) => (None, Member::Name(union.fields[FIELDas usize].name)),
46_ => crate::panicking::panic("internal error: entered unreachable code")unreachable!(),
47 }
48 };
49let type_name = const { crate::any::type_name::<T>() };
50match variant {
51Some(variant) => f.write_fmt(format_args!("field_of!({0}, {1}.{2})", type_name, variant,
field))write!(f, "field_of!({type_name}, {variant}.{field})"),
52None => f.write_fmt(format_args!("field_of!({0}, {1})", type_name, field))write!(f, "field_of!({type_name}, {field})"),
53 }
54// NOTE: if there are changes in the reflection work and the above no
55 // longer compiles, then the following debug impl could also work in
56 // the meantime:
57 // ```rust
58 // let type_name = const { type_name::<T>() };
59 // write!(f, "field_of!({type_name}, {VARIANT}.{FIELD})")
60 // ```
61}
62}
6364impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Copy65for FieldRepresentingType<T, VARIANT, FIELD>
66{
67}
6869impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Clone70for FieldRepresentingType<T, VARIANT, FIELD>
71{
72fn clone(&self) -> Self {
73*self74 }
75}
7677impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Default78for FieldRepresentingType<T, VARIANT, FIELD>
79{
80fn default() -> Self {
81Self { _phantom: PhantomData::default() }
82 }
83}
8485impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Hash86for FieldRepresentingType<T, VARIANT, FIELD>
87{
88fn hash<H: Hasher>(&self, state: &mut H) {
89self._phantom.hash(state);
90 }
91}
9293impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> PartialEq94for FieldRepresentingType<T, VARIANT, FIELD>
95{
96fn eq(&self, other: &Self) -> bool {
97self._phantom == other._phantom
98 }
99}
100101impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Eq102for FieldRepresentingType<T, VARIANT, FIELD>
103{
104}
105106impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> PartialOrd107for FieldRepresentingType<T, VARIANT, FIELD>
108{
109fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
110self._phantom.partial_cmp(&other._phantom)
111 }
112}
113114impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Ord115for FieldRepresentingType<T, VARIANT, FIELD>
116{
117fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
118self._phantom.cmp(&other._phantom)
119 }
120}
121122/// Expands to the field representing type of the given field.
123///
124/// The container type may be a tuple, `struct`, `union` or `enum`. In the case of an enum, the
125/// variant must also be specified. Only a single field is supported.
126#[unstable(feature = "field_projections", issue = "145383")]
127#[allow_internal_unstable(field_representing_type_raw, builtin_syntax)]
128#[diagnostic::on_unmatch_args(
129 note = "this macro expects a container type and a field path, like `field_of!(Type, field)` or `field_of!(Enum, Variant.field)`"
130)]
131// NOTE: when stabilizing this macro, we can never add new trait impls for `FieldRepresentingType`,
132// since it is `#[fundamental]` and thus could break users of this macro, since the compiler expands
133// it to `FieldRepresentingType<...>`. Thus stabilizing this requires careful thought about the
134// completeness of the trait impls for `FieldRepresentingType`.
135pub macro field_of($Container:ty, $($fields:expr)+ $(,)?) {
136 builtin # field_of($Container, $($fields)+)
137}
138139/// Type representing a field of a `struct`, `union`, `enum` variant or tuple.
140///
141/// # Safety
142///
143/// Given a valid value of type `Self::Base`, there exists a valid value of type `Self::Type` at
144/// byte offset `OFFSET`
145#[lang = "field"]
146#[unstable(feature = "field_projections", issue = "145383")]
147#[rustc_deny_explicit_impl]
148#[rustc_dyn_incompatible_trait]
149// NOTE: the compiler provides the impl of `Field` for `FieldRepresentingType` when it can guarantee
150// the safety requirements of this trait. It also has to manually add the correct trait bounds on
151// associated types (and the `Self` type). Thus any changes to the bounds here must be reflected in
152// the old and new trait solver:
153// - `fn assemble_candidates_for_field_trait` in
154// `compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs`, and
155// - `fn consider_builtin_field_candidate` in
156// `compiler/rustc_next_trait_solver/src/solve/trait_goals.rs`.
157pub unsafe trait Field: Send + Sync + Copy {
158/// The type of the base where this field exists in.
159#[lang = "field_base"]
160type Base;
161162/// The type of the field.
163#[lang = "field_type"]
164type Type;
165166/// The offset of the field in bytes.
167#[lang = "field_offset"]
168const OFFSET: usize = crate::intrinsics::field_offset::<Self>();
169}