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 { inner: Vec<(Key, Value)>, } impl MapVec { 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 { 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 { self.inner.iter().map(|(_, value)| value) } } impl Default for MapVec { fn default() -> Self { Self { inner: Vec::new() } } } pub trait OptionExt { /// 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( &mut self, func: impl Fn() -> Result, ) -> Result<&mut T, Err>; } impl OptionExt for Option { fn get_or_try_insert_with_fn( &mut self, func: impl FnOnce() -> Result, ) -> 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::()]; 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::()]; 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::()], [[u8; size_of::()]; 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 { Ok(value) => value, Err(err) => { return Some(Err(err.into())); } } }; } pub(crate) use try_option; macro_rules! or { (($($tt: tt)+) else ($($else_tt: tt)*)) => { $($tt)+ }; (() else ($($else_tt: tt)*)) => { $($else_tt)* }; } 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])* #[builder( name = $builder_name: ident $(, derives = ($($builder_derive: ident),+))? )] $(#[$attr: meta])* $visibility: vis struct $name: ident { $( $(#[doc = $field_doc: literal])* $(#[builder(skip_generate_fn$($field_skip_generate_fn: tt)?)])? $field_visibility: vis $field: ident: $field_type: ty, )* } ) => { $(#[doc = $doc])* $(#[$attr])* $visibility struct $name { $( $(#[doc = $field_doc])* $field_visibility $field: $field_type, )* } $(#[derive($($builder_derive),+)])? $visibility struct $builder_name { $( $field: $field_type, )* } impl $builder_name { $( $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 const fn build(self) -> $name { $name { $( $field: self.$field, )* } } } impl From<$name> for $builder_name { #[allow(unused_variables)] fn from(built: $name) -> Self { Self { $( $field: built.$field, )* } } } }; }