ironrdp_error/
lib.rs

1#![doc = include_str!("../README.md")]
2#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5#[cfg(feature = "alloc")]
6extern crate alloc;
7
8#[cfg(feature = "alloc")]
9use alloc::boxed::Box;
10use core::fmt;
11
12#[cfg(feature = "std")]
13pub trait Source: core::error::Error + Sync + Send + 'static {}
14
15#[cfg(feature = "std")]
16impl<T> Source for T where T: core::error::Error + Sync + Send + 'static {}
17
18#[cfg(not(feature = "std"))]
19pub trait Source: fmt::Display + fmt::Debug + Send + Sync + 'static {}
20
21#[cfg(not(feature = "std"))]
22impl<T> Source for T where T: fmt::Display + fmt::Debug + Send + Sync + 'static {}
23
24#[derive(Debug)]
25pub struct Error<Kind> {
26    pub context: &'static str,
27    pub kind: Kind,
28    #[cfg(feature = "std")]
29    source: Option<Box<dyn core::error::Error + Sync + Send>>,
30    #[cfg(all(not(feature = "std"), feature = "alloc"))]
31    source: Option<Box<dyn Source>>,
32}
33
34impl<Kind> Error<Kind> {
35    #[cold]
36    #[must_use]
37    pub fn new(context: &'static str, kind: Kind) -> Self {
38        Self {
39            context,
40            kind,
41            #[cfg(feature = "alloc")]
42            source: None,
43        }
44    }
45
46    #[cold]
47    #[must_use]
48    pub fn with_source<E>(self, source: E) -> Self
49    where
50        E: Source,
51    {
52        #[cfg(feature = "alloc")]
53        {
54            let mut this = self;
55            this.source = Some(Box::new(source));
56            this
57        }
58
59        // No source when no std and no alloc crates
60        #[cfg(not(feature = "alloc"))]
61        {
62            let _ = source;
63            self
64        }
65    }
66
67    pub fn into_other_kind<OtherKind>(self) -> Error<OtherKind>
68    where
69        Kind: Into<OtherKind>,
70    {
71        Error {
72            context: self.context,
73            kind: self.kind.into(),
74            #[cfg(any(feature = "std", feature = "alloc"))]
75            source: self.source,
76        }
77    }
78
79    pub fn kind(&self) -> &Kind {
80        &self.kind
81    }
82
83    pub fn report(&self) -> ErrorReport<'_, Kind> {
84        ErrorReport(self)
85    }
86}
87
88impl<Kind> fmt::Display for Error<Kind>
89where
90    Kind: fmt::Display,
91{
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        write!(f, "[{}] {}", self.context, self.kind)
94    }
95}
96
97#[cfg(feature = "std")]
98impl<Kind> core::error::Error for Error<Kind>
99where
100    Kind: core::error::Error,
101{
102    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
103        if let Some(source) = self.kind.source() {
104            Some(source)
105        } else {
106            // NOTE: we can’t use Option::as_ref here because of type inference
107            if let Some(e) = &self.source {
108                Some(e.as_ref())
109            } else {
110                None
111            }
112        }
113    }
114}
115
116#[cfg(feature = "std")]
117impl<Kind> From<Error<Kind>> for std::io::Error
118where
119    Kind: core::error::Error + Send + Sync + 'static,
120{
121    fn from(error: Error<Kind>) -> Self {
122        Self::other(error)
123    }
124}
125
126pub struct ErrorReport<'a, Kind>(&'a Error<Kind>);
127
128#[cfg(feature = "std")]
129impl<Kind> fmt::Display for ErrorReport<'_, Kind>
130where
131    Kind: core::error::Error,
132{
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        use core::error::Error;
135
136        write!(f, "{}", self.0)?;
137
138        let mut next_source = self.0.source();
139
140        while let Some(e) = next_source {
141            write!(f, ", caused by: {e}")?;
142            next_source = e.source();
143        }
144
145        Ok(())
146    }
147}
148
149#[cfg(not(feature = "std"))]
150impl<E> fmt::Display for ErrorReport<'_, E>
151where
152    E: fmt::Display,
153{
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        write!(f, "{}", self.0)?;
156
157        #[cfg(feature = "alloc")]
158        if let Some(source) = &self.0.source {
159            write!(f, ", caused by: {source}")?;
160        }
161
162        Ok(())
163    }
164}