errno_no_std/
lib.rs

1//! ## Feature flags
2#![doc=document_features::document_features!()]
3
4#![deny(warnings)]
5#![doc(test(attr(deny(warnings))))]
6#![doc(test(attr(allow(dead_code))))]
7#![doc(test(attr(allow(unused_variables))))]
8#![allow(clippy::unnecessary_cast)]
9
10#![cfg_attr(not(feature="std"), no_std)]
11#[cfg(feature="std")]
12extern crate core;
13
14#[cfg(test)]
15extern crate std;
16
17#[cfg(all(not(windows), not(custom_errno)))]
18mod posix;
19#[cfg(all(not(windows), not(custom_errno)))]
20use posix::*;
21
22#[cfg(all(windows, not(custom_errno)))]
23mod winapi;
24#[cfg(all(windows, not(custom_errno)))]
25use crate::winapi::*;
26
27#[cfg(custom_errno)]
28mod custom;
29#[cfg(custom_errno)]
30use custom::*;
31
32use core::fmt::{self, Formatter};
33#[cfg(feature="std")]
34use std::error::Error;
35#[cfg(feature="std")]
36use std::io::{self};
37
38/// Wraps a platform-specific error code.
39#[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Hash)]
40#[repr(transparent)]
41pub struct Errno(pub i32);
42
43impl fmt::Display for Errno {
44    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
45        errno_fmt(self.0, f)
46    }
47}
48
49#[cfg(feature="std")]
50impl Error for Errno { }
51
52#[cfg(feature="std")]
53impl From<Errno> for io::Error {
54    fn from(e: Errno) -> Self {
55        io::Error::from_raw_os_error(e.0)
56    }
57}
58
59/// Returns the platform-specific value of `errno`.
60pub fn errno() -> Errno { Errno(errno_raw()) }
61
62/// Sets the platform-specific value of `errno`.
63pub fn set_errno(err: Errno) { set_errno_raw(err.0) }
64
65#[cfg(test)]
66mod test {
67    use crate::*;
68    use copy_from_str::CopyFromStrExt;
69    use core::fmt::{Write};
70    use core::str::{self};
71    use quickcheck_macros::quickcheck;
72
73    #[cfg(custom_errno)]
74    mod custom_errno {
75        use std::cell::Cell;
76        use std::fmt::{self, Formatter};
77        use std::thread_local;
78
79        thread_local! {
80            static ERRNO: Cell<i32> = Cell::new(0);
81        }
82
83        #[no_mangle]
84        extern "Rust" fn rust_errno() -> i32 { ERRNO.with(|x| x.get()) }
85
86        #[no_mangle]
87        extern "Rust" fn rust_set_errno(e: i32) {
88            ERRNO.with(|x| x.set(e))
89        }
90
91        #[no_mangle]
92        extern "Rust" fn rust_errno_fmt(e: i32, f: &mut Formatter) -> fmt::Result {
93            write!(f, "Error {}", e)
94        }
95    }
96
97    struct Buf<'a> {
98        s: &'a mut str,
99        len: usize,
100    }
101
102    impl<'a> Write for Buf<'a> {
103        fn write_str(&mut self, s: &str) -> fmt::Result {
104            let advanced_len = self.len.checked_add(s.len()).unwrap();
105            self.s[self.len .. advanced_len].copy_from_str(s);
106            self.len = advanced_len;
107            Ok(())
108        }
109    }
110
111    #[quickcheck]
112    fn errno_after_set_errno(e: i32) -> bool {
113        set_errno(Errno(e));
114        errno() == Errno(e)
115    }
116
117    #[quickcheck]
118    fn error_display(e: i32) -> bool {
119        let mut buf = [0; 1024];
120        let buf = str::from_utf8_mut(&mut buf[..]).unwrap();
121        let mut buf = Buf { s: buf, len: 0 };
122        write!(&mut buf, "{}", Errno(e)).unwrap();
123        let res = &buf.s[.. buf.len];
124        if res.len() <= 5 { return false; }
125        let end = res.chars().last().unwrap();
126        end.is_ascii_alphanumeric() && !end.is_whitespace() || end == '.'
127    }
128}
129
130#[cfg(all(test, not(windows), not(target_os="macos"), not(custom_errno)))]
131mod test_localization {
132    use crate::*;
133    use copy_from_str::CopyFromStrExt;
134    use core::fmt::{Write};
135    use core::str::{self};
136    use libc::{LC_ALL, EACCES, setlocale};
137
138    struct Buf<'a> {
139        s: &'a mut str,
140        len: usize,
141    }
142
143    impl<'a> Write for Buf<'a> {
144        fn write_str(&mut self, s: &str) -> fmt::Result {
145            let advanced_len = self.len.checked_add(s.len()).unwrap();
146            self.s[self.len .. advanced_len].copy_from_str(s);
147            self.len = advanced_len;
148            Ok(())
149        }
150    }
151
152    struct DefaultLocale;
153
154    impl Drop for DefaultLocale {
155        fn drop(&mut self) {
156            unsafe { setlocale(LC_ALL, b"\0".as_ptr() as *const _); }
157        }
158    }
159
160    #[test]
161    fn localized_messages() {
162        let _default_locale = DefaultLocale;
163        let locales: &[&'static [u8]] = &[
164            b"en_US.UTF-8\0",
165            b"ja_JP.EUC-JP\0",
166            b"uk_UA.KOI8-U\0",
167            b"uk_UA.UTF-8\0"
168        ];
169        for &locale in locales {
170            unsafe { setlocale(LC_ALL, locale.as_ptr() as *const _) };
171            let msg = match locale.split(|&b| b == b'.').next().unwrap() {
172                b"en_US" => "Permission denied",
173                b"ja_JP" => "許可がありません",
174                b"uk_UA" => "Відмовлено у доступі",
175                _ => panic!("message?"),
176            };
177            let mut buf = [0; 1024];
178            let buf = str::from_utf8_mut(&mut buf[..]).unwrap();
179            let mut buf = Buf { s: buf, len: 0 };
180            write!(&mut buf, "{}", Errno(EACCES)).unwrap();
181            let res = &buf.s[.. buf.len];
182            assert_eq!(res, msg);
183        }
184    }
185}