musli_common/context/
mod.rs

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