1use 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
13pub const ERROR: &str = "Error";
15
16pub const EXPECTED: &str = "expected";
18
19pub const CONTEXT: &str = "context";
21
22#[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 pub(crate) const fn new_ref(value: &T) -> &Self {
49 unsafe { transmute(value) }
51 }
52
53 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 pub(crate) const fn new(value: T) -> Self {
62 Self {
63 predicate: PhantomData,
64 context: PhantomData,
65 value,
66 }
67 }
68
69 pub fn get(self) -> T {
71 self.value
72 }
73}
74
75pub type RecoverableRef<'a, T, P, C = NoContext, R = T> = Result<&'a T, &'a Error<R, P, C>>;
77
78pub 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}