musli_core/context.rs
1//! Things related to working with contexts.
2
3use core::error::Error;
4use core::fmt;
5use core::str;
6
7use crate::alloc::Allocator;
8use crate::de::{DecodeBytes, DecodeUnsized, DecodeUnsizedBytes};
9use crate::{Decode, Decoder};
10
11/// Provides ergonomic access to the serialization context.
12///
13/// This is used to among other things report diagnostics.
14pub trait Context {
15 /// Mode of the context.
16 type Mode: 'static;
17 /// Error produced by context.
18 type Error: 'static;
19 /// A mark during processing.
20 type Mark: Copy + Default;
21 /// The allocator associated with the context.
22 type Allocator: ?Sized + Allocator;
23 /// An allocated buffer containing a valid string.
24 type String<'this>: AsRef<str>
25 where
26 Self: 'this;
27
28 /// Clear the state of the context, allowing it to be re-used.
29 fn clear(&self);
30
31 /// Decode the given input using the associated mode.
32 #[inline]
33 fn decode<'de, T, D>(&self, decoder: D) -> Result<T, Self::Error>
34 where
35 T: Decode<'de, Self::Mode>,
36 D: Decoder<'de, Cx = Self, Mode = Self::Mode, Error = Self::Error>,
37 {
38 T::decode(self, decoder)
39 }
40
41 /// Decode the given unsized value using the associated mode.
42 #[inline]
43 fn decode_unsized<'de, T, D, F, O>(&self, decoder: D, f: F) -> Result<O, Self::Error>
44 where
45 T: ?Sized + DecodeUnsized<'de, Self::Mode>,
46 D: Decoder<'de, Cx = Self, Mode = Self::Mode, Error = Self::Error>,
47 F: FnOnce(&T) -> Result<O, D::Error>,
48 {
49 T::decode_unsized(self, decoder, f)
50 }
51
52 /// Decode the given input as bytes using the associated mode.
53 fn decode_bytes<'de, T, D>(&self, decoder: D) -> Result<T, Self::Error>
54 where
55 T: DecodeBytes<'de, Self::Mode>,
56 D: Decoder<'de, Cx = Self, Mode = Self::Mode, Error = Self::Error>,
57 {
58 T::decode_bytes(self, decoder)
59 }
60
61 /// Decode the given unsized value as bytes using the associated mode.
62 #[inline]
63 fn decode_unsized_bytes<'de, T, D, F, O>(&self, decoder: D, f: F) -> Result<O, Self::Error>
64 where
65 T: ?Sized + DecodeUnsizedBytes<'de, Self::Mode>,
66 D: Decoder<'de, Cx = Self, Mode = Self::Mode, Error = Self::Error>,
67 F: FnOnce(&T) -> Result<O, D::Error>,
68 {
69 T::decode_unsized_bytes(self, decoder, f)
70 }
71
72 /// Access the underlying allocator.
73 fn alloc(&self) -> &Self::Allocator;
74
75 /// Collect and allocate a string from a [`Display`] implementation.
76 ///
77 /// [`Display`]: fmt::Display
78 fn collect_string<T>(&self, value: &T) -> Result<Self::String<'_>, Self::Error>
79 where
80 T: ?Sized + fmt::Display;
81
82 /// Generate a map function which maps an error using the `custom` function.
83 #[inline]
84 fn map<T>(&self) -> impl FnOnce(T) -> Self::Error + '_
85 where
86 T: 'static + Send + Sync + Error,
87 {
88 move |error| self.custom(error)
89 }
90
91 /// Report a custom error, which is not encapsulated by the error type
92 /// expected by the context. This is essentially a type-erased way of
93 /// reporting error-like things out from the context.
94 fn custom<T>(&self, error: T) -> Self::Error
95 where
96 T: 'static + Send + Sync + Error;
97
98 /// Generate a map function which maps an error using the `message` function.
99 #[inline]
100 fn map_message<T>(&self) -> impl FnOnce(T) -> Self::Error + '_
101 where
102 T: fmt::Display,
103 {
104 move |error| self.message(error)
105 }
106
107 /// Report a message as an error.
108 ///
109 /// This is made available to format custom error messages in `no_std`
110 /// environments. The error message is to be collected by formatting `T`.
111 fn message<T>(&self, message: T) -> Self::Error
112 where
113 T: fmt::Display;
114
115 /// Report an error based on a mark.
116 ///
117 /// A mark is generated using [Context::mark] and indicates a prior state.
118 #[allow(unused_variables)]
119 #[inline(always)]
120 fn marked_message<T>(&self, mark: Self::Mark, message: T) -> Self::Error
121 where
122 T: fmt::Display,
123 {
124 self.message(message)
125 }
126
127 /// Report an error based on a mark.
128 ///
129 /// A mark is generated using [Context::mark] and indicates a prior state.
130 #[allow(unused_variables)]
131 #[inline(always)]
132 fn marked_custom<T>(&self, mark: Self::Mark, message: T) -> Self::Error
133 where
134 T: 'static + Send + Sync + Error,
135 {
136 self.custom(message)
137 }
138
139 /// Advance the context by `n` bytes of input.
140 ///
141 /// This is typically used to move the mark forward as produced by
142 /// [Context::mark].
143 #[allow(unused_variables)]
144 #[inline(always)]
145 fn advance(&self, n: usize) {}
146
147 /// Return a mark which acts as a checkpoint at the current encoding state.
148 ///
149 /// The context is in a privileged state in that it sees everything, so a
150 /// mark can be quite useful for determining the context of an error.
151 ///
152 /// This typically indicates a byte offset, and is used by
153 /// [`marked_message`][Context::marked_message] to report a spanned error.
154 #[inline(always)]
155 fn mark(&self) -> Self::Mark {
156 Self::Mark::default()
157 }
158
159 /// Report that an invalid variant tag was encountered.
160 #[inline(always)]
161 fn invalid_variant_tag<T>(&self, _: &'static str, tag: &T) -> Self::Error
162 where
163 T: ?Sized + fmt::Debug,
164 {
165 self.message(format_args!("Invalid variant tag {tag:?}"))
166 }
167
168 /// The value for the given tag could not be collected.
169 #[inline(always)]
170 fn expected_tag<T>(&self, _: &'static str, tag: &T) -> Self::Error
171 where
172 T: ?Sized + fmt::Debug,
173 {
174 self.message(format_args!("Expected tag: {tag:?}"))
175 }
176
177 /// Trying to decode an uninhabitable type.
178 #[inline(always)]
179 fn uninhabitable(&self, _: &'static str) -> Self::Error {
180 self.message(format_args!("Cannot decode uninhabitable types"))
181 }
182
183 /// Encountered an unsupported field tag.
184 #[inline(always)]
185 fn invalid_field_tag<T>(&self, _: &'static str, tag: &T) -> Self::Error
186 where
187 T: ?Sized + fmt::Debug,
188 {
189 self.message(format_args!("Invalid field tag {tag:?}"))
190 }
191
192 /// Expected another field to decode.
193 #[inline(always)]
194 fn expected_field_adjacent<T, C>(&self, _: &'static str, tag: &T, content: &C) -> Self::Error
195 where
196 T: ?Sized + fmt::Debug,
197 C: ?Sized + fmt::Debug,
198 {
199 self.message(format_args!(
200 "Expected adjacent field {tag:?} or {content:?}"
201 ))
202 }
203
204 /// Missing adjacent tag when decoding.
205 #[inline(always)]
206 fn missing_adjacent_tag<T>(&self, _: &'static str, tag: &T) -> Self::Error
207 where
208 T: ?Sized + fmt::Debug,
209 {
210 self.message(format_args!("Missing adjacent tag {tag:?}"))
211 }
212
213 /// Encountered an unsupported field tag.
214 #[inline(always)]
215 fn invalid_field_string_tag(&self, _: &'static str, field: Self::String<'_>) -> Self::Error {
216 let field = field.as_ref();
217 self.message(format_args!("Invalid field tag `{field}`"))
218 }
219
220 /// Missing variant field required to decode.
221 #[allow(unused_variables)]
222 #[inline(always)]
223 fn missing_variant_field<T>(&self, name: &'static str, tag: &T) -> Self::Error
224 where
225 T: ?Sized + fmt::Debug,
226 {
227 self.message(format_args!("Missing variant field: {tag:?}"))
228 }
229
230 /// Indicate that a variant tag could not be determined.
231 #[allow(unused_variables)]
232 #[inline(always)]
233 fn missing_variant_tag(&self, name: &'static str) -> Self::Error {
234 self.message(format_args!("Missing variant tag"))
235 }
236
237 /// Encountered an unsupported variant field.
238 #[allow(unused_variables)]
239 #[inline(always)]
240 fn invalid_variant_field_tag<V, T>(
241 &self,
242 name: &'static str,
243 variant: &V,
244 tag: &T,
245 ) -> Self::Error
246 where
247 V: ?Sized + fmt::Debug,
248 T: ?Sized + fmt::Debug,
249 {
250 self.message(format_args!(
251 "Invalid variant field tag `{tag:?}` for variant `{variant:?}`",
252 ))
253 }
254
255 /// Missing variant field required to decode.
256 #[allow(unused_variables)]
257 #[inline(always)]
258 fn alloc_failed(&self) -> Self::Error {
259 self.message("Failed to allocate")
260 }
261
262 /// Indicate that we've entered a struct with the given `name`.
263 ///
264 /// The `name` variable corresponds to the identifiers of the struct.
265 ///
266 /// This will be matched with a corresponding call to [`leave_struct`].
267 ///
268 /// [`leave_struct`]: Context::leave_struct
269 #[allow(unused_variables)]
270 #[inline(always)]
271 fn enter_struct(&self, name: &'static str) {}
272
273 /// Trace that we've left the last struct that was entered.
274 #[inline(always)]
275 fn leave_struct(&self) {}
276
277 /// Indicate that we've entered an enum with the given `name`.
278 ///
279 /// The `name` variable corresponds to the identifiers of the enum.
280 ///
281 /// This will be matched with a corresponding call to [`leave_enum`].
282 ///
283 /// [`leave_enum`]: Context::leave_enum
284 #[allow(unused_variables)]
285 #[inline(always)]
286 fn enter_enum(&self, name: &'static str) {}
287
288 /// Trace that we've left the last enum that was entered.
289 #[inline(always)]
290 fn leave_enum(&self) {}
291
292 /// Trace that we've entered the given named field.
293 ///
294 /// A named field is part of a regular struct, where the literal field name
295 /// is the `name` argument below, and the musli tag being used for the field
296 /// is the second argument.
297 ///
298 /// This will be matched with a corresponding call to [`leave_field`].
299 ///
300 /// Here `name` is `"field"` and `tag` is `"string"`.
301 ///
302 /// ```
303 /// use musli::{Decode, Encode};
304 ///
305 /// #[derive(Decode, Encode)]
306 /// #[musli(name_all = "name")]
307 /// struct Struct {
308 /// #[musli(name = "string")]
309 /// field: String,
310 /// }
311 /// ```
312 ///
313 /// [`leave_field`]: Context::leave_field
314 #[allow(unused_variables)]
315 #[inline(always)]
316 fn enter_named_field<T>(&self, name: &'static str, tag: &T)
317 where
318 T: ?Sized + fmt::Display,
319 {
320 }
321
322 /// Trace that we've entered the given unnamed field.
323 ///
324 /// An unnamed field is part of a tuple struct, where the field index is the
325 /// `index` argument below, and the musli tag being used for the field is
326 /// the second argument.
327 ///
328 /// This will be matched with a corresponding call to [`leave_field`].
329 ///
330 /// Here `index` is `0` and `name` is `"string"`.
331 ///
332 /// ```
333 /// use musli::{Decode, Encode};
334 ///
335 /// #[derive(Decode, Encode)]
336 /// #[musli(name_all = "name")]
337 /// struct Struct(#[musli(name = "string")] String);
338 /// ```
339 ///
340 /// [`leave_field`]: Context::leave_field
341 #[allow(unused_variables)]
342 #[inline(always)]
343 fn enter_unnamed_field<T>(&self, index: u32, name: &T)
344 where
345 T: ?Sized + fmt::Display,
346 {
347 }
348
349 /// Trace that we've left the last field that was entered.
350 ///
351 /// The `marker` argument will be the same as the one returned from
352 /// [`enter_named_field`] or [`enter_unnamed_field`].
353 ///
354 /// [`enter_named_field`]: Context::enter_named_field
355 /// [`enter_unnamed_field`]: Context::enter_unnamed_field
356 #[allow(unused_variables)]
357 #[inline(always)]
358 fn leave_field(&self) {}
359
360 /// Trace that we've entered the given variant in an enum.
361 ///
362 /// A named variant is part of an enum, where the literal variant name is
363 /// the `name` argument below, and the musli tag being used to decode the
364 /// variant is the second argument.
365 ///
366 /// This will be matched with a corresponding call to
367 /// [`leave_variant`] with the same marker provided as an argument as
368 /// the one returned here.
369 ///
370 /// Here `name` is `"field"` and `tag` is `"string"`.
371 ///
372 /// ```
373 /// use musli::{Decode, Encode};
374 ///
375 /// #[derive(Decode, Encode)]
376 /// #[musli(name_all = "name")]
377 /// struct Struct {
378 /// #[musli(name = "string")]
379 /// field: String,
380 /// }
381 /// ```
382 ///
383 /// [`leave_variant`]: Context::leave_variant
384 #[allow(unused_variables)]
385 #[inline(always)]
386 fn enter_variant<T>(&self, name: &'static str, tag: T)
387 where
388 T: fmt::Display,
389 {
390 }
391
392 /// Trace that we've left the last variant that was entered.
393 ///
394 /// The `marker` argument will be the same as the one returned from
395 /// [`enter_variant`].
396 ///
397 /// [`enter_variant`]: Context::enter_variant
398 #[allow(unused_variables)]
399 #[inline(always)]
400 fn leave_variant(&self) {}
401
402 /// Trace a that a map key has been entered.
403 #[allow(unused_variables)]
404 #[inline(always)]
405 fn enter_map_key<T>(&self, field: T)
406 where
407 T: fmt::Display,
408 {
409 }
410
411 /// Trace that we've left the last map field that was entered.
412 ///
413 /// The `marker` argument will be the same as the one returned from
414 /// [`enter_map_key`].
415 ///
416 /// [`enter_map_key`]: Context::enter_map_key
417 #[allow(unused_variables)]
418 #[inline(always)]
419 fn leave_map_key(&self) {}
420
421 /// Trace a sequence field.
422 #[allow(unused_variables)]
423 #[inline(always)]
424 fn enter_sequence_index(&self, index: usize) {}
425
426 /// Trace that we've left the last sequence index that was entered.
427 ///
428 /// The `marker` argument will be the same as the one returned from
429 /// [`enter_sequence_index`].
430 ///
431 /// [`enter_sequence_index`]: Context::enter_sequence_index
432 #[allow(unused_variables)]
433 #[inline(always)]
434 fn leave_sequence_index(&self) {}
435}