hun_error/
lib.rs

1//! 包装OS的错误码, 统一错误码的查询和获取接口
2//! 1. fn errno() -> i32;
3//! 2. fn set_errno(i32);
4//! 3. unsafe fn errmsg(i32) -> &str;
5//!
6//! 封装i32为Error
7//!
8//! # Example
9//! ```rust
10//! use hun_error::*;
11//!
12//! set_errno(100);
13//! let err = Error::last_error();
14//! assert_eq!(err, 100.into());
15//! ```
16
17
18#![no_std]
19
20use core::fmt;
21use core::slice;
22use core::str;
23
24#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
25#[repr(transparent)]
26pub struct Error {
27    pub errno: i32,
28}
29
30impl Error {
31    pub const fn new(errno: i32) -> Self {
32        Self { errno }
33    }
34    pub fn last_error() -> Self {
35        Self { errno: errno() }
36    }
37}
38
39impl Default for Error {
40    fn default() -> Self {
41        Error::new(-1)
42    }
43}
44
45impl From<i32> for Error {
46    fn from(i32: i32) -> Self {
47        Self::new(i32)
48    }
49}
50
51impl From<Error> for Result<(), Error> {
52    fn from(err: Error) -> Self {
53        if err.errno == 0 {
54            Ok(())
55        } else {
56            Err(err)
57        }
58    }
59}
60
61impl fmt::Display for Error {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
63        write!(f, "{}, {}", self.errno, unsafe { errmsg(self.errno) })
64    }
65}
66
67impl fmt::Debug for Error {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
69        write!(f, "{}, {}", self.errno, unsafe { errmsg(self.errno) })
70    }
71}
72
73cfg_if::cfg_if! {
74    if #[cfg(unix)] {
75        #[link(name = "c")]
76        extern "C" {
77            #[cfg(any(
78                target_os = "linux",
79                target_os = "redox",
80                target_os = "dragonfly",
81                target_os = "fuchsia"
82            ))]
83            #[link_name = "__errno_location"]
84            fn errno_location() -> *mut i32;
85        
86            #[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))]
87            #[link_name = "__errno"]
88            fn errno_location() -> *mut i32;
89
90            #[cfg(any(target_os = "ios", target_os = "macos", target_os = "freebsd"))]
91            #[link_name = "__error"]
92            fn errno_location() -> *mut i32;
93        
94            #[cfg(any(target_os = "illumos", target_os = "solaris"))]
95            #[link_name = "___errno"]
96            fn errno_location() -> *mut i32;
97        
98            #[cfg(any(target_os = "haiku"))]
99            #[link_name = "_errnop"]
100            fn errno_location() -> *mut i32;
101
102            fn strerror(errno: i32) -> *const u8;
103            fn strlen(s: *const u8) -> usize;
104        }
105
106        pub fn errno() -> i32 {
107            // # Safety
108            // errno_location总是返回有效地址
109            unsafe { *errno_location() }
110        }
111        
112        pub fn set_errno(errno: i32) {
113            // # Safety
114            // errno_location总是返回有效地址
115            unsafe { *errno_location() = errno };
116        }
117        
118        /// # Safety
119        /// strerror不支持重入, 其内容可能被后续调用修改
120        pub unsafe fn errmsg<'a>(errno: i32) -> &'a str {
121            let s = strerror(errno);
122            let len = strlen(s);
123            str::from_utf8_unchecked(slice::from_raw_parts(s, len))
124        }
125    } else if #[cfg(windows)] {
126        pub fn errmsg<'a>(errno: i32) -> &'a str {
127            "unknown"
128        }
129
130        #[link(name = "Kernel32")]
131        extern "C" {
132            #[link_name = "GetLastError"]
133            pub fn errno() -> i32;
134            #[link_name = "SetLastError"]
135            pub fn set_errno(errno: i32);
136        }
137    }
138}