fromsoftware_shared/
empty.rs

1use std::{fmt, iter::FusedIterator, mem::MaybeUninit, 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`.
30pub unsafe trait IsEmpty: Sized {
31    /// Returns whether the given `value` is "empty" according to its own
32    /// internal logic.
33    fn is_empty(value: &MaybeEmpty<Self>) -> bool;
34}
35
36impl<T> MaybeEmpty<T>
37where
38    T: IsEmpty,
39{
40    /// Returns whether this struct is "empty" according to its own internal
41    /// logic.
42    pub fn is_empty(&self) -> bool {
43        IsEmpty::is_empty(self)
44    }
45
46    /// Gets a pointer to the contained value. Reading from this pointer is
47    /// unsafe but well-defined, since the underlying memory will either be
48    /// a valid `T` *or* match the well-known empty pattern.
49    pub fn as_non_null(&self) -> NonNull<T> {
50        NonNull::from_ref(self).cast::<T>()
51    }
52
53    /// If this isn't empty, returns it. Otherwise, returns `None`.
54    pub fn as_option(&self) -> Option<&T> {
55        if self.is_empty() {
56            None
57        } else {
58            // Safety: IsEmpty guarantees that this is safe.
59            Some(unsafe { self.as_non_null().as_ref() })
60        }
61    }
62
63    /// If this isn't empty, returns it. Otherwise, returns `None`.
64    pub fn as_option_mut(&mut self) -> Option<&mut T> {
65        if self.is_empty() {
66            None
67        } else {
68            // Safety: IsEmpty guarantees that this is safe.
69            Some(unsafe { self.as_non_null().as_mut() })
70        }
71    }
72}
73
74impl<T> fmt::Debug for MaybeEmpty<T>
75where
76    T: IsEmpty + fmt::Debug,
77{
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        if let Some(value) = self.as_option() {
80            value.fmt(f)
81        } else {
82            write!(f, "<empty>")
83        }
84    }
85}
86
87/// An iterator adapter that omits empty elements.
88pub struct NonEmptyIter<'a, E, I>(I)
89where
90    E: IsEmpty + 'a,
91    I: Iterator<Item = &'a MaybeEmpty<E>>;
92
93impl<'a, E, I> Iterator for NonEmptyIter<'a, E, I>
94where
95    E: IsEmpty + 'a,
96    I: Iterator<Item = &'a MaybeEmpty<E>>,
97{
98    type Item = &'a E;
99
100    fn next(&mut self) -> Option<Self::Item> {
101        loop {
102            match self.0.next() {
103                Some(entry) => {
104                    if let Some(entry) = entry.as_option() {
105                        return Some(entry);
106                    }
107                }
108                None => return None,
109            }
110        }
111    }
112}
113
114impl<'a, E, I> FusedIterator for NonEmptyIter<'a, E, I>
115where
116    E: IsEmpty + 'a,
117    I: Iterator<Item = &'a MaybeEmpty<E>> + FusedIterator,
118{
119}
120
121/// An extension trait to add the [non_empty](Self::non_empty) method to
122/// iterators of [MaybeEmpty] values.
123pub trait NonEmptyIteratorExt<'a, E>: Iterator<Item = &'a MaybeEmpty<E>>
124where
125    E: IsEmpty + 'a,
126    Self: Sized,
127{
128    /// Filters out any empty values from this iterator.
129    fn non_empty(self) -> NonEmptyIter<'a, E, Self>;
130}
131
132impl<'a, E, I> NonEmptyIteratorExt<'a, E> for I
133where
134    E: IsEmpty + 'a,
135    I: Iterator<Item = &'a MaybeEmpty<E>> + Sized,
136{
137    fn non_empty(self) -> NonEmptyIter<'a, E, Self> {
138        NonEmptyIter(self)
139    }
140}
141
142/// A mutable iterator adapter that omits empty elements.
143pub struct NonEmptyIterMut<'a, E, I>(I)
144where
145    E: IsEmpty + 'a,
146    I: Iterator<Item = &'a mut MaybeEmpty<E>>;
147
148impl<'a, E, I> Iterator for NonEmptyIterMut<'a, E, I>
149where
150    E: IsEmpty + 'a,
151    I: Iterator<Item = &'a mut MaybeEmpty<E>>,
152{
153    type Item = &'a mut E;
154
155    fn next(&mut self) -> Option<Self::Item> {
156        loop {
157            match self.0.next() {
158                Some(entry) => {
159                    if let Some(entry) = entry.as_option_mut() {
160                        return Some(entry);
161                    }
162                }
163                None => return None,
164            }
165        }
166    }
167}
168
169/// An extension trait to add the [non_empty](Self::non_empty) method to
170/// iterators of [MaybeEmpty] values.
171pub trait NonEmptyIteratorMutExt<'a, E>: Iterator<Item = &'a mut MaybeEmpty<E>>
172where
173    E: IsEmpty + 'a,
174    Self: Sized,
175{
176    /// Filters out any empty values from this iterator.
177    fn non_empty(self) -> NonEmptyIterMut<'a, E, Self>;
178}
179
180impl<'a, E, I> NonEmptyIteratorMutExt<'a, E> for I
181where
182    E: IsEmpty + 'a,
183    I: Iterator<Item = &'a mut MaybeEmpty<E>> + Sized,
184{
185    fn non_empty(self) -> NonEmptyIterMut<'a, E, Self> {
186        NonEmptyIterMut(self)
187    }
188}