errno-no-std 0.2.2

Cross-platform interface to the `errno` variable.
Documentation
use core::fmt::{self, Formatter};
use core::ptr::{null, null_mut};
use core::slice::{self};
use widestring::U16Str;
use winapi::shared::minwindef::{DWORD, LPVOID};
use winapi::shared::ntdef::{LANG_NEUTRAL, LPWSTR, MAKELANGID, SUBLANG_DEFAULT};
use winapi::um::errhandlingapi::{GetLastError, SetLastError};
use winapi::um::winbase::*;

struct Buf(LPWSTR);

impl Drop for Buf {
    fn drop(&mut self) {
        unsafe { LocalFree(self.0 as LPVOID) };
    }
}

pub fn errno_fmt(e: i32, f: &mut Formatter) -> fmt::Result {
    let mut buf: LPWSTR = null_mut();
    let msg_len = unsafe { FormatMessageW(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        null(),
        e as DWORD,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as _,
        &mut buf as *mut _ as LPWSTR,
        0,
        null_mut()
    ) };
    if msg_len == 0 {
        return write!(f, "error 0x{:04x}", e as DWORD);
    }
    let buf = Buf(buf);
    let msg = unsafe { slice::from_raw_parts(buf.0, msg_len as usize) };
    let trim = msg.iter().copied().rev().take_while(|&w| w == b'\r' as u16 || w == b'\n' as u16).count();
    let msg = U16Str::from_slice(&msg[.. msg.len() - trim]);
    write!(f, "{}", msg.display())
}

pub fn errno_raw() -> i32 { 
    (unsafe { GetLastError() }) as i32
}

pub fn set_errno_raw(e: i32) {
    unsafe { SetLastError(e as DWORD) }
}