errno/
lib.rs

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")]
26mod sys;
27
28use core::fmt;
29#[cfg(feature = "std")]
30use std::error::Error;
31#[cfg(feature = "std")]
32use 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)]
43pub struct Errno(pub i32);
44
45impl 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
56impl 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
71impl From<Errno> for i32 {
72    fn from(e: Errno) -> Self {
73        e.0
74    }
75}
76
77#[cfg(feature = "std")]
78impl 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")]
87impl 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`.
94pub fn errno() -> Errno {
95    sys::errno()
96}
97
98/// Sets the platform-specific value of `errno`.
99pub fn set_errno(err: Errno) {
100    sys::set_errno(err)
101}
102
103#[test]
104fn it_works() {
105    let x = errno();
106    set_errno(x);
107}
108
109#[cfg(feature = "std")]
110#[test]
111fn it_works_with_to_string() {
112    let x = errno();
113    let _ = x.to_string();
114}
115
116#[cfg(feature = "std")]
117#[test]
118fn 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") || cfg!(target_os = "emscripten") {
124        "Argument list too long"
125    } else if cfg!(target_os = "haiku") {
126        "Operation not allowed"
127    } else if cfg!(target_os = "vxworks") {
128        "operation not permitted"
129    } else {
130        "Operation not permitted"
131    };
132
133    let errno_code = if cfg!(target_os = "haiku") {
134        -2147483633
135    } else if cfg!(target_os = "hurd") {
136        1073741825
137    } else {
138        1
139    };
140    set_errno(Errno(errno_code));
141
142    assert_eq!(errno().to_string(), expect);
143    assert_eq!(
144        format!("{:?}", errno()),
145        format!(
146            "Errno {{ code: {}, description: Some({:?}) }}",
147            errno_code, expect
148        )
149    );
150}
151
152#[cfg(feature = "std")]
153#[test]
154fn check_error_into_errno() {
155    const ERROR_CODE: i32 = 1;
156
157    let error = io::Error::from_raw_os_error(ERROR_CODE);
158    let new_error: io::Error = Errno(ERROR_CODE).into();
159    assert_eq!(error.kind(), new_error.kind());
160}