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