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::Allocator;
8
9/// Provides ergonomic access to the serialization context.
10///
11/// This is used to among other things report diagnostics.
12pub trait Context: Copy {
13    /// Error produced by the context.
14    type Error;
15    /// A mark during processing.
16    type Mark;
17    /// The allocator associated with the context.
18    type Allocator: Allocator;
19
20    /// Clear the state of the context, allowing it to be re-used.
21    fn clear(self);
22
23    /// Advance the context by `n` bytes of input.
24    ///
25    /// This is typically used to move the mark forward as produced by
26    /// [Context::mark].
27    fn advance(self, n: usize);
28
29    /// Return a mark which acts as a checkpoint at the current encoding state.
30    ///
31    /// The context is in a privileged state in that it sees everything, so a
32    /// mark can be quite useful for determining the context of an error.
33    ///
34    /// This typically indicates a byte offset, and is used by
35    /// [`marked_message`][Context::marked_message] to report a spanned error.
36    fn mark(self) -> Self::Mark;
37
38    /// Access the underlying allocator.
39    fn alloc(self) -> Self::Allocator;
40
41    /// Generate a map function which maps an error using the `custom` function.
42    #[inline]
43    fn map<E>(self) -> impl FnOnce(E) -> Self::Error
44    where
45        E: 'static + Send + Sync + Error,
46    {
47        move |error| self.custom(error)
48    }
49
50    /// Report a custom error, which is not encapsulated by the error type
51    /// expected by the context. This is essentially a type-erased way of
52    /// reporting error-like things out from the context.
53    fn custom<E>(self, error: E) -> Self::Error
54    where
55        E: 'static + Send + Sync + Error;
56
57    /// Report a message as an error.
58    ///
59    /// This is made available to format custom error messages in `no_std`
60    /// environments. The error message is to be collected by formatting `T`.
61    fn message<M>(self, message: M) -> Self::Error
62    where
63        M: fmt::Display;
64
65    /// Report an error based on a mark.
66    ///
67    /// A mark is generated using [Context::mark] and indicates a prior state.
68    #[inline]
69    fn marked_message<M>(self, mark: &Self::Mark, message: M) -> Self::Error
70    where
71        M: fmt::Display,
72    {
73        _ = mark;
74        self.message(message)
75    }
76
77    /// Report an error based on a mark.
78    ///
79    /// A mark is generated using [Context::mark] and indicates a prior state.
80    #[inline]
81    fn marked_custom<E>(self, mark: &Self::Mark, message: E) -> Self::Error
82    where
83        E: 'static + Send + Sync + Error,
84    {
85        _ = mark;
86        self.custom(message)
87    }
88
89    /// Indicate that we've entered a struct with the given `name`.
90    ///
91    /// The `name` variable corresponds to the identifiers of the struct.
92    ///
93    /// This will be matched with a corresponding call to [`leave_struct`].
94    ///
95    /// [`leave_struct`]: Context::leave_struct
96    #[inline]
97    fn enter_struct(self, type_name: &'static str) {
98        _ = type_name;
99    }
100
101    /// Trace that we've left the last struct that was entered.
102    #[inline]
103    fn leave_struct(self) {}
104
105    /// Indicate that we've entered an enum with the given `name`.
106    ///
107    /// The `name` variable corresponds to the identifiers of the enum.
108    ///
109    /// This will be matched with a corresponding call to [`leave_enum`].
110    ///
111    /// [`leave_enum`]: Context::leave_enum
112    #[inline]
113    fn enter_enum(self, type_name: &'static str) {
114        _ = type_name;
115    }
116
117    /// Trace that we've left the last enum that was entered.
118    #[inline]
119    fn leave_enum(self) {}
120
121    /// Trace that we've entered the given named field.
122    ///
123    /// A named field is part of a regular struct, where the literal field name
124    /// is the `name` argument below, and the musli tag being used for the field
125    /// is the second argument.
126    ///
127    /// This will be matched with a corresponding call to [`leave_field`].
128    ///
129    /// Here `name` is `"field"` and `tag` is `"string"`.
130    ///
131    /// ```
132    /// use musli::{Decode, Encode};
133    ///
134    /// #[derive(Decode, Encode)]
135    /// #[musli(name_all = "name")]
136    /// struct Struct {
137    ///     #[musli(name = "string")]
138    ///     field: String,
139    /// }
140    /// ```
141    ///
142    /// [`leave_field`]: Context::leave_field
143    #[inline]
144    fn enter_named_field<F>(self, type_name: &'static str, field: F)
145    where
146        F: fmt::Display,
147    {
148        _ = type_name;
149        _ = field;
150    }
151
152    /// Trace that we've entered the given unnamed field.
153    ///
154    /// An unnamed field is part of a tuple struct, where the field index is the
155    /// `index` argument below, and the musli tag being used for the field is
156    /// the second argument.
157    ///
158    /// This will be matched with a corresponding call to [`leave_field`].
159    ///
160    /// Here `index` is `0` and `name` is `"string"`.
161    ///
162    /// ```
163    /// use musli::{Decode, Encode};
164    ///
165    /// #[derive(Decode, Encode)]
166    /// #[musli(name_all = "name")]
167    /// struct Struct(#[musli(name = "string")] String);
168    /// ```
169    ///
170    /// [`leave_field`]: Context::leave_field
171    #[inline]
172    fn enter_unnamed_field<F>(self, index: u32, name: F)
173    where
174        F: fmt::Display,
175    {
176        _ = index;
177        _ = name;
178    }
179
180    /// Trace that we've left the last field that was entered.
181    ///
182    /// The `marker` argument will be the same as the one returned from
183    /// [`enter_named_field`] or [`enter_unnamed_field`].
184    ///
185    /// [`enter_named_field`]: Context::enter_named_field
186    /// [`enter_unnamed_field`]: Context::enter_unnamed_field
187    #[inline]
188    fn leave_field(self) {}
189
190    /// Trace that we've entered the given variant in an enum.
191    ///
192    /// A named variant is part of an enum, where the literal variant name is
193    /// the `name` argument below, and the musli tag being used to decode the
194    /// variant is the second argument.
195    ///
196    /// This will be matched with a corresponding call to
197    /// [`leave_variant`] with the same marker provided as an argument as
198    /// the one returned here.
199    ///
200    /// Here `name` is `"field"` and `tag` is `"string"`.
201    ///
202    /// ```
203    /// use musli::{Decode, Encode};
204    ///
205    /// #[derive(Decode, Encode)]
206    /// #[musli(name_all = "name")]
207    /// struct Struct {
208    ///     #[musli(name = "string")]
209    ///     field: String,
210    /// }
211    /// ```
212    ///
213    /// [`leave_variant`]: Context::leave_variant
214    #[inline]
215    fn enter_variant<V>(self, type_name: &'static str, tag: V)
216    where
217        V: fmt::Display,
218    {
219        _ = type_name;
220        _ = tag;
221    }
222
223    /// Trace that we've left the last variant that was entered.
224    ///
225    /// The `marker` argument will be the same as the one returned from
226    /// [`enter_variant`].
227    ///
228    /// [`enter_variant`]: Context::enter_variant
229    #[inline]
230    fn leave_variant(self) {}
231
232    /// Trace a that a map key has been entered.
233    #[inline]
234    fn enter_map_key<K>(self, field: K)
235    where
236        K: fmt::Display,
237    {
238        _ = field;
239    }
240
241    /// Trace that we've left the last map field that was entered.
242    ///
243    /// The `marker` argument will be the same as the one returned from
244    /// [`enter_map_key`].
245    ///
246    /// [`enter_map_key`]: Context::enter_map_key
247    #[inline]
248    fn leave_map_key(self) {}
249
250    /// Trace a sequence field.
251    #[inline]
252    fn enter_sequence_index(self, index: usize) {
253        _ = index;
254    }
255
256    /// Trace that we've left the last sequence index that was entered.
257    ///
258    /// The `marker` argument will be the same as the one returned from
259    /// [`enter_sequence_index`].
260    ///
261    /// [`enter_sequence_index`]: Context::enter_sequence_index
262    #[inline]
263    fn leave_sequence_index(self) {}
264}