1#![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#[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
59pub fn errno() -> Errno { Errno(errno_raw()) }
61
62pub 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}