1use core::cell::{Cell, UnsafeCell};
2use core::fmt::{self, Write};
3use core::marker::PhantomData;
4use core::ops::Range;
5
6use musli::{Allocator, Context};
7
8use crate::buf::{self, BufString};
9use crate::fixed::FixedVec;
10
11use super::access::{Access, Shared};
12use super::rich_error::{RichError, Step};
13use super::ErrorMarker;
14
15type BufPair<'a, A> = (Range<usize>, BufString<<A as Allocator>::Buf<'a>>);
16
17pub struct StackContext<'a, const P: usize, A, M>
27where
28 A: ?Sized + Allocator,
29{
30 access: Access,
31 mark: Cell<usize>,
32 alloc: &'a A,
33 error: UnsafeCell<Option<BufPair<'a, A>>>,
34 path: UnsafeCell<FixedVec<Step<BufString<A::Buf<'a>>>, P>>,
35 path_cap: Cell<usize>,
36 include_type: bool,
37 _marker: PhantomData<M>,
38}
39
40impl<'a, A, M> StackContext<'a, 16, A, M>
41where
42 A: ?Sized + Allocator,
43{
44 pub fn new(alloc: &'a A) -> Self {
51 Self::new_with(alloc)
52 }
53}
54
55impl<'a, const P: usize, A, M> StackContext<'a, P, A, M>
56where
57 A: ?Sized + Allocator,
58{
59 pub fn new_with(alloc: &'a A) -> Self {
62 Self {
63 access: Access::new(),
64 mark: Cell::new(0),
65 alloc,
66 error: UnsafeCell::new(None),
67 path: UnsafeCell::new(FixedVec::new()),
68 path_cap: Cell::new(0),
69 include_type: false,
70 _marker: PhantomData,
71 }
72 }
73
74 pub fn include_type(&mut self) -> &mut Self {
77 self.include_type = true;
78 self
79 }
80
81 pub fn errors(&self) -> Errors<'_, impl fmt::Display + 'a> {
83 let access = self.access.shared();
84
85 Errors {
86 path: unsafe { &*self.path.get() },
87 error: unsafe { (*self.error.get()).as_ref() },
88 path_cap: self.path_cap.get(),
89 _access: access,
90 }
91 }
92
93 fn push_error(&self, range: Range<usize>, error: BufString<A::Buf<'a>>) {
95 unsafe {
97 self.error.get().replace(Some((range, error)));
98 }
99 }
100
101 fn push_path(&self, step: Step<BufString<A::Buf<'a>>>) {
103 let _access = self.access.exclusive();
104
105 let path = unsafe { &mut (*self.path.get()) };
107
108 if path.try_push(step).is_err() {
109 self.path_cap.set(self.path_cap.get() + 1);
110 }
111 }
112
113 fn pop_path(&self) {
115 let cap = self.path_cap.get();
116
117 if cap > 0 {
118 self.path_cap.set(cap - 1);
119 return;
120 }
121
122 let _access = self.access.exclusive();
123
124 unsafe {
126 (*self.path.get()).pop();
127 }
128 }
129
130 fn format_string<T>(&self, value: T) -> Option<BufString<A::Buf<'a>>>
131 where
132 T: fmt::Display,
133 {
134 let buf = self.alloc.alloc()?;
135 let mut string = BufString::new(buf);
136 write!(string, "{value}").ok()?;
137 Some(string)
138 }
139}
140
141impl<'a, const V: usize, A, M> Context for StackContext<'a, V, A, M>
142where
143 A: ?Sized + Allocator,
144{
145 type Mode = M;
146 type Error = ErrorMarker;
147 type Mark = usize;
148 type Buf<'this> = A::Buf<'this> where Self: 'this;
149 type BufString<'this> = BufString<A::Buf<'this>> where Self: 'this;
150
151 #[inline]
152 fn alloc(&self) -> Option<Self::Buf<'_>> {
153 self.alloc.alloc()
154 }
155
156 #[inline]
157 fn collect_string<T>(&self, value: &T) -> Result<Self::BufString<'_>, Self::Error>
158 where
159 T: ?Sized + fmt::Display,
160 {
161 buf::collect_string(self, value)
162 }
163
164 #[inline]
165 fn custom<T>(&self, message: T) -> Self::Error
166 where
167 T: 'static + Send + Sync + fmt::Display + fmt::Debug,
168 {
169 if let Some(string) = self.format_string(message) {
170 self.push_error(self.mark.get()..self.mark.get(), string);
171 }
172
173 ErrorMarker
174 }
175
176 #[inline]
177 fn message<T>(&self, message: T) -> Self::Error
178 where
179 T: fmt::Display,
180 {
181 if let Some(string) = self.format_string(message) {
182 self.push_error(self.mark.get()..self.mark.get(), string);
183 }
184
185 ErrorMarker
186 }
187
188 #[inline]
189 fn marked_message<T>(&self, mark: Self::Mark, message: T) -> Self::Error
190 where
191 T: fmt::Display,
192 {
193 if let Some(string) = self.format_string(message) {
194 self.push_error(mark..self.mark.get(), string);
195 }
196
197 ErrorMarker
198 }
199
200 #[inline]
201 fn marked_custom<T>(&self, mark: Self::Mark, message: T) -> Self::Error
202 where
203 T: 'static + Send + Sync + fmt::Display + fmt::Debug,
204 {
205 if let Some(string) = self.format_string(message) {
206 self.push_error(mark..self.mark.get(), string);
207 }
208
209 ErrorMarker
210 }
211
212 #[inline]
213 fn mark(&self) -> Self::Mark {
214 self.mark.get()
215 }
216
217 #[inline]
218 fn advance(&self, n: usize) {
219 self.mark.set(self.mark.get().wrapping_add(n));
220 }
221
222 #[inline]
223 fn enter_named_field<T>(&self, name: &'static str, _: &T)
224 where
225 T: ?Sized + fmt::Display,
226 {
227 self.push_path(Step::Named(name));
228 }
229
230 #[inline]
231 fn enter_unnamed_field<T>(&self, index: u32, _: &T)
232 where
233 T: ?Sized + fmt::Display,
234 {
235 self.push_path(Step::Unnamed(index));
236 }
237
238 #[inline]
239 fn leave_field(&self) {
240 self.pop_path();
241 }
242
243 #[inline]
244 fn enter_struct(&self, name: &'static str) {
245 if self.include_type {
246 self.push_path(Step::Struct(name));
247 }
248 }
249
250 #[inline]
251 fn leave_struct(&self) {
252 if self.include_type {
253 self.pop_path();
254 }
255 }
256
257 #[inline]
258 fn enter_enum(&self, name: &'static str) {
259 if self.include_type {
260 self.push_path(Step::Enum(name));
261 }
262 }
263
264 #[inline]
265 fn leave_enum(&self) {
266 if self.include_type {
267 self.pop_path();
268 }
269 }
270
271 #[inline]
272 fn enter_variant<T>(&self, name: &'static str, _: T) {
273 self.push_path(Step::Variant(name));
274 }
275
276 #[inline]
277 fn leave_variant(&self) {
278 self.pop_path();
279 }
280
281 #[inline]
282 fn enter_sequence_index(&self, index: usize) {
283 self.push_path(Step::Index(index));
284 }
285
286 #[inline]
287 fn leave_sequence_index(&self) {
288 self.pop_path();
289 }
290
291 #[inline]
292 fn enter_map_key<T>(&self, field: T)
293 where
294 T: fmt::Display,
295 {
296 if let Some(string) = self.format_string(field) {
297 self.push_path(Step::Key(string));
298 }
299 }
300
301 #[inline]
302 fn leave_map_key(&self) {
303 self.pop_path();
304 }
305}
306
307pub struct Errors<'a, S> {
309 path: &'a [Step<S>],
310 error: Option<&'a (Range<usize>, S)>,
311 path_cap: usize,
312 _access: Shared<'a>,
313}
314
315impl<'a, S> Iterator for Errors<'a, S> {
316 type Item = RichError<'a, S, S>;
317
318 #[inline]
319 fn next(&mut self) -> Option<Self::Item> {
320 let (range, error) = self.error.take()?;
321
322 Some(RichError::new(
323 self.path,
324 self.path_cap,
325 range.clone(),
326 error,
327 ))
328 }
329}