1use 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#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub enum Access<'a> {
16 Field(Cow<'a, str>),
18 FieldIndex(usize),
20 TupleIndex(usize),
22 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 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 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}