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.rs111
1 files changed, 83 insertions, 28 deletions
diff --git a/engine/src/util.rs b/engine/src/util.rs
index a505a38..cc4677d 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 {
@@ -26,6 +25,18 @@ macro_rules! or {
pub(crate) use or;
+#[macro_export]
+macro_rules! expand_map_opt {
+ ($in: tt, no_occurance=($($no_occurance: tt)*), occurance=($($occurance: tt)*)) => {
+ $($occurance)*
+ };
+
+ (, no_occurance=($($no_occurance: tt)*), occurance=($($occurance: tt)*)) => {
+ $($no_occurance)*
+ };
+}
+
+#[macro_export]
macro_rules! builder {
(
$(#[doc = $doc: literal])*
@@ -37,7 +48,8 @@ macro_rules! builder {
$visibility: vis struct $name: ident
{
$(
- $(#[$field_attr: meta])*
+ $(#[doc = $field_doc: literal])*
+ $(#[builder(skip_generate_fn$($field_skip_generate_fn: tt)?)])?
$field_visibility: vis $field: ident: $field_type: ty,
)*
}
@@ -47,7 +59,7 @@ macro_rules! builder {
$visibility struct $name
{
$(
- $(#[$field_attr])*
+ $(#[doc = $field_doc])*
$field_visibility $field: $field_type,
)*
}
@@ -63,12 +75,18 @@ macro_rules! builder {
impl $builder_name
{
$(
- #[must_use]
- $visibility fn $field(mut self, $field: $field_type) -> Self
- {
- self.$field = $field;
- self
- }
+ $crate::expand_map_opt!(
+ $(true $($field_skip_generate_fn)?)?,
+ no_occurance=(
+ #[must_use]
+ $visibility fn $field(mut self, $field: $field_type) -> Self
+ {
+ self.$field = $field;
+ self
+ }
+ ),
+ occurance=()
+ );
)*
#[must_use]
@@ -83,6 +101,7 @@ macro_rules! builder {
impl From<$name> for $builder_name
{
+ #[allow(unused_variables)]
fn from(built: $name) -> Self
{
Self {
@@ -95,38 +114,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;