interprocess 2.2.2

Interprocess communication toolkit
Documentation
#![allow(dead_code)]

#[cfg(unix)]
use std::os::unix::io::RawFd;
use std::{
	io,
	mem::{transmute, MaybeUninit},
	num::Saturating,
	pin::Pin,
	sync::PoisonError,
};
#[cfg(windows)]
use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};

/// Utility trait that, if used as a supertrait, prevents other crates from implementing the
/// trait.
pub(crate) trait Sealed {}
pub(crate) trait DebugExpectExt: Sized {
	fn debug_expect(self, msg: &str);
}

pub(crate) static LOCK_POISON: &str = "unexpected lock poison";
pub(crate) fn poison_error<T>(_: PoisonError<T>) -> io::Error {
	io::Error::other(LOCK_POISON)
}

pub(crate) trait OrErrno<T>: Sized {
	fn true_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T>;
	#[inline(always)]
	fn true_val_or_errno(self, value: T) -> io::Result<T> {
		self.true_or_errno(|| value)
	}
	fn false_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T>;
	#[inline(always)]
	fn false_val_or_errno(self, value: T) -> io::Result<T> {
		self.true_or_errno(|| value)
	}
}
impl<B: ToBool, T> OrErrno<T> for B {
	#[inline]
	fn true_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T> {
		if self.to_bool() {
			Ok(f())
		} else {
			Err(io::Error::last_os_error())
		}
	}
	fn false_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T> {
		if !self.to_bool() {
			Ok(f())
		} else {
			Err(io::Error::last_os_error())
		}
	}
}

#[cfg(unix)]
pub(crate) trait FdOrErrno: Sized {
	fn fd_or_errno(self) -> io::Result<Self>;
}
#[cfg(unix)]
impl FdOrErrno for RawFd {
	#[inline]
	fn fd_or_errno(self) -> io::Result<Self> {
		(self != -1).true_val_or_errno(self)
	}
}

#[cfg(windows)]
pub(crate) trait HandleOrErrno: Sized {
	fn handle_or_errno(self) -> io::Result<Self>;
}
#[cfg(windows)]
impl HandleOrErrno for HANDLE {
	#[inline]
	fn handle_or_errno(self) -> io::Result<Self> {
		(self != INVALID_HANDLE_VALUE).true_val_or_errno(self)
	}
}

pub(crate) trait ToBool {
	fn to_bool(self) -> bool;
}
impl ToBool for bool {
	#[inline(always)]
	fn to_bool(self) -> bool {
		self
	}
}
impl ToBool for i32 {
	#[inline(always)]
	fn to_bool(self) -> bool {
		self != 0
	}
}

pub(crate) trait BoolExt {
	fn to_i32(self) -> i32;
	fn to_usize(self) -> usize;
}
impl BoolExt for bool {
	#[inline(always)] #[rustfmt::skip] // oh come on now
	fn to_i32(self) -> i32 {
		if self { 1 } else { 0 }
	}
	#[inline(always)] #[rustfmt::skip]
	fn to_usize(self) -> usize {
		if self { 1 } else { 0 }
	}
}

pub(crate) trait AsPtr {
	#[inline(always)]
	fn as_ptr(&self) -> *const Self {
		self
	}
}
impl<T: ?Sized> AsPtr for T {}

pub(crate) trait AsMutPtr {
	#[inline(always)]
	fn as_mut_ptr(&mut self) -> *mut Self {
		self
	}
}
impl<T: ?Sized> AsMutPtr for T {}

impl<T, E: std::fmt::Debug> DebugExpectExt for Result<T, E> {
	#[inline]
	#[track_caller]
	fn debug_expect(self, msg: &str) {
		if cfg!(debug_assertions) {
			self.expect(msg);
		}
	}
}
impl<T> DebugExpectExt for Option<T> {
	#[inline]
	#[track_caller]
	fn debug_expect(self, msg: &str) {
		if cfg!(debug_assertions) {
			self.expect(msg);
		}
	}
}

pub(crate) trait NumExt: Sized {
	#[inline]
	fn saturate(self) -> Saturating<Self> {
		Saturating(self)
	}
}
impl<T> NumExt for T {}

pub(crate) trait SubUsizeExt: TryInto<usize> + Sized {
	fn to_usize(self) -> usize;
}
pub(crate) trait SubIsizeExt: TryInto<usize> + Sized {
	fn to_isize(self) -> isize;
}
macro_rules! impl_subsize {
	($src:ident to usize) => {
		impl SubUsizeExt for $src {
			#[inline(always)]
			#[allow(clippy::as_conversions)]
			fn to_usize(self) -> usize {
				self as usize
			}
		}
	};
	($src:ident to isize) => {
		impl SubIsizeExt for $src {
			#[inline(always)]
			#[allow(clippy::as_conversions)]
			fn to_isize(self) -> isize {
				self as isize
			}
		}
	};
	($($src:ident to $dst:ident)+) => {$(
		impl_subsize!($src to $dst);
	)+};
}
// See platform_check.rs.
impl_subsize! {
	u8	to usize
	u16	to usize
	u32	to usize
	i8	to isize
	i16	to isize
	i32	to isize
	u8	to isize
	u16	to isize
}

// TODO(2.3.0) find a more elegant way
pub(crate) trait RawOsErrorExt {
	fn eeq(self, other: u32) -> bool;
}
impl RawOsErrorExt for Option<i32> {
	#[inline(always)]
	#[allow(clippy::as_conversions)]
	fn eeq(self, other: u32) -> bool {
		match self {
			Some(n) => n as u32 == other,
			None => false,
		}
	}
}

#[inline(always)]
pub(crate) fn weaken_buf_init<T>(r: &[T]) -> &[MaybeUninit<T>] {
	unsafe {
		// SAFETY: same slice, weaker refinement
		transmute(r)
	}
}
#[inline(always)]
pub(crate) fn weaken_buf_init_mut<T>(r: &mut [T]) -> &mut [MaybeUninit<T>] {
	unsafe {
		// SAFETY: same here
		transmute(r)
	}
}

#[inline(always)]
pub(crate) unsafe fn assume_slice_init<T>(r: &[MaybeUninit<T>]) -> &[T] {
	unsafe {
		// SAFETY: same slice, stronger refinement
		transmute(r)
	}
}

pub(crate) trait UnpinExt: Unpin {
	#[inline]
	fn pin(&mut self) -> Pin<&mut Self> {
		Pin::new(self)
	}
}
impl<T: Unpin + ?Sized> UnpinExt for T {}