facet_path/access.rs
1//! Error types for path-based value access.
2
3use facet_core::Shape;
4
5use crate::PathStep;
6
7/// Error returned when navigating a value using a [`Path`](crate::Path).
8///
9/// Each variant captures enough context for a caller to produce
10/// a meaningful diagnostic without re-walking the path.
11#[derive(Debug, Clone)]
12#[non_exhaustive]
13pub enum PathAccessError {
14 /// The root shape of the path doesn't match the value being navigated.
15 RootShapeMismatch {
16 /// The shape recorded in the path.
17 expected: &'static Shape,
18 /// The shape of the value we tried to navigate.
19 actual: &'static Shape,
20 },
21
22 /// The step kind doesn't apply to the current shape.
23 ///
24 /// For example, `PathStep::Field` on a scalar, or `PathStep::Index` on a struct.
25 WrongStepKind {
26 /// The step that didn't apply.
27 step: PathStep,
28 /// Index of this step in the path (0-based).
29 step_index: usize,
30 /// The shape at the point where the step was attempted.
31 shape: &'static Shape,
32 },
33
34 /// A field or list index is out of bounds.
35 IndexOutOfBounds {
36 /// The step that contained the out-of-bounds index.
37 step: PathStep,
38 /// Index of this step in the path (0-based).
39 step_index: usize,
40 /// The shape of the container.
41 shape: &'static Shape,
42 /// The index that was requested.
43 index: usize,
44 /// The number of available items (fields, elements, variants, etc.).
45 bound: usize,
46 },
47
48 /// The path says we should be at variant X, but the live value is variant Y.
49 VariantMismatch {
50 /// Index of this step in the path (0-based).
51 step_index: usize,
52 /// The enum shape.
53 shape: &'static Shape,
54 /// The variant index the path expected.
55 expected_variant: usize,
56 /// The variant index found at runtime.
57 actual_variant: usize,
58 },
59
60 /// A `Deref`, `Inner`, or `Proxy` step has no target.
61 ///
62 /// This can happen when a smart pointer has no `borrow_fn`,
63 /// or the shape has no `inner`, or no proxy definition.
64 MissingTarget {
65 /// The step that required a target.
66 step: PathStep,
67 /// Index of this step in the path (0-based).
68 step_index: usize,
69 /// The shape that was expected to provide a target.
70 shape: &'static Shape,
71 },
72
73 /// An `OptionSome` step was encountered but the value is `None`.
74 OptionIsNone {
75 /// Index of this step in the path (0-based).
76 step_index: usize,
77 /// The option shape.
78 shape: &'static Shape,
79 },
80}
81
82impl core::fmt::Display for PathAccessError {
83 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84 match self {
85 PathAccessError::RootShapeMismatch { expected, actual } => {
86 write!(
87 f,
88 "root shape mismatch: path expects {expected}, value is {actual}"
89 )
90 }
91 PathAccessError::WrongStepKind {
92 step,
93 step_index,
94 shape,
95 } => {
96 write!(
97 f,
98 "step {step_index} ({step:?}) does not apply to shape {shape}"
99 )
100 }
101 PathAccessError::IndexOutOfBounds {
102 step,
103 step_index,
104 shape,
105 index,
106 bound,
107 } => {
108 write!(
109 f,
110 "step {step_index} ({step:?}): index {index} out of bounds for {shape} (has {bound})"
111 )
112 }
113 PathAccessError::VariantMismatch {
114 step_index,
115 shape,
116 expected_variant,
117 actual_variant,
118 } => {
119 write!(
120 f,
121 "step {step_index}: variant mismatch on {shape}: path expects variant {expected_variant}, value has variant {actual_variant}"
122 )
123 }
124 PathAccessError::MissingTarget {
125 step,
126 step_index,
127 shape,
128 } => {
129 write!(
130 f,
131 "step {step_index} ({step:?}): no target available for {shape}"
132 )
133 }
134 PathAccessError::OptionIsNone { step_index, shape } => {
135 write!(
136 f,
137 "step {step_index}: option {shape} is None, cannot navigate into Some"
138 )
139 }
140 }
141 }
142}
143
144impl core::error::Error for PathAccessError {}