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