//! Cross-platform interface to the `errno` variable. //! //! # Examples //! ``` //! use errno::{Errno, errno, set_errno}; //! //! // Get the current value of errno //! let e = errno(); //! //! // Set the current value of errno //! set_errno(e); //! //! // Extract the error code as an i32 //! let code = e.0; //! //! // Display a human-friendly error message //! println!("Error {}: {}", code, e); //! ``` #![cfg_attr(target_os = "wasi", feature(thread_local))] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(unix)] extern crate libc; #[cfg(windows)] extern crate winapi; #[cfg(target_os = "dragonfly")] extern crate errno_dragonfly; #[cfg(target_os = "wasi")] extern crate libc; #[cfg(target_os = "hermit")] extern crate libc; #[cfg_attr(unix, path = "unix.rs")] #[cfg_attr(windows, path = "windows.rs")] #[cfg_attr(target_os = "wasi", path = "wasi.rs")] #[cfg_attr(target_os = "hermit", path = "hermit.rs")] mod sys; #[cfg(feature = "std")] use std::fmt; #[cfg(feature = "std")] use std::io; #[cfg(feature = "std")] use std::error::Error; /// Wraps a platform-specific error code. /// /// The `Display` instance maps the code to a human-readable string. It /// calls [`strerror_r`][1] under POSIX, and [`FormatMessageW`][2] on /// Windows. /// /// [1]: http://pubs.opengroup.org/onlinepubs/009695399/functions/strerror.html /// [2]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351%28v=vs.85%29.aspx #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Errno(pub i32); #[cfg(feature = "std")] impl fmt::Debug for Errno { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { sys::with_description(*self, |desc| { fmt.debug_struct("Errno") .field("code", &self.0) .field("description", &desc.ok()) .finish() }) } } #[cfg(feature = "std")] impl fmt::Display for Errno { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { sys::with_description(*self, |desc| match desc { Ok(desc) => fmt.write_str(&desc), Err(fm_err) => write!( fmt, "OS error {} ({} returned error {})", self.0, sys::STRERROR_NAME, fm_err.0), }) } } impl Into for Errno { fn into(self) -> i32 { self.0 } } #[cfg(feature = "std")] impl Error for Errno { // TODO: Remove when MSRV >= 1.27 #[allow(deprecated)] fn description(&self) -> &str { "system error" } } #[cfg(feature = "std")] impl From for io::Error { fn from(errno: Errno) -> Self { io::Error::from_raw_os_error(errno.0) } } /// Returns the platform-specific value of `errno`. pub fn errno() -> Errno { sys::errno() } /// Sets the platform-specific value of `errno`. pub fn set_errno(err: Errno) { sys::set_errno(err) } #[test] fn it_works() { let x = errno(); set_errno(x); } #[cfg(feature = "std")] #[test] fn it_works_with_to_string() { let x = errno(); let _ = x.to_string(); } #[cfg(feature = "std")] #[test] fn check_description() { let expect = if cfg!(windows) { "Incorrect function." } else if cfg!(target_os = "illumos") { "Not owner" } else if cfg!(target_os = "wasi") { "Argument list too long" } else { "Operation not permitted" }; set_errno(Errno(1)); assert_eq!(errno().to_string(), expect); assert_eq!( format!("{:?}", errno()), format!("Errno {{ code: 1, description: Some({:?}) }}", expect)); } #[cfg(feature = "std")] #[test] fn check_error_into_errno() { const ERROR_CODE: i32 = 1; let error = io::Error::from_raw_os_error(ERROR_CODE); let new_error: io::Error = Errno(ERROR_CODE).into(); assert_eq!(error.kind(), new_error.kind()); }