facet_reflect/
error.rs

1use facet_core::{Characteristic, EnumType, FieldError, Shape, TryFromError};
2
3/// A kind-only version of Tracker
4#[allow(missing_docs)]
5#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
6#[non_exhaustive]
7pub enum TrackerKind {
8    Scalar,
9    Array,
10    Struct,
11    SmartPointer,
12    SmartPointerSlice,
13    Enum,
14    List,
15    Map,
16    Set,
17    Option,
18    Result,
19    DynamicValue,
20}
21
22/// Errors that can occur when reflecting on types.
23#[derive(Clone)]
24pub enum ReflectError {
25    /// Tried to set an enum to a variant that does not exist
26    NoSuchVariant {
27        /// The enum definition containing all known variants.
28        enum_type: EnumType,
29    },
30
31    /// Tried to get the wrong shape out of a value — e.g. we were manipulating
32    /// a `String`, but `.get()` was called with a `u64` or something.
33    WrongShape {
34        /// The expected shape of the value.
35        expected: &'static Shape,
36        /// The actual shape of the value.
37        actual: &'static Shape,
38    },
39
40    /// Attempted to perform an operation that expected a struct or something
41    WasNotA {
42        /// The name of the expected type.
43        expected: &'static str,
44
45        /// The type we got instead
46        actual: &'static Shape,
47    },
48
49    /// A field was not initialized during build
50    UninitializedField {
51        /// The shape containing the field
52        shape: &'static Shape,
53        /// The name of the field that wasn't initialized
54        field_name: &'static str,
55    },
56
57    /// A field in an enum variant was not initialized during build
58    UninitializedEnumField {
59        /// The enum shape
60        shape: &'static Shape,
61        /// The name of the field that wasn't initialized
62        field_name: &'static str,
63        /// The name of the variant containing the field
64        variant_name: &'static str,
65    },
66
67    /// A scalar value was not initialized during build
68    UninitializedValue {
69        /// The scalar shape
70        shape: &'static Shape,
71    },
72
73    /// An invariant of the reflection system was violated.
74    InvariantViolation {
75        /// The invariant that was violated.
76        invariant: &'static str,
77    },
78
79    /// Attempted to set a value to its default, but the value doesn't implement `Default`.
80    MissingCharacteristic {
81        /// The shape of the value that doesn't implement `Default`.
82        shape: &'static Shape,
83        /// The characteristic that is missing.
84        characteristic: Characteristic,
85    },
86
87    /// An operation failed for a given shape
88    OperationFailed {
89        /// The shape of the value for which the operation failed.
90        shape: &'static Shape,
91        /// The name of the operation that failed.
92        operation: &'static str,
93    },
94
95    /// An error occurred when attempting to access or modify a field.
96    FieldError {
97        /// The shape of the value containing the field.
98        shape: &'static Shape,
99        /// The specific error that occurred with the field.
100        field_error: FieldError,
101    },
102
103    /// Indicates that we try to access a field on an `Arc<T>`, for example, and the field might exist
104    /// on the T, but you need to do begin_smart_ptr first when using the WIP API.
105    MissingPushPointee {
106        /// The smart pointer (`Arc<T>`, `Box<T>` etc.) shape on which field was caleld
107        shape: &'static Shape,
108    },
109
110    /// An unknown error occurred.
111    Unknown,
112
113    /// An error occured while putting
114    TryFromError {
115        /// The shape of the value being converted from.
116        src_shape: &'static Shape,
117
118        /// The shape of the value being converted to.
119        dst_shape: &'static Shape,
120
121        /// The inner error
122        inner: TryFromError,
123    },
124
125    /// A shape has a `default` attribute, but no implementation of the `Default` trait.
126    DefaultAttrButNoDefaultImpl {
127        /// The shape of the value that has a `default` attribute but no default implementation.
128        shape: &'static Shape,
129    },
130
131    /// The type is unsized
132    Unsized {
133        /// The shape for the type that is unsized
134        shape: &'static Shape,
135        /// The operation we were trying to perform
136        operation: &'static str,
137    },
138
139    /// Array not fully initialized during build
140    ArrayNotFullyInitialized {
141        /// The shape of the array
142        shape: &'static Shape,
143        /// The number of elements pushed
144        pushed_count: usize,
145        /// The expected array size
146        expected_size: usize,
147    },
148
149    /// Array index out of bounds
150    ArrayIndexOutOfBounds {
151        /// The shape of the array
152        shape: &'static Shape,
153        /// The index that was out of bounds
154        index: usize,
155        /// The array size
156        size: usize,
157    },
158
159    /// Invalid operation for the current state
160    InvalidOperation {
161        /// The operation that was attempted
162        operation: &'static str,
163        /// The reason why it failed
164        reason: &'static str,
165    },
166
167    /// Unexpected tracker state when performing a reflection operation
168    UnexpectedTracker {
169        /// User-friendly message including operation that was being
170        /// attempted
171        message: &'static str,
172
173        /// The current tracker set for this frame
174        current_tracker: TrackerKind,
175    },
176
177    /// No active frame in Partial
178    NoActiveFrame,
179
180    #[cfg(feature = "alloc")]
181    /// Error during custom deserialization
182    CustomDeserializationError {
183        /// Error message provided by the deserialize_with method
184        message: alloc::string::String,
185        /// Shape that was passed to deserialize_with
186        src_shape: &'static Shape,
187        /// the shape of the target type
188        dst_shape: &'static Shape,
189    },
190
191    #[cfg(feature = "alloc")]
192    /// Error during custom serialization
193    CustomSerializationError {
194        /// Error message provided by the serialize_with method
195        message: alloc::string::String,
196        /// Shape that was passed to serialize_with
197        src_shape: &'static Shape,
198        /// the shape of the target
199        dst_shape: &'static Shape,
200    },
201}
202
203impl core::fmt::Display for ReflectError {
204    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
205        match self {
206            ReflectError::NoSuchVariant { enum_type } => {
207                write!(f, "No such variant in enum. Known variants: ")?;
208                for v in enum_type.variants {
209                    write!(f, ", {}", v.name)?;
210                }
211                write!(f, ", that's it.")
212            }
213            ReflectError::WrongShape { expected, actual } => {
214                write!(f, "Wrong shape: expected {expected}, but got {actual}")
215            }
216            ReflectError::WasNotA { expected, actual } => {
217                write!(f, "Wrong shape: expected {expected}, but got {actual}")
218            }
219            ReflectError::UninitializedField { shape, field_name } => {
220                write!(
221                    f,
222                    "Field '{shape}::{field_name}' was not initialized. \
223                    If you need to leave fields partially initialized and come back later, \
224                    use deferred mode (begin_deferred/finish_deferred)"
225                )
226            }
227            ReflectError::UninitializedEnumField {
228                shape,
229                field_name,
230                variant_name,
231            } => {
232                write!(
233                    f,
234                    "Field '{shape}::{field_name}' in variant '{variant_name}' was not initialized. \
235                    If you need to leave fields partially initialized and come back later, \
236                    use deferred mode (begin_deferred/finish_deferred)"
237                )
238            }
239            ReflectError::UninitializedValue { shape } => {
240                write!(
241                    f,
242                    "Value '{shape}' was not initialized. \
243                    If you need to leave values partially initialized and come back later, \
244                    use deferred mode (begin_deferred/finish_deferred)"
245                )
246            }
247            ReflectError::InvariantViolation { invariant } => {
248                write!(f, "Invariant violation: {invariant}")
249            }
250            ReflectError::MissingCharacteristic {
251                shape,
252                characteristic,
253            } => write!(
254                f,
255                "{shape} does not implement characteristic {characteristic:?}",
256            ),
257            ReflectError::OperationFailed { shape, operation } => {
258                write!(f, "Operation failed on shape {shape}: {operation}")
259            }
260            ReflectError::FieldError { shape, field_error } => {
261                write!(f, "Field error for shape {shape}: {field_error}")
262            }
263            ReflectError::MissingPushPointee { shape } => {
264                write!(
265                    f,
266                    "Tried to access a field on smart pointer '{shape}', but you need to call .begin_smart_ptr() first to work with the value it points to (and pop it with .pop() later)"
267                )
268            }
269            ReflectError::Unknown => write!(f, "Unknown error"),
270            ReflectError::TryFromError {
271                src_shape,
272                dst_shape,
273                inner,
274            } => {
275                write!(
276                    f,
277                    "While trying to put {src_shape} into a {dst_shape}: {inner}"
278                )
279            }
280            ReflectError::DefaultAttrButNoDefaultImpl { shape } => write!(
281                f,
282                "Shape '{shape}' has a `default` attribute but no default implementation"
283            ),
284            ReflectError::Unsized { shape, operation } => write!(
285                f,
286                "Shape '{shape}' is unsized, can't perform operation {operation}"
287            ),
288            ReflectError::ArrayNotFullyInitialized {
289                shape,
290                pushed_count,
291                expected_size,
292            } => {
293                write!(
294                    f,
295                    "Array '{shape}' not fully initialized: expected {expected_size} elements, but got {pushed_count}"
296                )
297            }
298            ReflectError::ArrayIndexOutOfBounds { shape, index, size } => {
299                write!(
300                    f,
301                    "Array index {index} out of bounds for '{shape}' (array length is {size})"
302                )
303            }
304            ReflectError::InvalidOperation { operation, reason } => {
305                write!(f, "Invalid operation '{operation}': {reason}")
306            }
307            ReflectError::UnexpectedTracker {
308                message,
309                current_tracker,
310            } => {
311                write!(f, "{message}: current tracker is {current_tracker:?}")
312            }
313            ReflectError::NoActiveFrame => {
314                write!(f, "No active frame in Partial")
315            }
316            #[cfg(feature = "alloc")]
317            ReflectError::CustomDeserializationError {
318                message,
319                src_shape,
320                dst_shape,
321            } => {
322                write!(
323                    f,
324                    "Custom deserialization of shape '{src_shape}' into '{dst_shape}' failed: {message}"
325                )
326            }
327            #[cfg(feature = "alloc")]
328            ReflectError::CustomSerializationError {
329                message,
330                src_shape,
331                dst_shape,
332            } => {
333                write!(
334                    f,
335                    "Custom serialization of shape '{src_shape}' into '{dst_shape}' failed: {message}"
336                )
337            }
338        }
339    }
340}
341
342impl core::fmt::Debug for ReflectError {
343    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
344        // Use Display implementation for more readable output
345        write!(f, "ReflectError({self})")
346    }
347}
348
349impl core::error::Error for ReflectError {}