musli_utils/context/
mod.rs

1//! Helper types to set up a basic Müsli [`Context`].
2//!
3//! [`Context`]: musli::Context
4
5mod access;
6mod error_marker;
7mod rich_error;
8mod stack_context;
9#[cfg(feature = "alloc")]
10mod system_context;
11pub use self::error_marker::ErrorMarker;
12mod error;
13pub use self::error::Error;
14
15use core::cell::{Cell, UnsafeCell};
16use core::fmt;
17use core::marker::PhantomData;
18
19use musli::context::StdError;
20use musli::mode::Binary;
21use musli::{Allocator, Context};
22
23use crate::buf::{self, BufString};
24
25#[cfg(feature = "alloc")]
26pub use self::system_context::SystemContext;
27
28pub use self::stack_context::StackContext;
29
30pub use self::rich_error::RichError;
31
32/// A simple non-diagnostical capturing context which simply emits the original
33/// error.
34///
35/// Using this should result in code which essentially just uses the emitted
36/// error type directly.
37pub struct Same<A, M, E> {
38    alloc: A,
39    _marker: PhantomData<(M, E)>,
40}
41
42impl<A, M, E> Same<A, M, E> {
43    /// Construct a new `Same` capturing context.
44    pub fn new(alloc: A) -> Self {
45        Self {
46            alloc,
47            _marker: PhantomData,
48        }
49    }
50}
51
52impl<A> Same<A, Binary, ErrorMarker> {
53    /// Construct a new `Same` capturing context.
54    #[inline]
55    #[doc(hidden)]
56    pub fn marker(alloc: A) -> Self {
57        Self::new(alloc)
58    }
59}
60
61impl<A, M, E> Default for Same<A, M, E>
62where
63    A: Default,
64{
65    #[inline]
66    fn default() -> Self {
67        Self {
68            alloc: A::default(),
69            _marker: PhantomData,
70        }
71    }
72}
73
74impl<A, M, E> Context for Same<A, M, E>
75where
76    A: Allocator,
77    E: Error,
78{
79    type Mode = M;
80    type Error = E;
81    type Mark = ();
82    type Buf<'this> = A::Buf<'this> where Self: 'this;
83    type BufString<'this> = BufString<A::Buf<'this>> where Self: 'this;
84
85    #[inline]
86    fn clear(&self) {}
87
88    #[inline]
89    fn alloc(&self) -> Option<Self::Buf<'_>> {
90        self.alloc.alloc()
91    }
92
93    #[inline]
94    fn collect_string<T>(&self, value: &T) -> Result<Self::BufString<'_>, Self::Error>
95    where
96        T: ?Sized + fmt::Display,
97    {
98        buf::collect_string(self, value)
99    }
100
101    #[inline]
102    fn custom<T>(&self, message: T) -> Self::Error
103    where
104        T: 'static + Send + Sync + StdError,
105    {
106        E::custom(message)
107    }
108
109    #[inline]
110    fn message<T>(&self, message: T) -> Self::Error
111    where
112        T: fmt::Display,
113    {
114        E::message(message)
115    }
116}
117
118/// A simple non-diagnostical capturing context which ignores the error and
119/// loses all information about it (except that it happened).
120pub struct Ignore<A, M, E> {
121    alloc: A,
122    error: Cell<bool>,
123    _marker: PhantomData<(M, E)>,
124}
125
126impl<A, M, E> Default for Ignore<A, M, E>
127where
128    A: Default,
129{
130    #[inline]
131    fn default() -> Self {
132        Self {
133            alloc: A::default(),
134            error: Cell::new(false),
135            _marker: PhantomData,
136        }
137    }
138}
139
140impl<A, M, E> Ignore<A, M, E> {
141    /// Construct a new ignoring context.
142    pub fn new(alloc: A) -> Self {
143        Self {
144            alloc,
145            error: Cell::new(false),
146            _marker: PhantomData,
147        }
148    }
149}
150
151impl<A> Ignore<A, Binary, ErrorMarker> {
152    /// Construct a new ignoring context which collects an error marker.
153    #[doc(hidden)]
154    pub fn marker(alloc: A) -> Self {
155        Self::new(alloc)
156    }
157}
158
159impl<A, M, E> Ignore<A, M, E>
160where
161    E: Error,
162{
163    /// Construct an error or panic.
164    pub fn unwrap(self) -> E {
165        if self.error.get() {
166            return E::message("error");
167        }
168
169        panic!("did not error")
170    }
171}
172
173impl<A, M, E: 'static> Context for Ignore<A, M, E>
174where
175    A: Allocator,
176{
177    type Mode = M;
178    type Error = ErrorMarker;
179    type Mark = ();
180    type Buf<'this> = A::Buf<'this> where Self: 'this;
181    type BufString<'this> = BufString<A::Buf<'this>> where Self: 'this;
182
183    #[inline]
184    fn clear(&self) {}
185
186    #[inline]
187    fn alloc(&self) -> Option<Self::Buf<'_>> {
188        self.alloc.alloc()
189    }
190
191    #[inline]
192    fn collect_string<T>(&self, value: &T) -> Result<Self::BufString<'_>, Self::Error>
193    where
194        T: ?Sized + fmt::Display,
195    {
196        buf::collect_string(self, value)
197    }
198
199    #[inline]
200    fn custom<T>(&self, _: T) -> ErrorMarker
201    where
202        T: 'static + Send + Sync + fmt::Display + fmt::Debug,
203    {
204        self.error.set(true);
205        ErrorMarker
206    }
207
208    #[inline]
209    fn message<T>(&self, _: T) -> ErrorMarker
210    where
211        T: fmt::Display,
212    {
213        self.error.set(true);
214        ErrorMarker
215    }
216}
217
218/// A simple non-diagnostical capturing context.
219pub struct Capture<A, M, E> {
220    alloc: A,
221    error: UnsafeCell<Option<E>>,
222    _marker: PhantomData<M>,
223}
224
225impl<A, M, E> Capture<A, M, E> {
226    /// Construct a new capturing allocator.
227    pub fn new(alloc: A) -> Self {
228        Self {
229            alloc,
230            error: UnsafeCell::new(None),
231            _marker: PhantomData,
232        }
233    }
234
235    /// Construct an error or panic.
236    pub fn unwrap(self) -> E {
237        if let Some(error) = self.error.into_inner() {
238            return error;
239        }
240
241        panic!("no error captured")
242    }
243}
244
245impl<A, M, E> Context for Capture<A, M, E>
246where
247    A: Allocator,
248    E: Error,
249{
250    type Mode = M;
251    type Error = ErrorMarker;
252    type Mark = ();
253    type Buf<'this> = A::Buf<'this> where Self: 'this;
254    type BufString<'this> = BufString<A::Buf<'this>> where Self: 'this;
255
256    #[inline]
257    fn clear(&self) {
258        // SAFETY: We're restricting access to the context, so that this is
259        // safe.
260        unsafe {
261            (*self.error.get()) = None;
262        }
263    }
264
265    #[inline]
266    fn alloc(&self) -> Option<Self::Buf<'_>> {
267        self.alloc.alloc()
268    }
269
270    #[inline]
271    fn collect_string<T>(&self, value: &T) -> Result<Self::BufString<'_>, Self::Error>
272    where
273        T: ?Sized + fmt::Display,
274    {
275        buf::collect_string(self, value)
276    }
277
278    #[inline]
279    fn custom<T>(&self, error: T) -> ErrorMarker
280    where
281        T: 'static + Send + Sync + StdError,
282    {
283        // SAFETY: We're restricting access to the context, so that this is
284        // safe.
285        unsafe {
286            self.error.get().replace(Some(E::custom(error)));
287        }
288
289        ErrorMarker
290    }
291
292    #[inline]
293    fn message<T>(&self, message: T) -> ErrorMarker
294    where
295        T: fmt::Display,
296    {
297        // SAFETY: We're restricting access to the context, so that this is
298        // safe.
299        unsafe {
300            self.error.get().replace(Some(E::message(message)));
301        }
302
303        ErrorMarker
304    }
305}
306
307impl<A, M, E> Default for Capture<A, M, E>
308where
309    A: Default,
310{
311    #[inline]
312    fn default() -> Self {
313        Self::new(A::default())
314    }
315}