tlbits/
error.rs

1use core::fmt::{Debug, Display};
2use std::{error::Error as StdError, io};
3
4use thiserror::Error as ThisError;
5
6/// **De**/**ser**ialization error
7pub trait Error: StdError + Sized {
8    /// Returns a custom error from given message
9    fn custom<T>(msg: T) -> Self
10    where
11        T: Display;
12
13    /// Wraps current error in given context
14    fn context<C>(self, context: C) -> Self
15    where
16        C: Display;
17}
18
19/// Adapter for providing context on [`Result`]
20pub trait Context: Sized {
21    type Ok;
22    type Error: Error;
23
24    /// Wrap [`Err`] in context by calling given function
25    fn with_context<C>(self, context: impl FnOnce() -> C) -> Result<Self::Ok, Self::Error>
26    where
27        C: Display;
28
29    /// Wrap [`Err`] in given context
30    #[inline]
31    fn context<C>(self, context: C) -> Result<Self::Ok, Self::Error>
32    where
33        C: Display,
34    {
35        self.with_context(move || context)
36    }
37}
38
39impl<T, E> Context for Result<T, E>
40where
41    E: Error,
42{
43    type Ok = T;
44    type Error = E;
45
46    #[inline]
47    fn with_context<C>(self, context: impl FnOnce() -> C) -> Result<T, E>
48    where
49        C: Display,
50    {
51        self.map_err(move |err| err.context(context()))
52    }
53}
54
55impl<T> Context for Option<T> {
56    type Ok = T;
57
58    type Error = StringError;
59
60    #[inline]
61    fn with_context<C>(self, context: impl FnOnce() -> C) -> Result<Self::Ok, Self::Error>
62    where
63        C: Display,
64    {
65        self.ok_or_else(context).map_err(Error::custom)
66    }
67}
68
69/// [`String`]-backed [`Error`]
70#[derive(Debug, ThisError)]
71#[error("{0}")]
72pub struct StringError(String);
73
74impl Error for StringError {
75    #[inline]
76    fn custom<T>(msg: T) -> Self
77    where
78        T: Display,
79    {
80        Self(msg.to_string())
81    }
82
83    #[inline]
84    fn context<C>(self, context: C) -> Self
85    where
86        C: Display,
87    {
88        Self(format!("{context}: {self}"))
89    }
90}
91
92impl AsRef<str> for StringError {
93    #[inline]
94    fn as_ref(&self) -> &str {
95        self.0.as_str()
96    }
97}
98
99impl Error for io::Error {
100    #[inline]
101    fn custom<T>(msg: T) -> Self
102    where
103        T: Display,
104    {
105        Self::other(msg.to_string())
106    }
107
108    #[inline]
109    fn context<C>(self, context: C) -> Self
110    where
111        C: Display,
112    {
113        Self::new(self.kind(), format!("{context}: {self}"))
114    }
115}