#![no_std]
use core::fmt;
use core::result;
use core::str;
pub type Result<T> = result::Result<T, Error>;
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Error {
pub errno: i32,
}
impl Error {
pub const fn new(errno: i32) -> Self {
Self { errno }
}
pub fn last() -> Self {
Self { errno: errno() }
}
}
impl Default for Error {
fn default() -> Self {
Error::new(-1)
}
}
impl From<i32> for Error {
fn from(i32: i32) -> Self {
Self::new(i32)
}
}
impl From<Error> for Result<()> {
fn from(err: Error) -> Self {
if err.errno == 0 {
Ok(())
} else {
Err(err)
}
}
}
const ERRMSG_MAX_SIZE: usize = 64;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> {
let mut msg = [0_u8; ERRMSG_MAX_SIZE];
write!(f, "{}: {}", self.errno, errmsg(self.errno, &mut msg[..]))
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> {
let mut msg = [0_u8; ERRMSG_MAX_SIZE];
write!(f, "{}: {}", self.errno, errmsg(self.errno, &mut msg[..]))
}
}
#[cfg(any(unix, all(target_os = "windows", target_env = "gnu")))]
fn format_message_utf8<'a>(input: &[u8], output: &'a mut [u8]) -> &'a str {
let Ok(s) = str::from_utf8(input) else {
return get_message(output, 0);
};
if input.len() <= output.len() {
output[..input.len()].copy_from_slice(input);
return str::from_utf8(&output[..input.len()]).unwrap();
}
return truncate_message(s, output);
}
#[cfg(any(unix, all(target_os = "windows", target_env = "gnu")))]
fn truncate_message<'a>(input: &str, output: &'a mut [u8]) -> &'a str {
let mut pos = 0;
for c in input.chars() {
if !put_message(output, &mut pos, c) {
break;
}
}
get_message(output, pos)
}
fn put_message(output: &mut [u8], pos: &mut usize, c: char) -> bool {
if *pos + c.len_utf8() <= output.len() {
c.encode_utf8(&mut output[*pos..]);
*pos += c.len_utf8();
return true;
}
false
}
fn get_message(output: &[u8], len: usize) -> &str {
if len > 0 {
str::from_utf8(&output[..len]).unwrap()
} else {
"Unknown error"
}
}
#[cfg(all(target_os = "windows", not(target_env = "gnu")))]
fn format_message_utf16<'a>(input: &[u16], output: &'a mut [u8]) -> &'a str {
let mut pos = 0;
char::decode_utf16(input.iter().copied()).any(|c| {
let Ok(c) = c else {
pos = 0;
return true;
};
!put_message(output, &mut pos, c)
});
get_message(output, pos)
}
#[cfg(any(unix, all(target_os = "windows", target_env = "gnu")))]
mod unix;
#[cfg(any(unix, all(target_os = "windows", target_env = "gnu")))]
pub use unix::*;
#[cfg(all(target_os = "windows", not(target_env = "gnu")))]
mod windows;
#[cfg(all(target_os = "windows", not(target_env = "gnu")))]
pub use windows::*;
#[cfg(test)]
mod test {
use super::*;
extern crate std;
use std::println;
#[test]
fn test_errno() {
set_errno(100);
assert_eq!(errno(), 100);
}
#[test]
fn test_print() {
for n in 0..=102 {
let err = Error::new(n);
println!("[{}]\n[{:?}]\n", err, err);
}
set_errno(4);
println!("5: {}", errmsg(5, &mut [0_u8; 7]));
}
}