1 | //! Cross-platform interface to the `errno` variable. |
2 | //! |
3 | //! # Examples |
4 | //! ``` |
5 | //! use errno::{Errno, errno, set_errno}; |
6 | //! |
7 | //! // Get the current value of errno |
8 | //! let e = errno(); |
9 | //! |
10 | //! // Set the current value of errno |
11 | //! set_errno(e); |
12 | //! |
13 | //! // Extract the error code as an i32 |
14 | //! let code = e.0; |
15 | //! |
16 | //! // Display a human-friendly error message |
17 | //! println!("Error {}: {}" , code, e); |
18 | //! ``` |
19 | |
20 | #![cfg_attr (not(feature = "std" ), no_std)] |
21 | |
22 | #[cfg_attr (unix, path = "unix.rs" )] |
23 | #[cfg_attr (windows, path = "windows.rs" )] |
24 | #[cfg_attr (target_os = "wasi" , path = "wasi.rs" )] |
25 | #[cfg_attr (target_os = "hermit" , path = "hermit.rs" )] |
26 | mod sys; |
27 | |
28 | use core::fmt; |
29 | #[cfg (feature = "std" )] |
30 | use std::error::Error; |
31 | #[cfg (feature = "std" )] |
32 | use std::io; |
33 | |
34 | /// Wraps a platform-specific error code. |
35 | /// |
36 | /// The `Display` instance maps the code to a human-readable string. It |
37 | /// calls [`strerror_r`][1] under POSIX, and [`FormatMessageW`][2] on |
38 | /// Windows. |
39 | /// |
40 | /// [1]: http://pubs.opengroup.org/onlinepubs/009695399/functions/strerror.html |
41 | /// [2]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351%28v=vs.85%29.aspx |
42 | #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Hash)] |
43 | pub struct Errno(pub i32); |
44 | |
45 | impl fmt::Debug for Errno { |
46 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
47 | sys::with_description(*self, |desc| { |
48 | fmt.debug_struct("Errno" ) |
49 | .field("code" , &self.0) |
50 | .field("description" , &desc.ok()) |
51 | .finish() |
52 | }) |
53 | } |
54 | } |
55 | |
56 | impl fmt::Display for Errno { |
57 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
58 | sys::with_description(*self, |desc| match desc { |
59 | Ok(desc) => fmt.write_str(desc), |
60 | Err(fm_err) => write!( |
61 | fmt, |
62 | "OS error {} ({} returned error {})" , |
63 | self.0, |
64 | sys::STRERROR_NAME, |
65 | fm_err.0 |
66 | ), |
67 | }) |
68 | } |
69 | } |
70 | |
71 | impl From<Errno> for i32 { |
72 | fn from(e: Errno) -> Self { |
73 | e.0 |
74 | } |
75 | } |
76 | |
77 | #[cfg (feature = "std" )] |
78 | impl Error for Errno { |
79 | // TODO: Remove when MSRV >= 1.27 |
80 | #[allow (deprecated)] |
81 | fn description(&self) -> &str { |
82 | "system error" |
83 | } |
84 | } |
85 | |
86 | #[cfg (feature = "std" )] |
87 | impl From<Errno> for io::Error { |
88 | fn from(errno: Errno) -> Self { |
89 | io::Error::from_raw_os_error(errno.0) |
90 | } |
91 | } |
92 | |
93 | /// Returns the platform-specific value of `errno`. |
94 | pub fn errno() -> Errno { |
95 | sys::errno() |
96 | } |
97 | |
98 | /// Sets the platform-specific value of `errno`. |
99 | pub fn set_errno(err: Errno) { |
100 | sys::set_errno(err) |
101 | } |
102 | |
103 | #[test] |
104 | fn it_works() { |
105 | let x = errno(); |
106 | set_errno(x); |
107 | } |
108 | |
109 | #[cfg (feature = "std" )] |
110 | #[test] |
111 | fn it_works_with_to_string() { |
112 | let x = errno(); |
113 | let _ = x.to_string(); |
114 | } |
115 | |
116 | #[cfg (feature = "std" )] |
117 | #[test] |
118 | fn check_description() { |
119 | let expect = if cfg!(windows) { |
120 | "Incorrect function." |
121 | } else if cfg!(target_os = "illumos" ) { |
122 | "Not owner" |
123 | } else if cfg!(target_os = "wasi" ) { |
124 | "Argument list too long" |
125 | } else if cfg!(target_os = "haiku" ) { |
126 | "Operation not allowed" |
127 | } else { |
128 | "Operation not permitted" |
129 | }; |
130 | |
131 | let errno_code = if cfg!(target_os = "haiku" ) { |
132 | -2147483633 |
133 | } else { |
134 | 1 |
135 | }; |
136 | set_errno(Errno(errno_code)); |
137 | |
138 | assert_eq!(errno().to_string(), expect); |
139 | assert_eq!( |
140 | format!("{:?}" , errno()), |
141 | format!( |
142 | "Errno {{ code: {}, description: Some({:?}) }}" , |
143 | errno_code, expect |
144 | ) |
145 | ); |
146 | } |
147 | |
148 | #[cfg (feature = "std" )] |
149 | #[test] |
150 | fn check_error_into_errno() { |
151 | const ERROR_CODE: i32 = 1; |
152 | |
153 | let error = io::Error::from_raw_os_error(ERROR_CODE); |
154 | let new_error: io::Error = Errno(ERROR_CODE).into(); |
155 | assert_eq!(error.kind(), new_error.kind()); |
156 | } |
157 | |