bevy_reflect/path/error.rs
1use core::fmt;
2
3use super::Access;
4use crate::{ReflectKind, VariantType};
5
6/// The kind of [`AccessError`], along with some kind-specific information.
7#[derive(Debug, PartialEq, Eq, Clone)]
8pub enum AccessErrorKind {
9 /// An error that occurs when a certain type doesn't
10 /// contain the value referenced by the [`Access`].
11 MissingField(ReflectKind),
12
13 /// An error that occurs when using an [`Access`] on the wrong type.
14 /// (i.e. a [`ListIndex`](Access::ListIndex) on a struct, or a [`TupleIndex`](Access::TupleIndex) on a list)
15 IncompatibleTypes {
16 /// The [`ReflectKind`] that was expected based on the [`Access`].
17 expected: ReflectKind,
18 /// The actual [`ReflectKind`] that was found.
19 actual: ReflectKind,
20 },
21
22 /// An error that occurs when using an [`Access`] on the wrong enum variant.
23 /// (i.e. a [`ListIndex`](Access::ListIndex) on a struct variant, or a [`TupleIndex`](Access::TupleIndex) on a unit variant)
24 IncompatibleEnumVariantTypes {
25 /// The [`VariantType`] that was expected based on the [`Access`].
26 expected: VariantType,
27 /// The actual [`VariantType`] that was found.
28 actual: VariantType,
29 },
30}
31
32impl AccessErrorKind {
33 pub(super) fn with_access(self, access: Access, offset: Option<usize>) -> AccessError {
34 AccessError {
35 kind: self,
36 access,
37 offset,
38 }
39 }
40}
41
42/// An error originating from an [`Access`] of an element within a type.
43///
44/// Use the `Display` impl of this type to get information on the error.
45///
46/// Some sample messages:
47///
48/// ```text
49/// Error accessing element with `.alpha` access (offset 14): The struct accessed doesn't have an "alpha" field
50/// Error accessing element with '[0]' access: Expected index access to access a list, found a struct instead.
51/// Error accessing element with '.4' access: Expected variant index access to access a Tuple variant, found a Unit variant instead.
52/// ```
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub struct AccessError<'a> {
55 pub(super) kind: AccessErrorKind,
56 pub(super) access: Access<'a>,
57 pub(super) offset: Option<usize>,
58}
59
60impl<'a> AccessError<'a> {
61 /// Returns the kind of [`AccessError`].
62 pub const fn kind(&self) -> &AccessErrorKind {
63 &self.kind
64 }
65
66 /// The returns the [`Access`] that this [`AccessError`] occurred in.
67 pub const fn access(&self) -> &Access<'_> {
68 &self.access
69 }
70
71 /// If the [`Access`] was created with a parser or an offset was manually provided,
72 /// returns the offset of the [`Access`] in its path string.
73 pub const fn offset(&self) -> Option<&usize> {
74 self.offset.as_ref()
75 }
76}
77
78impl fmt::Display for AccessError<'_> {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 let AccessError {
81 kind,
82 access,
83 offset,
84 } = self;
85
86 write!(f, "Error accessing element with `{access}` access")?;
87 if let Some(offset) = offset {
88 write!(f, "(offset {offset})")?;
89 }
90 write!(f, ": ")?;
91
92 match kind {
93 AccessErrorKind::MissingField(type_accessed) => {
94 match access {
95 Access::Field(field) => write!(
96 f,
97 "The {type_accessed} accessed doesn't have {} `{}` field",
98 if let Some("a" | "e" | "i" | "o" | "u") = field.get(0..1) {
99 "an"
100 } else {
101 "a"
102 },
103 access.display_value()
104 ),
105 Access::FieldIndex(_) => write!(
106 f,
107 "The {type_accessed} accessed doesn't have field index `{}`",
108 access.display_value(),
109 ),
110 Access::TupleIndex(_) | Access::ListIndex(_) => write!(
111 f,
112 "The {type_accessed} accessed doesn't have index `{}`",
113 access.display_value()
114 )
115 }
116 }
117 AccessErrorKind::IncompatibleTypes { expected, actual } => write!(
118 f,
119 "Expected {} access to access a {expected}, found a {actual} instead.",
120 access.kind()
121 ),
122 AccessErrorKind::IncompatibleEnumVariantTypes { expected, actual } => write!(
123 f,
124 "Expected variant {} access to access a {expected:?} variant, found a {actual:?} variant instead.",
125 access.kind()
126 ),
127 }
128 }
129}
130
131impl core::error::Error for AccessError<'_> {}