Skip to main content

irox_bits/
error.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2024 IROX Contributors
3//
4
5/// Type alias to [`BitsError`]
6///
7/// Originally would map to [`std::io::Error`] when the `std` feature was enabled, but that proved
8/// less ergonomic than just a internal error struct.
9pub type Error = BitsError;
10
11/// Type alias to [`BitsErrorKind`]
12///
13/// Originally would map to [`std::io::ErrorKind`] when the `std` feature was enabled, but that proved
14/// less ergonomic than just a internal error struct.
15pub type ErrorKind = BitsErrorKind;
16
17/// Error returned from the various Bits methods.
18///
19/// This used to be a no-std 1:1 swap out with [`std::io::Error`], but it become more ergonomic to
20/// simply use this error type everywhere.
21#[derive(Debug, Copy, Clone, Eq, PartialEq)]
22pub struct BitsError {
23    kind: BitsErrorKind,
24    msg: &'static str,
25}
26
27impl BitsError {
28    /// Creates a new error
29    #[allow(clippy::print_stdout)]
30    pub fn new(kind: BitsErrorKind, msg: &'static str) -> Self {
31        #[cfg(all(feature = "bits_backtrace", debug_assertions))]
32        {
33            println!(
34                "BitsError ({kind:?}:{msg})\n{}",
35                std::backtrace::Backtrace::capture()
36            );
37        }
38        BitsError { kind, msg }
39    }
40    /// Creates a new error
41    pub const fn cnew(kind: BitsErrorKind, msg: &'static str) -> Self {
42        BitsError { kind, msg }
43    }
44
45    /// Returns the error type/kind of this error
46    pub const fn kind(&self) -> BitsErrorKind {
47        self.kind
48    }
49
50    /// Returns the error message.
51    pub const fn msg(&self) -> &'static str {
52        self.msg
53    }
54
55    /// Creates an error variant of this type
56    pub fn err<T>(kind: BitsErrorKind, msg: &'static str) -> Result<T, Self> {
57        Err(Self::new(kind, msg))
58    }
59}
60
61impl From<BitsErrorKind> for BitsError {
62    fn from(kind: BitsErrorKind) -> Self {
63        BitsError {
64            kind,
65            msg: match kind {
66                BitsErrorKind::InvalidData => "Invalid Data",
67                BitsErrorKind::UnexpectedEof => "Unexpected EOF",
68                BitsErrorKind::FormatError => "Unspecified Formatting Error",
69                BitsErrorKind::OutOfMemory => "Out of Memory",
70
71                BitsErrorKind::NotFound => "Not Found",
72                BitsErrorKind::PermissionDenied => "Permission Denied",
73                BitsErrorKind::ConnectionRefused => "Connection Refused",
74                BitsErrorKind::ConnectionReset => "Connection Reset",
75                BitsErrorKind::ConnectionAborted => "Connection Aborted",
76                BitsErrorKind::AddrInUse => "Address In Use",
77                BitsErrorKind::AddrNotAvailable => "Address Not Available",
78                BitsErrorKind::BrokenPipe => "Broken Pipe",
79                BitsErrorKind::AlreadyExists => "Already Exists",
80                BitsErrorKind::WouldBlock => "Would Block",
81                BitsErrorKind::InvalidInput => "Invalid Input",
82                BitsErrorKind::TimedOut => "Timed Out",
83                BitsErrorKind::WriteZero => "Write Zero",
84                BitsErrorKind::Interrupted => "Interrupted",
85                BitsErrorKind::NotConnected => "Not Connected",
86                BitsErrorKind::Unsupported => "Unsupported",
87                BitsErrorKind::Other => "Other",
88            },
89        }
90    }
91}
92
93impl From<BitsError> for core::fmt::Error {
94    fn from(_kind: BitsError) -> Self {
95        core::fmt::Error
96    }
97}
98
99impl From<core::fmt::Error> for BitsError {
100    fn from(_value: core::fmt::Error) -> Self {
101        BitsErrorKind::FormatError.into()
102    }
103}
104
105#[cfg(feature = "std")]
106impl From<std::io::Error> for BitsError {
107    fn from(value: std::io::Error) -> Self {
108        BitsError::new(value.kind().into(), "IO Error")
109    }
110}
111
112#[cfg(feature = "std")]
113impl From<BitsError> for std::io::Error {
114    fn from(value: BitsError) -> Self {
115        Into::<std::io::ErrorKind>::into(value.kind).into()
116    }
117}
118
119#[cfg(feature = "std")]
120impl From<std::io::ErrorKind> for BitsErrorKind {
121    fn from(value: std::io::ErrorKind) -> Self {
122        use std::io::ErrorKind;
123        match value {
124            ErrorKind::NotFound => BitsErrorKind::NotFound,
125            ErrorKind::PermissionDenied => BitsErrorKind::PermissionDenied,
126            ErrorKind::ConnectionRefused => BitsErrorKind::ConnectionRefused,
127            ErrorKind::ConnectionReset => BitsErrorKind::ConnectionReset,
128            ErrorKind::ConnectionAborted => BitsErrorKind::ConnectionAborted,
129            ErrorKind::NotConnected => BitsErrorKind::NotConnected,
130            ErrorKind::AddrInUse => BitsErrorKind::AddrInUse,
131            ErrorKind::AddrNotAvailable => BitsErrorKind::AddrNotAvailable,
132            ErrorKind::BrokenPipe => BitsErrorKind::BrokenPipe,
133            ErrorKind::AlreadyExists => BitsErrorKind::AlreadyExists,
134            ErrorKind::WouldBlock => BitsErrorKind::WouldBlock,
135            ErrorKind::InvalidInput => BitsErrorKind::InvalidInput,
136            ErrorKind::InvalidData => BitsErrorKind::InvalidData,
137            ErrorKind::TimedOut => BitsErrorKind::TimedOut,
138            ErrorKind::WriteZero => BitsErrorKind::WriteZero,
139            ErrorKind::Interrupted => BitsErrorKind::Interrupted,
140            ErrorKind::Unsupported => BitsErrorKind::Unsupported,
141            ErrorKind::UnexpectedEof => BitsErrorKind::UnexpectedEof,
142            ErrorKind::OutOfMemory => BitsErrorKind::OutOfMemory,
143            _ => BitsErrorKind::Other,
144        }
145    }
146}
147
148#[cfg(feature = "std")]
149impl From<BitsErrorKind> for std::io::ErrorKind {
150    fn from(value: BitsErrorKind) -> Self {
151        use std::io::ErrorKind;
152        match value {
153            BitsErrorKind::InvalidData => ErrorKind::InvalidData,
154            BitsErrorKind::UnexpectedEof => ErrorKind::UnexpectedEof,
155            BitsErrorKind::OutOfMemory => ErrorKind::OutOfMemory,
156            BitsErrorKind::NotFound => ErrorKind::NotFound,
157            BitsErrorKind::PermissionDenied => ErrorKind::PermissionDenied,
158            BitsErrorKind::ConnectionRefused => ErrorKind::ConnectionRefused,
159            BitsErrorKind::ConnectionReset => ErrorKind::ConnectionReset,
160            BitsErrorKind::ConnectionAborted => ErrorKind::ConnectionAborted,
161            BitsErrorKind::AddrInUse => ErrorKind::AddrInUse,
162            BitsErrorKind::AddrNotAvailable => ErrorKind::AddrNotAvailable,
163            BitsErrorKind::BrokenPipe => ErrorKind::BrokenPipe,
164            BitsErrorKind::AlreadyExists => ErrorKind::AlreadyExists,
165            BitsErrorKind::WouldBlock => ErrorKind::WouldBlock,
166            BitsErrorKind::InvalidInput => ErrorKind::InvalidInput,
167            BitsErrorKind::TimedOut => ErrorKind::TimedOut,
168            BitsErrorKind::WriteZero => ErrorKind::WriteZero,
169            BitsErrorKind::Interrupted => ErrorKind::Interrupted,
170            BitsErrorKind::Unsupported => ErrorKind::Unsupported,
171            BitsErrorKind::NotConnected => ErrorKind::NotConnected,
172            _ => ErrorKind::Other,
173        }
174    }
175}
176
177/// Enum originally modelled after [`std::io::ErrorKind`], used to indicate the
178/// type of the error encountered.
179#[derive(Debug, Copy, Clone, Eq, PartialEq)]
180pub enum BitsErrorKind {
181    InvalidData,
182    UnexpectedEof,
183    FormatError,
184    OutOfMemory,
185    NotFound,
186    PermissionDenied,
187    ConnectionRefused,
188    ConnectionReset,
189    ConnectionAborted,
190    AddrInUse,
191    AddrNotAvailable,
192    BrokenPipe,
193    AlreadyExists,
194    WouldBlock,
195    InvalidInput,
196    TimedOut,
197    WriteZero,
198    Interrupted,
199    NotConnected,
200    Unsupported,
201    Other,
202}
203
204impl BitsErrorKind {
205    pub const fn err<T>(self, msg: &'static str) -> Result<T, BitsError> {
206        Err(BitsError::cnew(self, msg))
207    }
208}
209
210#[cfg(feature = "std")]
211impl std::error::Error for BitsError {}
212
213impl core::fmt::Display for BitsError {
214    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
215        write!(f, "BitsError({:?}): {}", self.kind, self.msg)
216    }
217}
218
219cfg_feature_alloc! {
220    impl From<alloc::string::FromUtf8Error> for BitsError {
221        fn from(_value: alloc::string::FromUtf8Error) -> Self {
222            BitsError {
223                kind: BitsErrorKind::InvalidInput,
224                msg: "Invalid UTF-8 detected while trying to process input.",
225            }
226        }
227    }
228}