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 {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result46     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 {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result57     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 {
from(e: Errno) -> Self72     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)]
description(&self) -> &str81     fn description(&self) -> &str {
82         "system error"
83     }
84 }
85 
86 #[cfg(feature = "std")]
87 impl From<Errno> for io::Error {
from(errno: Errno) -> Self88     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`.
errno() -> Errno94 pub fn errno() -> Errno {
95     sys::errno()
96 }
97 
98 /// Sets the platform-specific value of `errno`.
set_errno(err: Errno)99 pub fn set_errno(err: Errno) {
100     sys::set_errno(err)
101 }
102 
103 #[test]
it_works()104 fn it_works() {
105     let x = errno();
106     set_errno(x);
107 }
108 
109 #[cfg(feature = "std")]
110 #[test]
it_works_with_to_string()111 fn it_works_with_to_string() {
112     let x = errno();
113     let _ = x.to_string();
114 }
115 
116 #[cfg(feature = "std")]
117 #[test]
check_description()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]
check_error_into_errno()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