summaryrefslogtreecommitdiff
path: root/engine/src/util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/util.rs')
-rw-r--r--engine/src/util.rs73
1 files changed, 55 insertions, 18 deletions
diff --git a/engine/src/util.rs b/engine/src/util.rs
index a505a38..0f6c78c 100644
--- a/engine/src/util.rs
+++ b/engine/src/util.rs
@@ -1,3 +1,5 @@
+use std::marker::PhantomData;
+
macro_rules! try_option {
($expr: expr) => {
match $expr {
@@ -9,9 +11,6 @@ macro_rules! try_option {
};
}
-use std::mem::ManuallyDrop;
-use std::ops::{Deref, DerefMut};
-
pub(crate) use try_option;
macro_rules! or {
@@ -97,36 +96,74 @@ macro_rules! builder {
pub(crate) use builder;
-/// Wrapper that ensures the contained value will never be dropped.
-#[derive(Debug)]
-pub struct NeverDrop<Value>
+pub enum RefOrValue<'a, T>
{
- value: ManuallyDrop<Value>,
+ Ref(&'a T),
+ Value(Option<T>),
}
-impl<Value> NeverDrop<Value>
+impl<'a, T> RefOrValue<'a, T>
{
- #[must_use]
- pub fn new(value: Value) -> Self
+ pub fn get(&self) -> Option<&T>
{
- Self { value: ManuallyDrop::new(value) }
+ match self {
+ Self::Ref(val_ref) => Some(val_ref),
+ Self::Value(val_cell) => val_cell.as_ref(),
+ }
}
}
-impl<Value> Deref for NeverDrop<Value>
+#[derive(Debug)]
+pub struct Defer<'func, Func, Data>
+where
+ Func: FnMut(&mut Data) + 'func,
{
- type Target = Value;
+ func: Func,
+ pub data: Data,
+ _pd: PhantomData<&'func ()>,
+}
- fn deref(&self) -> &Self::Target
+impl<'func, Func, Data> Defer<'func, Func, Data>
+where
+ Func: FnMut(&mut Data) + 'func,
+{
+ pub fn new(data: Data, func: Func) -> Self
{
- &self.value
+ Self { func, data, _pd: PhantomData }
}
}
-impl<Value> DerefMut for NeverDrop<Value>
+impl<'func, Func, Data> Drop for Defer<'func, Func, Data>
+where
+ Func: FnMut(&mut Data) + 'func,
{
- fn deref_mut(&mut self) -> &mut Self::Target
+ fn drop(&mut self)
{
- &mut self.value
+ (self.func)(&mut self.data)
}
}
+
+/// Defines a function that will be called at the end of the current scope.
+///
+/// Only captured variables that are later mutably borrowed needs to specified as
+/// captures.
+macro_rules! defer {
+ (|$capture: ident| {$($tt: tt)*}) => {
+ // This uses the automatic temporary lifetime extension behaviour introduced
+ // in Rust 1.79.0 (https://blog.rust-lang.org/2024/06/13/Rust-1.79.0.html) to
+ // create a unnamable variable for the Defer struct. The variable should be
+ // unnamable so that it cannot be missused and so that this macro can be used
+ // multiple times without having to give it a identifier for the Defer struct
+ // variable
+ let Defer { data: $capture, .. } = if true {
+ &Defer::new($capture, |$capture| {
+ $($tt)*
+ })
+ }
+ else {
+ unreachable!();
+ };
+ };
+}
+
+pub(crate) use defer;