musli/context/
capture.rs

1use core::cell::UnsafeCell;
2use core::error::Error;
3use core::fmt;
4use core::marker::PhantomData;
5
6use super::{ContextError, ErrorMarker};
7
8mod sealed {
9    pub trait Sealed {}
10    impl Sealed for super::Ignore {}
11    impl<E> Sealed for super::Capture<E> {}
12    impl<E> Sealed for super::Emit<E> {}
13}
14
15/// The trait governing how error capture is implemented.
16///
17/// See [`DefaultContext::with_capture`] or [`DefaultContext::with_error`] for
18/// more information.
19///
20/// [`DefaultContext::with_capture`]: super::DefaultContext::with_capture
21/// [`DefaultContext::with_error`]: super::DefaultContext::with_error
22pub trait ErrorMode<A>: self::sealed::Sealed {
23    #[doc(hidden)]
24    type Error;
25
26    #[doc(hidden)]
27    fn clear(&self);
28
29    #[doc(hidden)]
30    fn message<T>(&self, alloc: A, message: T) -> Self::Error
31    where
32        T: fmt::Display;
33
34    #[doc(hidden)]
35    fn custom<T>(&self, alloc: A, error: T) -> Self::Error
36    where
37        T: 'static + Send + Sync + Error;
38}
39
40/// Disable error capture.
41///
42/// The error produced will be an [`ErrorMarker`] which is a zero-sized
43/// placeholder type.
44///
45/// To capture an error, use [`with_capture::<E>`]. To produce an error see
46/// [`with_error::<E>`].
47///
48/// This is the default behavior you get when calling [`new`] or [`new_in`].
49///
50/// [`with_capture::<E>`]: super::DefaultContext::with_capture
51/// [`with_error::<E>`]: super::DefaultContext::with_error
52///
53/// [`new`]: super::new
54/// [`new_in`]: super::new_in
55#[non_exhaustive]
56pub struct Ignore;
57
58impl<A> ErrorMode<A> for Ignore {
59    type Error = ErrorMarker;
60
61    #[inline]
62    fn clear(&self) {}
63
64    #[inline]
65    fn message<T>(&self, alloc: A, message: T) -> Self::Error
66    where
67        T: fmt::Display,
68    {
69        _ = alloc;
70        _ = message;
71        ErrorMarker
72    }
73
74    #[inline]
75    fn custom<T>(&self, alloc: A, error: T) -> Self::Error
76    where
77        T: 'static + Send + Sync + Error,
78    {
79        _ = alloc;
80        _ = error;
81        ErrorMarker
82    }
83}
84
85/// Emit an error of the specified type `E`.
86///
87/// See [`DefaultContext::with_error`] for more information.
88///
89/// [`DefaultContext::with_error`]: super::DefaultContext::with_error
90pub struct Emit<E> {
91    _marker: PhantomData<E>,
92}
93
94impl<E> Emit<E> {
95    #[inline]
96    pub(super) fn new() -> Self {
97        Self {
98            _marker: PhantomData,
99        }
100    }
101}
102
103impl<E, A> ErrorMode<A> for Emit<E>
104where
105    E: ContextError<A>,
106{
107    type Error = E;
108
109    #[inline]
110    fn clear(&self) {}
111
112    #[inline]
113    fn message<T>(&self, alloc: A, message: T) -> Self::Error
114    where
115        T: fmt::Display,
116    {
117        E::message(alloc, message)
118    }
119
120    #[inline]
121    fn custom<T>(&self, alloc: A, error: T) -> Self::Error
122    where
123        T: 'static + Send + Sync + Error,
124    {
125        E::custom(alloc, error)
126    }
127}
128
129/// Capture an error of the specified type `E`.
130///
131/// See [`DefaultContext::with_capture`] for more information.
132///
133/// [`DefaultContext::with_capture`]: super::DefaultContext::with_capture
134pub struct Capture<E> {
135    error: UnsafeCell<Option<E>>,
136}
137
138impl<E> Capture<E> {
139    #[inline]
140    pub(super) fn new() -> Self {
141        Self {
142            error: UnsafeCell::new(None),
143        }
144    }
145}
146
147impl<E> Capture<E> {
148    #[inline]
149    pub(super) fn unwrap(&self) -> E {
150        // SAFETY: We're restricting access to the context, so that this is
151        // safe.
152        unsafe {
153            match (*self.error.get()).take() {
154                Some(error) => error,
155                None => panic!("no error captured"),
156            }
157        }
158    }
159
160    #[inline]
161    pub(super) fn result(&self) -> Result<(), E> {
162        // SAFETY: We're restricting access to the context, so that this is
163        // safe.
164        unsafe {
165            match (*self.error.get()).take() {
166                Some(error) => Err(error),
167                None => Ok(()),
168            }
169        }
170    }
171}
172
173impl<E, A> ErrorMode<A> for Capture<E>
174where
175    E: ContextError<A>,
176{
177    type Error = ErrorMarker;
178
179    #[inline]
180    fn clear(&self) {
181        // SAFETY: We're restricting access to the context, so that this is
182        // safe.
183        unsafe {
184            (*self.error.get()) = None;
185        }
186    }
187
188    #[inline]
189    fn message<T>(&self, alloc: A, message: T) -> Self::Error
190    where
191        T: fmt::Display,
192    {
193        // SAFETY: We're restricting access to the context, so that this is
194        // safe.
195        unsafe {
196            (*self.error.get()) = Some(E::message(alloc, message));
197        }
198
199        ErrorMarker
200    }
201
202    #[inline]
203    fn custom<T>(&self, alloc: A, error: T) -> Self::Error
204    where
205        T: 'static + Send + Sync + Error,
206    {
207        // SAFETY: We're restricting access to the context, so that this is
208        // safe.
209        unsafe {
210            (*self.error.get()) = Some(E::custom(alloc, error));
211        }
212
213        ErrorMarker
214    }
215}