ntr-io 0.0.1

Idiomatic NT APIs on Rust (I/O)
use super as io;
use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use super::win::*;
use core::fmt;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ptr;

#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct BorrowedHandle<'handle> {
    handle: RawHandle,
    _phantom: PhantomData<&'handle OwnedHandle>,
}

#[repr(transparent)]
pub struct OwnedHandle {
    handle: RawHandle,
}

#[repr(transparent)]
#[derive(Debug)]
pub struct HandleOrNull(RawHandle);

#[repr(transparent)]
#[derive(Debug)]
pub struct HandleOrInvalid(RawHandle);

unsafe impl Send for OwnedHandle {}
unsafe impl Send for HandleOrNull {}
unsafe impl Send for HandleOrInvalid {}
unsafe impl Send for BorrowedHandle<'_> {}
unsafe impl Sync for OwnedHandle {}
unsafe impl Sync for HandleOrNull {}
unsafe impl Sync for HandleOrInvalid {}
unsafe impl Sync for BorrowedHandle<'_> {}

impl BorrowedHandle<'_> {
    #[inline]
    pub const unsafe fn borrow_raw(handle: RawHandle) -> Self {
        Self {
            handle,
            _phantom: PhantomData,
        }
    }
}

impl TryFrom<HandleOrNull> for OwnedHandle {
    type Error = NullHandleError;

    #[inline]
    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
        let handle_or_null = ManuallyDrop::new(handle_or_null);
        if handle_or_null.is_valid() {
            Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_null.0) })
        } else {
            Err(NullHandleError(()))
        }
    }
}

impl Drop for HandleOrNull {
    #[inline]
    fn drop(&mut self) {
        if self.is_valid() {
            unsafe {
                let _ = CloseHandle(self.0.as_windows_handle());
            }
        }
    }
}

impl OwnedHandle {
    pub fn try_clone(&self) -> io::Result<Self> {
        self.as_handle().try_clone_to_owned()
    }
}

impl BorrowedHandle<'_> {
    pub fn try_clone_to_owned(&self) -> io::Result<OwnedHandle> {
        self.duplicate(0, false, DUPLICATE_SAME_ACCESS.0)
    }

    pub(crate) fn duplicate(
        &self,
        access: u32,
        inherit: bool,
        options: u32,
    ) -> io::Result<OwnedHandle> {
        let handle = self.as_raw_handle();

        if handle.is_null() {
            return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) };
        }

        let mut ret = ptr::null_mut();
        unsafe {
            let cur_proc = GetCurrentProcess();
            DuplicateHandle(
                cur_proc,
                handle.as_windows_handle(),
                cur_proc,
                &mut ret as *mut _ as *mut _,
                access,
                inherit,
                DUPLICATE_HANDLE_OPTIONS(options),
            )?
        };
        unsafe { Ok(OwnedHandle::from_raw_handle(ret)) }
    }
}

impl TryFrom<HandleOrInvalid> for OwnedHandle {
    type Error = InvalidHandleError;

    #[inline]
    fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
        let handle_or_invalid = ManuallyDrop::new(handle_or_invalid);
        if handle_or_invalid.is_valid() {
            Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_invalid.0) })
        } else {
            Err(InvalidHandleError(()))
        }
    }
}

impl Drop for HandleOrInvalid {
    #[inline]
    fn drop(&mut self) {
        if self.is_valid() {
            unsafe {
                let _ = CloseHandle(self.0.as_windows_handle());
            }
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NullHandleError(());

impl fmt::Display for NullHandleError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt)
    }
}

impl core::error::Error for NullHandleError {}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidHandleError(());

impl fmt::Display for InvalidHandleError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE"
            .fmt(fmt)
    }
}

impl core::error::Error for InvalidHandleError {}

impl AsRawHandle for BorrowedHandle<'_> {
    #[inline]
    fn as_raw_handle(&self) -> RawHandle {
        self.handle
    }
}

impl AsRawHandle for OwnedHandle {
    #[inline]
    fn as_raw_handle(&self) -> RawHandle {
        self.handle
    }
}

impl IntoRawHandle for OwnedHandle {
    #[inline]
    fn into_raw_handle(self) -> RawHandle {
        ManuallyDrop::new(self).handle
    }
}

impl FromRawHandle for OwnedHandle {
    #[inline]
    unsafe fn from_raw_handle(handle: RawHandle) -> Self {
        Self { handle }
    }
}

impl HandleOrNull {
    #[inline]
    pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
        Self(handle)
    }

    fn is_valid(&self) -> bool {
        !self.0.is_null()
    }
}

impl HandleOrInvalid {
    #[inline]
    pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
        Self(handle)
    }

    fn is_valid(&self) -> bool {
        self.0.as_windows_handle() != INVALID_HANDLE_VALUE
    }
}

impl Drop for OwnedHandle {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let _ = CloseHandle(self.handle.as_windows_handle());
        }
    }
}

impl fmt::Debug for BorrowedHandle<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BorrowedHandle")
            .field("handle", &self.handle)
            .finish()
    }
}

impl fmt::Debug for OwnedHandle {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("OwnedHandle")
            .field("handle", &self.handle)
            .finish()
    }
}

pub trait AsHandle {
    fn as_handle(&self) -> BorrowedHandle<'_>;
}

impl<T: AsHandle + ?Sized> AsHandle for &T {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        T::as_handle(self)
    }
}

impl<T: AsHandle + ?Sized> AsHandle for &mut T {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        T::as_handle(self)
    }
}

#[cfg(any(feature = "alloc"))]
impl<T: AsHandle + ?Sized> AsHandle for alloc::sync::Arc<T> {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        (**self).as_handle()
    }
}

#[cfg(feature = "alloc")]
impl<T: AsHandle + ?Sized> AsHandle for alloc::rc::Rc<T> {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        (**self).as_handle()
    }
}

#[cfg(feature = "nightly")]
#[cfg(feature = "alloc")]
impl<T: AsHandle + ?Sized> AsHandle for alloc::rc::UniqueRc<T> {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        (**self).as_handle()
    }
}

impl<T: AsHandle + ?Sized> AsHandle for Box<T> {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        (**self).as_handle()
    }
}

impl AsHandle for BorrowedHandle<'_> {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        *self
    }
}

impl AsHandle for OwnedHandle {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
    }
}