1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use std::error::Error;
use std::fmt::{self, Display};

/// A general error that may occur while running or creating
/// the event loop.
#[derive(Debug)]
#[non_exhaustive]
pub enum EventLoopError {
    /// The event loop can't be re-created.
    RecreationAttempt,
    /// Application has exit with an error status.
    ExitFailure(i32),
    /// Got unspecified OS-specific error during the request.
    Os(OsError),
    /// Creating the event loop with the requested configuration is not supported.
    NotSupported(NotSupportedError),
}

impl fmt::Display for EventLoopError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::RecreationAttempt => write!(f, "EventLoop can't be recreated"),
            Self::Os(err) => err.fmt(f),
            Self::ExitFailure(status) => write!(f, "Exit Failure: {status}"),
            Self::NotSupported(err) => err.fmt(f),
        }
    }
}

impl Error for EventLoopError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        if let Self::Os(err) = self {
            err.source()
        } else {
            None
        }
    }
}

impl From<OsError> for EventLoopError {
    fn from(value: OsError) -> Self {
        Self::Os(value)
    }
}

impl From<NotSupportedError> for EventLoopError {
    fn from(value: NotSupportedError) -> Self {
        Self::NotSupported(value)
    }
}

/// A general error that may occur during a request to the windowing system.
#[derive(Debug)]
#[non_exhaustive]
pub enum RequestError {
    /// The request is not supported.
    NotSupported(NotSupportedError),
    /// The request was ignored by the operating system.
    Ignored,
    /// Got unspecified OS specific error during the request.
    Os(OsError),
}

impl Display for RequestError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NotSupported(err) => err.fmt(f),
            Self::Ignored => write!(f, "The request was ignored"),
            Self::Os(err) => err.fmt(f),
        }
    }
}
impl Error for RequestError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        if let Self::Os(err) = self {
            err.source()
        } else {
            None
        }
    }
}

impl From<NotSupportedError> for RequestError {
    fn from(value: NotSupportedError) -> Self {
        Self::NotSupported(value)
    }
}

impl From<OsError> for RequestError {
    fn from(value: OsError) -> Self {
        Self::Os(value)
    }
}

/// The requested operation is not supported.
#[derive(Debug)]
pub struct NotSupportedError {
    /// The reason why a certain operation is not supported.
    reason: &'static str,
}

impl NotSupportedError {
    pub fn new(reason: &'static str) -> Self {
        Self { reason }
    }
}

impl fmt::Display for NotSupportedError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Operation is not supported: {}", self.reason)
    }
}
impl Error for NotSupportedError {}

/// Unclassified error from the OS.
#[derive(Debug)]
pub struct OsError {
    line: u32,
    file: &'static str,
    error: Box<dyn Error + Send + Sync + 'static>,
}

impl OsError {
    #[allow(dead_code)]
    pub(crate) fn new(
        line: u32,
        file: &'static str,
        error: impl Into<Box<dyn Error + Send + Sync + 'static>>,
    ) -> Self {
        Self { line, file, error: error.into() }
    }
}

impl Display for OsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad(&format!("os error at {}:{}: {}", self.file, self.line, self.error))
    }
}
impl Error for OsError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        Some(self.error.as_ref())
    }
}

#[allow(unused_macros)]
macro_rules! os_error {
    ($error:expr) => {{
        crate::error::OsError::new(line!(), file!(), $error)
    }};
}