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