bevy_reflect/path/
access.rs

1//! Representation for individual element accesses within a path.
2
3use std::{borrow::Cow, fmt};
4
5use super::error::AccessErrorKind;
6use crate::{AccessError, Reflect, ReflectKind, ReflectMut, ReflectRef, VariantType};
7
8type InnerResult<T> = Result<T, AccessErrorKind>;
9
10/// A singular element access within a path.
11/// Multiple accesses can be combined into a [`ParsedPath`](super::ParsedPath).
12///
13/// Can be applied to a [`dyn Reflect`](Reflect) to get a reference to the targeted element.
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub enum Access<'a> {
16    /// A name-based field access on a struct.
17    Field(Cow<'a, str>),
18    /// A index-based field access on a struct.
19    FieldIndex(usize),
20    /// An index-based access on a tuple.
21    TupleIndex(usize),
22    /// An index-based access on a list.
23    ListIndex(usize),
24}
25
26impl fmt::Display for Access<'_> {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        match self {
29            Access::Field(field) => write!(f, ".{field}"),
30            Access::FieldIndex(index) => write!(f, "#{index}"),
31            Access::TupleIndex(index) => write!(f, ".{index}"),
32            Access::ListIndex(index) => write!(f, "[{index}]"),
33        }
34    }
35}
36
37impl<'a> Access<'a> {
38    /// Converts this into an "owned" value.
39    ///
40    /// If the [`Access`] is of variant [`Field`](Access::Field),
41    /// the field's [`Cow<str>`] will be converted to its owned
42    /// counterpart, which doesn't require a reference.
43    pub fn into_owned(self) -> Access<'static> {
44        match self {
45            Self::Field(value) => Access::Field(Cow::Owned(value.into_owned())),
46            Self::FieldIndex(value) => Access::FieldIndex(value),
47            Self::TupleIndex(value) => Access::TupleIndex(value),
48            Self::ListIndex(value) => Access::ListIndex(value),
49        }
50    }
51
52    pub(super) fn element<'r>(
53        &self,
54        base: &'r dyn Reflect,
55        offset: Option<usize>,
56    ) -> Result<&'r dyn Reflect, AccessError<'a>> {
57        self.element_inner(base)
58            .and_then(|opt| opt.ok_or(AccessErrorKind::MissingField(base.reflect_kind())))
59            .map_err(|err| err.with_access(self.clone(), offset))
60    }
61
62    fn element_inner<'r>(&self, base: &'r dyn Reflect) -> InnerResult<Option<&'r dyn Reflect>> {
63        use ReflectRef::*;
64
65        let invalid_variant =
66            |expected, actual| AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual };
67
68        match (self, base.reflect_ref()) {
69            (Self::Field(field), Struct(struct_ref)) => Ok(struct_ref.field(field.as_ref())),
70            (Self::Field(field), Enum(enum_ref)) => match enum_ref.variant_type() {
71                VariantType::Struct => Ok(enum_ref.field(field.as_ref())),
72                actual => Err(invalid_variant(VariantType::Struct, actual)),
73            },
74            (&Self::FieldIndex(index), Struct(struct_ref)) => Ok(struct_ref.field_at(index)),
75            (&Self::FieldIndex(index), Enum(enum_ref)) => match enum_ref.variant_type() {
76                VariantType::Struct => Ok(enum_ref.field_at(index)),
77                actual => Err(invalid_variant(VariantType::Struct, actual)),
78            },
79            (Self::Field(_) | Self::FieldIndex(_), actual) => {
80                Err(AccessErrorKind::IncompatibleTypes {
81                    expected: ReflectKind::Struct,
82                    actual: actual.into(),
83                })
84            }
85
86            (&Self::TupleIndex(index), TupleStruct(tuple)) => Ok(tuple.field(index)),
87            (&Self::TupleIndex(index), Tuple(tuple)) => Ok(tuple.field(index)),
88            (&Self::TupleIndex(index), Enum(enum_ref)) => match enum_ref.variant_type() {
89                VariantType::Tuple => Ok(enum_ref.field_at(index)),
90                actual => Err(invalid_variant(VariantType::Tuple, actual)),
91            },
92            (Self::TupleIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
93                expected: ReflectKind::Tuple,
94                actual: actual.into(),
95            }),
96
97            (&Self::ListIndex(index), List(list)) => Ok(list.get(index)),
98            (&Self::ListIndex(index), Array(list)) => Ok(list.get(index)),
99            (Self::ListIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
100                expected: ReflectKind::List,
101                actual: actual.into(),
102            }),
103        }
104    }
105
106    pub(super) fn element_mut<'r>(
107        &self,
108        base: &'r mut dyn Reflect,
109        offset: Option<usize>,
110    ) -> Result<&'r mut dyn Reflect, AccessError<'a>> {
111        let kind = base.reflect_kind();
112
113        self.element_inner_mut(base)
114            .and_then(|maybe| maybe.ok_or(AccessErrorKind::MissingField(kind)))
115            .map_err(|err| err.with_access(self.clone(), offset))
116    }
117
118    fn element_inner_mut<'r>(
119        &self,
120        base: &'r mut dyn Reflect,
121    ) -> InnerResult<Option<&'r mut dyn Reflect>> {
122        use ReflectMut::*;
123
124        let invalid_variant =
125            |expected, actual| AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual };
126
127        match (self, base.reflect_mut()) {
128            (Self::Field(field), Struct(struct_mut)) => Ok(struct_mut.field_mut(field.as_ref())),
129            (Self::Field(field), Enum(enum_mut)) => match enum_mut.variant_type() {
130                VariantType::Struct => Ok(enum_mut.field_mut(field.as_ref())),
131                actual => Err(invalid_variant(VariantType::Struct, actual)),
132            },
133            (&Self::FieldIndex(index), Struct(struct_mut)) => Ok(struct_mut.field_at_mut(index)),
134            (&Self::FieldIndex(index), Enum(enum_mut)) => match enum_mut.variant_type() {
135                VariantType::Struct => Ok(enum_mut.field_at_mut(index)),
136                actual => Err(invalid_variant(VariantType::Struct, actual)),
137            },
138            (Self::Field(_) | Self::FieldIndex(_), actual) => {
139                Err(AccessErrorKind::IncompatibleTypes {
140                    expected: ReflectKind::Struct,
141                    actual: actual.into(),
142                })
143            }
144
145            (&Self::TupleIndex(index), TupleStruct(tuple)) => Ok(tuple.field_mut(index)),
146            (&Self::TupleIndex(index), Tuple(tuple)) => Ok(tuple.field_mut(index)),
147            (&Self::TupleIndex(index), Enum(enum_mut)) => match enum_mut.variant_type() {
148                VariantType::Tuple => Ok(enum_mut.field_at_mut(index)),
149                actual => Err(invalid_variant(VariantType::Tuple, actual)),
150            },
151            (Self::TupleIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
152                expected: ReflectKind::Tuple,
153                actual: actual.into(),
154            }),
155
156            (&Self::ListIndex(index), List(list)) => Ok(list.get_mut(index)),
157            (&Self::ListIndex(index), Array(list)) => Ok(list.get_mut(index)),
158            (Self::ListIndex(_), actual) => Err(AccessErrorKind::IncompatibleTypes {
159                expected: ReflectKind::List,
160                actual: actual.into(),
161            }),
162        }
163    }
164
165    /// Returns a reference to this [`Access`]'s inner value as a [`&dyn Display`](fmt::Display).
166    pub fn display_value(&self) -> &dyn fmt::Display {
167        match self {
168            Self::Field(value) => value,
169            Self::FieldIndex(value) | Self::TupleIndex(value) | Self::ListIndex(value) => value,
170        }
171    }
172
173    pub(super) fn kind(&self) -> &'static str {
174        match self {
175            Self::Field(_) => "field",
176            Self::FieldIndex(_) => "field index",
177            Self::TupleIndex(_) | Self::ListIndex(_) => "index",
178        }
179    }
180}