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.rs270
1 files changed, 222 insertions, 48 deletions
diff --git a/engine/src/util.rs b/engine/src/util.rs
index a505a38..454a776 100644
--- a/engine/src/util.rs
+++ b/engine/src/util.rs
@@ -1,3 +1,195 @@
+use std::fmt::Debug;
+use std::mem::transmute;
+use std::sync::atomic::Ordering;
+
+use portable_atomic::AtomicU128;
+
+use crate::ecs::util::VecExt;
+
+#[derive(Debug)]
+pub struct MapVec<Key: Ord, Value>
+{
+ inner: Vec<(Key, Value)>,
+}
+
+impl<Key: Ord, Value> MapVec<Key, Value>
+{
+ pub fn insert(&mut self, key: Key, value: Value)
+ {
+ self.inner
+ .insert_at_part_pt_by_key((key, value), |(a_key, _)| a_key);
+ }
+
+ pub fn remove(&mut self, key: Key) -> Option<Value>
+ {
+ let index = self
+ .inner
+ .binary_search_by_key(&&key, |(a_key, _)| a_key)
+ .ok()?;
+
+ let (_, value) = self.inner.remove(index);
+
+ Some(value)
+ }
+
+ pub fn get(&self, key: &Key) -> Option<&Value>
+ {
+ let index = self
+ .inner
+ .binary_search_by_key(&key, |(a_key, _)| a_key)
+ .ok()?;
+
+ let Some((_, value)) = self.inner.get(index) else {
+ unreachable!(); // Reason: Index from binary search cannot be OOB
+ };
+
+ Some(value)
+ }
+
+ pub fn get_mut(&mut self, key: &Key) -> Option<&mut Value>
+ {
+ let index = self
+ .inner
+ .binary_search_by_key(&key, |(a_key, _)| a_key)
+ .ok()?;
+
+ let Some((_, value)) = self.inner.get_mut(index) else {
+ unreachable!(); // Reason: Index from binary search cannot be OOB
+ };
+
+ Some(value)
+ }
+
+ pub fn values(&self) -> impl Iterator<Item = &Value>
+ {
+ self.inner.iter().map(|(_, value)| value)
+ }
+}
+
+impl<Key: Ord, Value> Default for MapVec<Key, Value>
+{
+ fn default() -> Self
+ {
+ Self { inner: Vec::new() }
+ }
+}
+
+pub trait OptionExt<T>
+{
+ /// Substitute for the currently experimental function
+ /// [`Option::get_or_try_insert_with`].
+ /// See https://github.com/rust-lang/rust/issues/143648
+ fn get_or_try_insert_with_fn<Err>(
+ &mut self,
+ func: impl Fn() -> Result<T, Err>,
+ ) -> Result<&mut T, Err>;
+}
+
+impl<T> OptionExt<T> for Option<T>
+{
+ fn get_or_try_insert_with_fn<Err>(
+ &mut self,
+ func: impl FnOnce() -> Result<T, Err>,
+ ) -> Result<&mut T, Err>
+ {
+ if let None = self {
+ *self = Some(func()?);
+ }
+
+ Ok(unsafe { self.as_mut().unwrap_unchecked() })
+ }
+}
+
+pub struct AtomicTwoF64
+{
+ inner: AtomicU128,
+}
+
+impl AtomicTwoF64
+{
+ pub const fn new((first, second): (f64, f64)) -> Self
+ {
+ let mut bytes = [0u8; size_of::<u128>()];
+
+ bytes.copy_from_slice([first.to_ne_bytes(), second.to_ne_bytes()].as_flattened());
+
+ Self {
+ inner: AtomicU128::new(u128::from_ne_bytes(bytes)),
+ }
+ }
+
+ pub fn load(&self, order: Ordering) -> (f64, f64)
+ {
+ u128_to_two_f64(self.inner.load(order))
+ }
+
+ pub fn store(&self, values: (f64, f64), order: Ordering)
+ {
+ self.inner.store(two_f64_to_u128(values), order);
+ }
+
+ pub fn swap(&self, values: (f64, f64), order: Ordering) -> (f64, f64)
+ {
+ u128_to_two_f64(self.inner.swap(two_f64_to_u128(values), order))
+ }
+
+ pub fn compare_exchange(
+ &self,
+ current: (f64, f64),
+ new: (f64, f64),
+ success_order: Ordering,
+ failure_order: Ordering,
+ ) -> Result<(f64, f64), (f64, f64)>
+ {
+ self.inner
+ .compare_exchange(
+ two_f64_to_u128(current),
+ two_f64_to_u128(new),
+ success_order,
+ failure_order,
+ )
+ .map(|stored| u128_to_two_f64(stored))
+ .map_err(|stored| u128_to_two_f64(stored))
+ }
+}
+
+impl Debug for AtomicTwoF64
+{
+ fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
+ {
+ let (first, second) = self.load(Ordering::Relaxed);
+
+ formatter
+ .debug_tuple("AtomicTwoF64")
+ .field(&first)
+ .field(&second)
+ .finish()
+ }
+}
+
+fn two_f64_to_u128((first, second): (f64, f64)) -> u128
+{
+ let mut bytes = [0u8; size_of::<u128>()];
+
+ bytes.copy_from_slice([first.to_ne_bytes(), second.to_ne_bytes()].as_flattened());
+
+ u128::from_ne_bytes(bytes)
+}
+
+fn u128_to_two_f64(src: u128) -> (f64, f64)
+{
+ let [first_bytes, second_bytes] = unsafe {
+ transmute::<[u8; size_of::<u128>()], [[u8; size_of::<f64>()]; 2]>(
+ src.to_ne_bytes(),
+ )
+ };
+
+ (
+ f64::from_ne_bytes(first_bytes),
+ f64::from_ne_bytes(second_bytes),
+ )
+}
+
macro_rules! try_option {
($expr: expr) => {
match $expr {
@@ -9,9 +201,6 @@ macro_rules! try_option {
};
}
-use std::mem::ManuallyDrop;
-use std::ops::{Deref, DerefMut};
-
pub(crate) use try_option;
macro_rules! or {
@@ -26,6 +215,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 +238,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 +249,7 @@ macro_rules! builder {
$visibility struct $name
{
$(
- $(#[$field_attr])*
+ $(#[doc = $field_doc])*
$field_visibility $field: $field_type,
)*
}
@@ -63,16 +265,23 @@ 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]
- $visibility fn build(self) -> $name {
+ $visibility const fn build(self) -> $name
+ {
$name {
$(
$field: self.$field,
@@ -83,6 +292,7 @@ macro_rules! builder {
impl From<$name> for $builder_name
{
+ #[allow(unused_variables)]
fn from(built: $name) -> Self
{
Self {
@@ -94,39 +304,3 @@ macro_rules! builder {
}
};
}
-
-pub(crate) use builder;
-
-/// Wrapper that ensures the contained value will never be dropped.
-#[derive(Debug)]
-pub struct NeverDrop<Value>
-{
- value: ManuallyDrop<Value>,
-}
-
-impl<Value> NeverDrop<Value>
-{
- #[must_use]
- pub fn new(value: Value) -> Self
- {
- Self { value: ManuallyDrop::new(value) }
- }
-}
-
-impl<Value> Deref for NeverDrop<Value>
-{
- type Target = Value;
-
- fn deref(&self) -> &Self::Target
- {
- &self.value
- }
-}
-
-impl<Value> DerefMut for NeverDrop<Value>
-{
- fn deref_mut(&mut self) -> &mut Self::Target
- {
- &mut self.value
- }
-}