cc/
utilities.rs

1use std::{
2    cell::UnsafeCell,
3    ffi::OsStr,
4    fmt::{self, Write},
5    marker::PhantomData,
6    mem::MaybeUninit,
7    panic::{RefUnwindSafe, UnwindSafe},
8    path::Path,
9    sync::Once,
10};
11
12pub(super) struct JoinOsStrs<'a, T> {
13    pub(super) slice: &'a [T],
14    pub(super) delimiter: char,
15}
16
17impl<T> fmt::Display for JoinOsStrs<'_, T>
18where
19    T: AsRef<OsStr>,
20{
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        let len = self.slice.len();
23        for (index, os_str) in self.slice.iter().enumerate() {
24            // TODO: Use OsStr::display once it is stablised,
25            // Path and OsStr has the same `Display` impl
26            write!(f, "{}", Path::new(os_str).display())?;
27            if index + 1 < len {
28                f.write_char(self.delimiter)?;
29            }
30        }
31        Ok(())
32    }
33}
34
35pub(super) struct OptionOsStrDisplay<T>(pub(super) Option<T>);
36
37impl<T> fmt::Display for OptionOsStrDisplay<T>
38where
39    T: AsRef<OsStr>,
40{
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        // TODO: Use OsStr::display once it is stablised
43        // Path and OsStr has the same `Display` impl
44        if let Some(os_str) = self.0.as_ref() {
45            write!(f, "Some({})", Path::new(os_str).display())
46        } else {
47            f.write_str("None")
48        }
49    }
50}
51
52pub(crate) struct OnceLock<T> {
53    once: Once,
54    value: UnsafeCell<MaybeUninit<T>>,
55    _marker: PhantomData<T>,
56}
57
58impl<T> Default for OnceLock<T> {
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64impl<T> OnceLock<T> {
65    pub(crate) const fn new() -> Self {
66        Self {
67            once: Once::new(),
68            value: UnsafeCell::new(MaybeUninit::uninit()),
69            _marker: PhantomData,
70        }
71    }
72
73    #[inline]
74    fn is_initialized(&self) -> bool {
75        self.once.is_completed()
76    }
77
78    unsafe fn get_unchecked(&self) -> &T {
79        debug_assert!(self.is_initialized());
80        #[allow(clippy::needless_borrow)]
81        #[allow(unused_unsafe)]
82        unsafe {
83            (&*self.value.get()).assume_init_ref()
84        }
85    }
86
87    pub(crate) fn get_or_init(&self, f: impl FnOnce() -> T) -> &T {
88        self.once.call_once(|| {
89            unsafe { &mut *self.value.get() }.write(f());
90        });
91        unsafe { self.get_unchecked() }
92    }
93
94    pub(crate) fn get(&self) -> Option<&T> {
95        if self.is_initialized() {
96            // Safe b/c checked is_initialized
97            Some(unsafe { self.get_unchecked() })
98        } else {
99            None
100        }
101    }
102}
103
104impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        let mut d = f.debug_tuple("OnceLock");
107        match self.get() {
108            Some(v) => d.field(v),
109            None => d.field(&format_args!("<uninit>")),
110        };
111        d.finish()
112    }
113}
114
115unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
116unsafe impl<T: Send> Send for OnceLock<T> {}
117
118impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
119impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
120
121impl<T> Drop for OnceLock<T> {
122    #[inline]
123    fn drop(&mut self) {
124        if self.once.is_completed() {
125            // SAFETY: The cell is initialized and being dropped, so it can't
126            // be accessed again.
127            unsafe { self.value.get_mut().assume_init_drop() };
128        }
129    }
130}