Skip to main content

refining_core/
errors.rs

1//! Errors returned during refining.
2
3use core::{fmt, marker::PhantomData, mem::transmute};
4
5use thiserror::Error;
6
7use crate::{
8    context::NoContext,
9    predicate::{Predicate, PredicateExpected},
10    types::TypeStr,
11};
12
13/// The `Error` literal.
14pub const ERROR: &str = "Error";
15
16/// The `expected` literal.
17pub const EXPECTED: &str = "expected";
18
19/// The `context` literal.
20pub const CONTEXT: &str = "context";
21
22/// Represents errors that occur when the value of type `T` does not satisfy the predicate `P`.
23///
24/// The context `C` provides additional information about the error, and defaults to `NoContext`.
25///
26/// For instance, [`False`] expects `nothing` and its code is `false`, so the error message is:
27///
28/// ```text
29/// expected nothing (no context) [false]
30/// ```
31///
32/// [`False`]: crate::logical::False
33#[derive(Error)]
34#[error(
35    "{EXPECTED} {expected} ({context}) [{expected:?}]",
36    expected = P::expected(),
37    context = C::VALUE
38)]
39#[repr(transparent)]
40pub struct Error<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized = NoContext> {
41    predicate: PhantomData<P>,
42    context: PhantomData<C>,
43    value: T,
44}
45
46impl<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Error<T, P, C> {
47    // XXX: do not expose this function
48    pub(crate) const fn new_ref(value: &T) -> &Self {
49        // SAFETY: layouts of `T` and `Self` are the same, so this is safe
50        unsafe { transmute(value) }
51    }
52
53    /// Returns the contained value reference.
54    pub const fn get_ref(&self) -> &T {
55        &self.value
56    }
57}
58
59impl<T, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> Error<T, P, C> {
60    // XXX: do not expose this function
61    pub(crate) const fn new(value: T) -> Self {
62        Self {
63            predicate: PhantomData,
64            context: PhantomData,
65            value,
66        }
67    }
68
69    /// Returns the contained value.
70    pub fn get(self) -> T {
71        self.value
72    }
73}
74
75/// Represents recoverable reference results.
76pub type RecoverableRef<'a, T, P, C = NoContext, R = T> = Result<&'a T, &'a Error<R, P, C>>;
77
78/// Represents recoverable results.
79pub type Recoverable<T, P, C = NoContext, R = T> = Result<T, Error<R, P, C>>;
80
81impl<T: ?Sized, P: Predicate<T> + ?Sized, C: TypeStr + ?Sized> fmt::Debug for Error<T, P, C> {
82    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
83        let expected = P::expected();
84        let context = C::VALUE;
85
86        formatter
87            .debug_struct(ERROR)
88            .field(EXPECTED, &expected)
89            .field(CONTEXT, &context)
90            .finish_non_exhaustive()
91    }
92}