Skip to main content

fromsoftware_shared/
empty.rs

1use std::{fmt, iter::FusedIterator, mem::MaybeUninit, ops::Drop, ptr::NonNull};
2
3/// A wrapper type to represent an instance of a type `T` that may be in a
4/// well-known "empty" state where its usual guarantees aren't upheld.
5///
6/// This is similar to [MaybeUninit] in that it ensures that the underlying
7/// structure isn't accessed until we're confident it's valid, but it's
8/// different in that the memory is actually initialized. It's just initialized
9/// to a known pattern that indicates an empty or null value. The specific
10/// pattern differs from type to type; individual types implement the [IsEmpty]
11/// trait to determine when the structure is valid.
12///
13/// This is also similar to [Option]. The main difference is that this is usable
14/// for complex structs defined in C++, while [Option] is only usable for
15/// pointers and Rust structs.
16#[repr(transparent)]
17// Ideally this would be a union, but transparent unions aren't stable yet, so
18// we use the std-defined MaybeUninit instead as a workaround.
19pub struct MaybeEmpty<T>(MaybeUninit<T>)
20where
21    T: IsEmpty;
22
23/// Implement this trait for a type to allow it to be used with [MaybeEmpty].
24///
25/// ## Safety
26///
27/// Implementors must guarantee that if [is_empty](Self::is_empty) returns true
28/// for a given `MaybeEmpty<T>`, that value meets all the requirements for a
29/// value of type `T`. They must also guarantee that no code needs to be run to
30/// drop an empty `MaybeEmpty<T>`.
31pub unsafe trait IsEmpty: Sized {
32    /// Returns whether the given `value` is "empty" according to its own
33    /// internal logic.
34    fn is_empty(value: &MaybeEmpty<Self>) -> bool;
35}
36
37impl<T> MaybeEmpty<T>
38where
39    T: IsEmpty,
40{
41    /// Creates a new [MaybeEmpty] initialized with the given value.
42    pub fn new(value: T) -> MaybeEmpty<T> {
43        MaybeEmpty(MaybeUninit::new(value))
44    }
45
46    /// Returns whether this struct is "empty" according to its own internal
47    /// logic.
48    pub fn is_empty(&self) -> bool {
49        IsEmpty::is_empty(self)
50    }
51
52    /// Gets a pointer to the contained value. Reading from this pointer is
53    /// unsafe but well-defined, since the underlying memory will either be
54    /// a valid `T` *or* match the well-known empty pattern.
55    pub fn as_non_null(&self) -> NonNull<T> {
56        NonNull::from_ref(self).cast::<T>()
57    }
58
59    /// If this isn't empty, returns it. Otherwise, returns `None`.
60    pub fn as_option(&self) -> Option<&T> {
61        if self.is_empty() {
62            None
63        } else {
64            // Safety: IsEmpty guarantees that this is safe.
65            Some(unsafe { self.as_non_null().as_ref() })
66        }
67    }
68
69    /// If this isn't empty, returns it. Otherwise, returns `None`.
70    pub fn as_option_mut(&mut self) -> Option<&mut T> {
71        if self.is_empty() {
72            None
73        } else {
74            // Safety: IsEmpty guarantees that this is safe.
75            Some(unsafe { self.as_non_null().as_mut() })
76        }
77    }
78}
79
80impl<T> fmt::Debug for MaybeEmpty<T>
81where
82    T: IsEmpty + fmt::Debug,
83{
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        if let Some(value) = self.as_option() {
86            value.fmt(f)
87        } else {
88            write!(f, "<empty>")
89        }
90    }
91}
92
93impl<T> From<T> for MaybeEmpty<T>
94where
95    T: IsEmpty,
96{
97    fn from(value: T) -> MaybeEmpty<T> {
98        MaybeEmpty(MaybeUninit::new(value))
99    }
100}
101
102impl<T> Drop for MaybeEmpty<T>
103where
104    T: IsEmpty,
105{
106    fn drop(&mut self) {
107        if self.is_empty() {
108            unsafe { self.0.assume_init_drop() };
109        }
110    }
111}
112
113/// An iterator adapter that omits empty elements.
114pub struct NonEmptyIter<'a, E, I>(I)
115where
116    E: IsEmpty + 'a,
117    I: Iterator<Item = &'a MaybeEmpty<E>>;
118
119impl<'a, E, I> Iterator for NonEmptyIter<'a, E, I>
120where
121    E: IsEmpty + 'a,
122    I: Iterator<Item = &'a MaybeEmpty<E>>,
123{
124    type Item = &'a E;
125
126    fn next(&mut self) -> Option<Self::Item> {
127        loop {
128            match self.0.next() {
129                Some(entry) => {
130                    if let Some(entry) = entry.as_option() {
131                        return Some(entry);
132                    }
133                }
134                None => return None,
135            }
136        }
137    }
138}
139
140impl<'a, E, I> FusedIterator for NonEmptyIter<'a, E, I>
141where
142    E: IsEmpty + 'a,
143    I: Iterator<Item = &'a MaybeEmpty<E>> + FusedIterator,
144{
145}
146
147/// An extension trait to add the [non_empty](Self::non_empty) method to
148/// iterators of [MaybeEmpty] values.
149pub trait NonEmptyIteratorExt<'a, E>: Iterator<Item = &'a MaybeEmpty<E>>
150where
151    E: IsEmpty + 'a,
152    Self: Sized,
153{
154    /// Filters out any empty values from this iterator.
155    fn non_empty(self) -> NonEmptyIter<'a, E, Self>;
156}
157
158impl<'a, E, I> NonEmptyIteratorExt<'a, E> for I
159where
160    E: IsEmpty + 'a,
161    I: Iterator<Item = &'a MaybeEmpty<E>> + Sized,
162{
163    fn non_empty(self) -> NonEmptyIter<'a, E, Self> {
164        NonEmptyIter(self)
165    }
166}
167
168/// A mutable iterator adapter that omits empty elements.
169pub struct NonEmptyIterMut<'a, E, I>(I)
170where
171    E: IsEmpty + 'a,
172    I: Iterator<Item = &'a mut MaybeEmpty<E>>;
173
174impl<'a, E, I> Iterator for NonEmptyIterMut<'a, E, I>
175where
176    E: IsEmpty + 'a,
177    I: Iterator<Item = &'a mut MaybeEmpty<E>>,
178{
179    type Item = &'a mut E;
180
181    fn next(&mut self) -> Option<Self::Item> {
182        loop {
183            match self.0.next() {
184                Some(entry) => {
185                    if let Some(entry) = entry.as_option_mut() {
186                        return Some(entry);
187                    }
188                }
189                None => return None,
190            }
191        }
192    }
193}
194
195/// An extension trait to add the [non_empty](Self::non_empty) method to
196/// iterators of [MaybeEmpty] values.
197pub trait NonEmptyIteratorMutExt<'a, E>: Iterator<Item = &'a mut MaybeEmpty<E>>
198where
199    E: IsEmpty + 'a,
200    Self: Sized,
201{
202    /// Filters out any empty values from this iterator.
203    fn non_empty(self) -> NonEmptyIterMut<'a, E, Self>;
204}
205
206impl<'a, E, I> NonEmptyIteratorMutExt<'a, E> for I
207where
208    E: IsEmpty + 'a,
209    I: Iterator<Item = &'a mut MaybeEmpty<E>> + Sized,
210{
211    fn non_empty(self) -> NonEmptyIterMut<'a, E, Self> {
212        NonEmptyIterMut(self)
213    }
214}