diff options
Diffstat (limited to 'engine/src/util.rs')
-rw-r--r-- | engine/src/util.rs | 73 |
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; |