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}