interprocess/
misc.rs

1#![allow(dead_code)]
2
3#[cfg(unix)]
4use std::os::unix::io::RawFd;
5use std::{
6    io,
7    mem::{transmute, MaybeUninit},
8    num::Saturating,
9    pin::Pin,
10    sync::PoisonError,
11};
12#[cfg(windows)]
13use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};
14
15/// Utility trait that, if used as a supertrait, prevents other crates from implementing the
16/// trait.
17pub(crate) trait Sealed {}
18pub(crate) trait DebugExpectExt: Sized {
19    fn debug_expect(self, msg: &str);
20}
21
22pub(crate) static LOCK_POISON: &str = "unexpected lock poison";
23pub(crate) fn poison_error<T>(_: PoisonError<T>) -> io::Error { io::Error::other(LOCK_POISON) }
24
25pub(crate) trait OrErrno<T>: Sized {
26    fn true_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T>;
27    #[inline(always)]
28    fn true_val_or_errno(self, value: T) -> io::Result<T> { self.true_or_errno(|| value) }
29    fn false_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T>;
30    #[inline(always)]
31    fn false_val_or_errno(self, value: T) -> io::Result<T> { self.true_or_errno(|| value) }
32}
33impl<B: ToBool, T> OrErrno<T> for B {
34    #[inline]
35    fn true_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T> {
36        if self.to_bool() {
37            Ok(f())
38        } else {
39            Err(io::Error::last_os_error())
40        }
41    }
42    fn false_or_errno(self, f: impl FnOnce() -> T) -> io::Result<T> {
43        if !self.to_bool() {
44            Ok(f())
45        } else {
46            Err(io::Error::last_os_error())
47        }
48    }
49}
50
51#[cfg(unix)]
52pub(crate) trait FdOrErrno: Sized {
53    fn fd_or_errno(self) -> io::Result<Self>;
54}
55#[cfg(unix)]
56impl FdOrErrno for RawFd {
57    #[inline]
58    fn fd_or_errno(self) -> io::Result<Self> { (self != -1).true_val_or_errno(self) }
59}
60
61#[cfg(windows)]
62pub(crate) trait HandleOrErrno: Sized {
63    fn handle_or_errno(self) -> io::Result<Self>;
64}
65#[cfg(windows)]
66impl HandleOrErrno for HANDLE {
67    #[inline]
68    fn handle_or_errno(self) -> io::Result<Self> {
69        (self != INVALID_HANDLE_VALUE).true_val_or_errno(self)
70    }
71}
72
73pub(crate) trait ToBool {
74    fn to_bool(self) -> bool;
75}
76impl ToBool for bool {
77    #[inline(always)]
78    fn to_bool(self) -> bool { self }
79}
80impl ToBool for i32 {
81    #[inline(always)]
82    fn to_bool(self) -> bool { self != 0 }
83}
84
85pub(crate) trait BoolExt {
86    fn to_i32(self) -> i32;
87    fn to_usize(self) -> usize;
88}
89impl BoolExt for bool {
90    #[inline(always)] #[rustfmt::skip] // oh come on now
91    fn to_i32(self) -> i32 {
92        if self { 1 } else { 0 }
93    }
94    #[inline(always)] #[rustfmt::skip]
95    fn to_usize(self) -> usize {
96        if self { 1 } else { 0 }
97    }
98}
99
100pub(crate) trait AsPtr {
101    #[inline(always)]
102    fn as_ptr(&self) -> *const Self { self }
103}
104impl<T: ?Sized> AsPtr for T {}
105
106pub(crate) trait AsMutPtr {
107    #[inline(always)]
108    fn as_mut_ptr(&mut self) -> *mut Self { self }
109}
110impl<T: ?Sized> AsMutPtr for T {}
111
112impl<T, E: std::fmt::Debug> DebugExpectExt for Result<T, E> {
113    #[inline]
114    #[track_caller]
115    fn debug_expect(self, msg: &str) {
116        if cfg!(debug_assertions) {
117            self.expect(msg);
118        }
119    }
120}
121impl<T> DebugExpectExt for Option<T> {
122    #[inline]
123    #[track_caller]
124    fn debug_expect(self, msg: &str) {
125        if cfg!(debug_assertions) {
126            self.expect(msg);
127        }
128    }
129}
130
131pub(crate) trait NumExt: Sized {
132    #[inline]
133    fn saturate(self) -> Saturating<Self> { Saturating(self) }
134}
135impl<T> NumExt for T {}
136
137pub(crate) trait SubUsizeExt: TryInto<usize> + Sized {
138    fn to_usize(self) -> usize;
139}
140pub(crate) trait SubIsizeExt: TryInto<usize> + Sized {
141    fn to_isize(self) -> isize;
142}
143macro_rules! impl_subsize {
144    ($src:ident to usize) => {
145        impl SubUsizeExt for $src {
146            #[inline(always)]
147            #[allow(clippy::as_conversions)]
148            fn to_usize(self) -> usize {
149                self as usize
150            }
151        }
152    };
153    ($src:ident to isize) => {
154        impl SubIsizeExt for $src {
155            #[inline(always)]
156            #[allow(clippy::as_conversions)]
157            fn to_isize(self) -> isize {
158                self as isize
159            }
160        }
161    };
162    ($($src:ident to $dst:ident)+) => {$(
163        impl_subsize!($src to $dst);
164    )+};
165}
166// See platform_check.rs.
167impl_subsize! {
168    u8  to usize
169    u16 to usize
170    u32 to usize
171    i8  to isize
172    i16 to isize
173    i32 to isize
174    u8  to isize
175    u16 to isize
176}
177
178// TODO(2.3.0) find a more elegant way
179pub(crate) trait RawOsErrorExt {
180    fn eeq(self, other: u32) -> bool;
181}
182impl RawOsErrorExt for Option<i32> {
183    #[inline(always)]
184    #[allow(clippy::as_conversions)]
185    fn eeq(self, other: u32) -> bool {
186        match self {
187            Some(n) => n as u32 == other,
188            None => false,
189        }
190    }
191}
192
193#[inline(always)]
194pub(crate) fn weaken_buf_init<T>(r: &[T]) -> &[MaybeUninit<T>] {
195    unsafe {
196        // SAFETY: same slice, weaker refinement
197        transmute(r)
198    }
199}
200#[inline(always)]
201pub(crate) fn weaken_buf_init_mut<T>(r: &mut [T]) -> &mut [MaybeUninit<T>] {
202    unsafe {
203        // SAFETY: same here
204        transmute(r)
205    }
206}
207
208#[inline(always)]
209pub(crate) unsafe fn assume_slice_init<T>(r: &[MaybeUninit<T>]) -> &[T] {
210    unsafe {
211        // SAFETY: same slice, stronger refinement
212        transmute(r)
213    }
214}
215
216pub(crate) trait UnpinExt: Unpin {
217    #[inline]
218    fn pin(&mut self) -> Pin<&mut Self> { Pin::new(self) }
219}
220impl<T: Unpin + ?Sized> UnpinExt for T {}