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}