musli_utils/context/
system_context.rs1use core::cell::{Cell, UnsafeCell};
2use core::fmt;
3use core::marker::PhantomData;
4use core::ops::Range;
5
6use alloc::string::{String, ToString};
7use alloc::vec::Vec;
8
9use musli::{Allocator, Context};
10
11use super::access::{self, Access};
12use super::rich_error::{RichError, Step};
13use super::ErrorMarker;
14use crate::buf::{self, BufString};
15
16type BufTriplet<E> = (Vec<Step<String>>, Range<usize>, E);
17
18pub struct SystemContext<A, M> {
20 access: Access,
21 mark: Cell<usize>,
22 alloc: A,
23 errors: UnsafeCell<Vec<BufTriplet<String>>>,
24 path: UnsafeCell<Vec<Step<String>>>,
25 include_type: bool,
26 _marker: PhantomData<M>,
27}
28
29impl<A, M> SystemContext<A, M> {
30 pub fn new(alloc: A) -> Self {
35 Self {
36 access: Access::new(),
37 mark: Cell::new(0),
38 alloc,
39 errors: UnsafeCell::new(Vec::new()),
40 path: UnsafeCell::new(Vec::new()),
41 include_type: false,
42 _marker: PhantomData,
43 }
44 }
45
46 pub fn include_type(&mut self) -> &mut Self {
49 self.include_type = true;
50 self
51 }
52
53 pub fn report(&self) -> Report<'_> {
55 Report {
56 errors: self.errors(),
57 }
58 }
59
60 pub fn errors(&self) -> Errors<'_> {
62 let access = self.access.shared();
63
64 Errors {
66 errors: unsafe { &*self.errors.get() },
67 index: 0,
68 _access: access,
69 }
70 }
71}
72
73impl<A, M> SystemContext<A, M>
74where
75 A: Allocator,
76{
77 fn push_error(&self, range: Range<usize>, message: String) {
78 let _access = self.access.exclusive();
79
80 let path = unsafe { (*self.path.get()).clone() };
82 let errors = unsafe { &mut (*self.errors.get()) };
83
84 errors.push((path, range, message));
85 }
86
87 fn push_path(&self, step: Step<String>) {
88 let _access = self.access.exclusive();
89
90 let path = unsafe { &mut (*self.path.get()) };
92
93 path.push(step);
94 }
95
96 fn pop_path(&self) {
97 let _access = self.access.exclusive();
98
99 let path = unsafe { &mut (*self.path.get()) };
101
102 path.pop();
103 }
104}
105
106impl<A, M> Context for SystemContext<A, M>
107where
108 A: Allocator,
109{
110 type Mode = M;
111 type Error = ErrorMarker;
112 type Mark = usize;
113 type Buf<'this> = A::Buf<'this> where Self: 'this;
114 type BufString<'this> = BufString<A::Buf<'this>> where Self: 'this;
115
116 #[inline]
117 fn clear(&self) {
118 self.mark.set(0);
119 let _access = self.access.exclusive();
120
121 unsafe {
123 (*self.errors.get()).clear();
124 (*self.path.get()).clear();
125 }
126 }
127
128 #[inline]
129 fn alloc(&self) -> Option<Self::Buf<'_>> {
130 self.alloc.alloc()
131 }
132
133 #[inline]
134 fn collect_string<T>(&self, value: &T) -> Result<Self::BufString<'_>, Self::Error>
135 where
136 T: ?Sized + fmt::Display,
137 {
138 buf::collect_string(self, value)
139 }
140
141 #[inline]
142 fn custom<T>(&self, message: T) -> Self::Error
143 where
144 T: 'static + Send + Sync + fmt::Display + fmt::Debug,
145 {
146 self.push_error(self.mark.get()..self.mark.get(), message.to_string());
147 ErrorMarker
148 }
149
150 #[inline]
151 fn message<T>(&self, message: T) -> Self::Error
152 where
153 T: fmt::Display,
154 {
155 self.push_error(self.mark.get()..self.mark.get(), message.to_string());
156 ErrorMarker
157 }
158
159 #[inline]
160 fn marked_message<T>(&self, mark: Self::Mark, message: T) -> Self::Error
161 where
162 T: fmt::Display,
163 {
164 self.push_error(mark..self.mark.get(), message.to_string());
165 ErrorMarker
166 }
167
168 #[inline]
169 fn marked_custom<T>(&self, mark: Self::Mark, message: T) -> Self::Error
170 where
171 T: 'static + Send + Sync + fmt::Display + fmt::Debug,
172 {
173 self.push_error(mark..self.mark.get(), message.to_string());
174 ErrorMarker
175 }
176
177 #[inline]
178 fn mark(&self) -> Self::Mark {
179 self.mark.get()
180 }
181
182 #[inline]
183 fn advance(&self, n: usize) {
184 self.mark.set(self.mark.get().wrapping_add(n));
185 }
186
187 #[inline]
188 fn enter_named_field<T>(&self, name: &'static str, _: &T)
189 where
190 T: ?Sized + fmt::Display,
191 {
192 self.push_path(Step::Named(name));
193 }
194
195 #[inline]
196 fn enter_unnamed_field<T>(&self, index: u32, _: &T)
197 where
198 T: ?Sized + fmt::Display,
199 {
200 self.push_path(Step::Unnamed(index));
201 }
202
203 #[inline]
204 fn leave_field(&self) {
205 self.pop_path();
206 }
207
208 #[inline]
209 fn enter_struct(&self, name: &'static str) {
210 if self.include_type {
211 self.push_path(Step::Struct(name));
212 }
213 }
214
215 #[inline]
216 fn leave_struct(&self) {
217 if self.include_type {
218 self.pop_path();
219 }
220 }
221
222 #[inline]
223 fn enter_enum(&self, name: &'static str) {
224 if self.include_type {
225 self.push_path(Step::Enum(name));
226 }
227 }
228
229 #[inline]
230 fn leave_enum(&self) {
231 if self.include_type {
232 self.pop_path();
233 }
234 }
235
236 #[inline]
237 fn enter_variant<T>(&self, name: &'static str, _: T) {
238 self.push_path(Step::Variant(name));
239 }
240
241 #[inline]
242 fn leave_variant(&self) {
243 self.pop_path();
244 }
245
246 #[inline]
247 fn enter_sequence_index(&self, index: usize) {
248 self.push_path(Step::Index(index));
249 }
250
251 #[inline]
252 fn leave_sequence_index(&self) {
253 self.pop_path();
254 }
255
256 #[inline]
257 fn enter_map_key<T>(&self, field: T)
258 where
259 T: fmt::Display,
260 {
261 self.push_path(Step::Key(field.to_string()));
262 }
263
264 #[inline]
265 fn leave_map_key(&self) {
266 self.pop_path();
267 }
268}
269
270pub struct Report<'a> {
272 errors: Errors<'a>,
273}
274
275impl fmt::Display for Report<'_> {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 for error in self.errors.clone() {
278 writeln!(f, "{error}")?;
279 }
280
281 Ok(())
282 }
283}
284
285#[derive(Clone)]
287pub struct Errors<'a> {
288 errors: &'a [BufTriplet<String>],
289 index: usize,
290 _access: access::Shared<'a>,
292}
293
294impl<'a> Iterator for Errors<'a> {
295 type Item = RichError<'a, String, String>;
296
297 fn next(&mut self) -> Option<Self::Item> {
298 let (path, range, error) = self.errors.get(self.index)?;
299 self.index += 1;
300 Some(RichError::new(path, 0, range.clone(), error))
301 }
302}