rawsys_linux/errno/
mod.rs1#[macro_use]
21mod macros;
22
23#[allow(clippy::all, clippy::pedantic)]
24mod generated;
25
26#[cfg(feature = "std")]
27mod last;
28
29use core::fmt;
30
31pub use self::generated::Errno;
32
33impl Errno {
34 pub const EWOULDBLOCK: Self = Self::EAGAIN;
36
37 pub const EDEADLOCK: Self = Self::EDEADLK;
39
40 pub fn new(num: i32) -> Self {
42 Self(num)
43 }
44
45 pub fn into_raw(self) -> i32 {
47 self.0
48 }
49
50 pub fn is_valid(&self) -> bool {
52 self.0 < 4096
53 }
54
55 #[inline(always)]
60 #[deprecated = "It is recommended to explicitly use u32 or u64."]
61 pub fn from_ret(value: usize) -> Result<usize, Errno> {
62 if value > -4096isize as usize {
63 Err(Self(-(value as i32)))
67 } else {
68 Ok(value)
69 }
70 }
71
72 #[inline(always)]
74 pub fn from_ret_u32(value: u32) -> Result<u32, Errno> {
75 const THRESHOLD: u32 = u32::MAX - 4095; if value > THRESHOLD {
77 let code = (u32::MAX - value + 1) as i32;
79 Err(Errno(code))
80 } else {
81 Ok(value)
82 }
83 }
84
85 #[inline(always)]
87 pub fn from_ret_u64(value: u64) -> Result<u64, Errno> {
88 const THRESHOLD: u64 = u64::MAX - 4095; if value > THRESHOLD {
90 let code = (u64::MAX - value + 1) as i32;
92 Err(Errno(code))
93 } else {
94 Ok(value)
95 }
96 }
97 #[cfg(feature = "std")]
99 pub fn last() -> Self {
100 Self(unsafe { *last::errno() })
101 }
102
103 #[cfg(feature = "std")]
105 pub fn result<T>(value: T) -> Result<T, Errno>
106 where
107 T: ErrnoSentinel + PartialEq<T>,
108 {
109 if value == T::sentinel() {
110 Err(Self::last())
111 } else {
112 Ok(value)
113 }
114 }
115
116 pub fn name(&self) -> Option<&'static str> {
119 self.name_and_description().map(|x| x.0)
120 }
121
122 pub fn description(&self) -> Option<&'static str> {
125 self.name_and_description().map(|x| x.1)
126 }
127
128 #[cfg(feature = "std")]
136 pub fn from_io_error(err: std::io::Error) -> Option<Self> {
137 err.raw_os_error().map(Self::new)
138 }
139}
140
141impl fmt::Display for Errno {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 match self.name_and_description() {
144 Some((name, description)) => {
145 write!(f, "{} {name} ({description})", -self.0)
146 }
147 None => {
148 if self.is_valid() {
149 write!(f, "{}", -self.0)
150 } else {
151 write!(f, "Invalid errno {:#x}", self.0)
152 }
153 }
154 }
155 }
156}
157
158impl fmt::Debug for Errno {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 match self.name() {
161 Some(name) => f.write_str(name),
162 None => write!(f, "Errno({})", self.0),
163 }
164 }
165}
166
167#[cfg(feature = "std")]
168impl From<Errno> for std::io::Error {
169 fn from(err: Errno) -> Self {
170 std::io::Error::from_raw_os_error(err.into_raw())
171 }
172}
173
174#[cfg(feature = "std")]
175impl std::error::Error for Errno {}
176
177pub trait ErrnoSentinel: Sized {
178 fn sentinel() -> Self;
179}
180
181impl ErrnoSentinel for isize {
182 fn sentinel() -> Self {
183 -1
184 }
185}
186
187impl ErrnoSentinel for i32 {
188 fn sentinel() -> Self {
189 -1
190 }
191}
192
193impl ErrnoSentinel for i64 {
194 fn sentinel() -> Self {
195 -1
196 }
197}
198
199impl ErrnoSentinel for *mut core::ffi::c_void {
200 fn sentinel() -> Self {
201 -1isize as *mut core::ffi::c_void
202 }
203}
204
205impl ErrnoSentinel for usize {
206 fn sentinel() -> Self {
207 usize::MAX
208 }
209}
210
211#[cfg(test)]
212mod test {
213 use super::*;
214
215 #[test]
216 fn basic() {
217 assert_eq!(Errno::ENOENT.name(), Some("ENOENT"));
218 assert_eq!(
219 Errno::ENOENT.description(),
220 Some("No such file or directory")
221 );
222 #[cfg(feature = "std")]
223 {
224 assert_eq!(
225 format!("{}", Errno::ENOENT),
226 "-2 ENOENT (No such file or directory)"
227 );
228 assert_eq!(format!("{:?}", Errno::ENOENT), "ENOENT");
229 }
230 }
231
232 #[allow(deprecated)]
233 #[test]
234 fn from_ret() {
235 assert_eq!(Errno::from_ret(-2isize as usize), Err(Errno::ENOENT));
236 assert_eq!(Errno::from_ret_u64(-2isize as u64), Err(Errno::ENOENT));
237 assert_eq!(Errno::from_ret_u32(-2isize as u32), Err(Errno::ENOENT));
238 assert_eq!(Errno::from_ret(2), Ok(2));
239 assert_eq!(Errno::from_ret_u32(2), Ok(2));
240 assert_eq!(Errno::from_ret_u64(2), Ok(2));
241 }
242
243 #[cfg(feature = "std")]
244 #[test]
245 fn io_error() {
246 use std::io;
247
248 assert_eq!(
249 io::Error::from(Errno::ENOENT).kind(),
250 io::ErrorKind::NotFound
251 );
252
253 assert_eq!(
254 Errno::from_io_error(io::Error::from_raw_os_error(2)),
255 Some(Errno::ENOENT)
256 );
257
258 assert_eq!(
259 Errno::from_io_error(io::Error::new(io::ErrorKind::Other, "")),
260 None
261 );
262 }
263
264 #[cfg(feature = "std")]
265 #[test]
266 fn last_errno() {
267 assert_eq!(
268 Errno::result(unsafe {
269 libc::open(
270 b"this_should_not_exist\0".as_ptr() as *const _,
271 libc::O_RDONLY,
272 )
273 }),
274 Err(Errno::ENOENT)
275 );
276 }
277}