diff options
Diffstat (limited to 'ecs/src/util.rs')
| -rw-r--r-- | ecs/src/util.rs | 262 | 
1 files changed, 261 insertions, 1 deletions
| diff --git a/ecs/src/util.rs b/ecs/src/util.rs index 0273b18..27e9748 100644 --- a/ecs/src/util.rs +++ b/ecs/src/util.rs @@ -1,4 +1,171 @@ -use std::ops::BitAnd; +use std::hash::Hash; +use std::mem::transmute; +use std::ops::{BitAnd, Deref}; + +use hashbrown::HashMap; + +pub(crate) mod array_vec; + +pub trait VecExt<Item> +{ +    fn insert_at_part_pt_by_key<Key>( +        &mut self, +        item: Item, +        func: impl FnMut(&Item) -> &Key, +    ) where +        Key: Ord; +} + +impl<Item> VecExt<Item> for Vec<Item> +{ +    fn insert_at_part_pt_by_key<Key>( +        &mut self, +        item: Item, +        mut func: impl FnMut(&Item) -> &Key, +    ) where +        Key: Ord, +    { +        let key = func(&item); + +        let insert_index = self.partition_point(|other_item| func(other_item) <= key); + +        self.insert(insert_index, item); +    } +} + +pub trait StreamingIterator +{ +    type Item<'a> +    where +        Self: 'a; + +    fn streaming_next(&mut self) -> Option<Self::Item<'_>>; + +    fn streaming_map<NewItem, Func>(self, func: Func) -> StreamingMap<Self, Func> +    where +        Self: Sized, +        Func: FnMut(Self::Item<'_>) -> NewItem, +    { +        StreamingMap { iter: self, func } +    } + +    fn streaming_find<'this, Predicate>( +        &'this mut self, +        mut predicate: Predicate, +    ) -> Option<Self::Item<'this>> +    where +        Self: Sized, +        Predicate: FnMut(&Self::Item<'this>) -> bool, +    { +        while let Some(item) = unsafe { +            transmute::<Option<Self::Item<'_>>, Option<Self::Item<'_>>>( +                self.streaming_next(), +            ) +        } { +            if predicate(&item) { +                return Some(item); +            } +        } + +        None +    } +} + +pub struct StreamingMap<Iter, Func> +{ +    iter: Iter, +    func: Func, +} + +impl<Iter, Func, Item> StreamingIterator for StreamingMap<Iter, Func> +where +    Iter: StreamingIterator, +    Func: FnMut(Iter::Item<'_>) -> Item, +{ +    type Item<'a> +        = Item +    where +        Iter: 'a, +        Func: 'a; + +    fn streaming_next(&mut self) -> Option<Self::Item<'_>> +    { +        Some((self.func)(self.iter.streaming_next()?)) +    } +} + +#[derive(Debug)] +pub enum BorrowedOrOwned<'a, Value> +{ +    Borrowned(&'a Value), +    Owned(Value), +} + +impl<Value> Deref for BorrowedOrOwned<'_, Value> +{ +    type Target = Value; + +    fn deref(&self) -> &Self::Target +    { +        match self { +            Self::Borrowned(value) => value, +            Self::Owned(value) => value, +        } +    } +} + +#[derive(Debug, Clone)] +pub enum Either<A, B> +{ +    A(A), +    B(B), +} + +impl<A, B> Iterator for Either<A, B> +where +    A: Iterator, +    B: Iterator<Item = A::Item>, +{ +    type Item = A::Item; + +    fn next(&mut self) -> Option<Self::Item> +    { +        match self { +            Self::A(a) => a.next(), +            Self::B(b) => b.next(), +        } +    } +} + +pub trait HashMapExt<Key, Value> +{ +    /// Returns true if the keys are a subset of another [`HashMap`]'s keys, i.e., `other` +    /// contains at least all the keys in `self`. +    fn keys_is_subset(&self, other: &Self) -> bool; + +    /// Returns true if the keys are a superset of another [`HashMap`]'s keys, i.e., +    /// `self` contains at least all the keys in `other`. +    fn keys_is_superset(&self, other: &Self) -> bool; +} + +impl<Key, Value> HashMapExt<Key, Value> for HashMap<Key, Value> +where +    Key: Eq + Hash, +{ +    fn keys_is_subset(&self, other: &Self) -> bool +    { +        if self.len() <= other.len() { +            self.keys().all(|key| other.contains_key(key)) +        } else { +            false +        } +    } + +    fn keys_is_superset(&self, other: &Self) -> bool +    { +        other.keys_is_subset(self) +    } +}  pub trait Array<Item>:      AsRef<[Item]> @@ -77,6 +244,7 @@ impl BitMask<u64>          Self { mask }      } +    #[must_use]      pub const fn value(self) -> u64      {          self.mask @@ -86,6 +254,8 @@ impl BitMask<u64>      #[must_use]      pub const fn field_prep(self, field_value: u64) -> u64      { +        debug_assert!(field_value < 1 << self.mask.count_ones()); +          ((field_value) << self.mask.trailing_zeros()) & (self.mask)      }  } @@ -103,6 +273,7 @@ impl BitAnd<u64> for BitMask<u64>  pub trait NumberExt: Sized  {      /// Returns a range of bits (field) specified by the provided [`BitMask`]. +    #[must_use]      fn field_get(self, field_mask: BitMask<Self>) -> Self;  } @@ -129,6 +300,88 @@ macro_rules! gen_mask_64 {  pub(crate) use gen_mask_64; +macro_rules! impl_multiple { +    ( +        $type: ident, +        ($( +            impl$(<$($generic: tt$(: $bound: ident)?),*>)? +            _<$($lt_param: lifetime),*><$($type_param: ty),*> +            $(($($extra_cb_arg: expr),*))? +        ),*) +        cb=( +            type_params=($($ty_param_matcher: ident),*) +            $(, $($extra_matcher: ident),+)? +        ) => { +            $($item_tt: tt)* +        } +    ) => { +        const _: () = { +            $crate::util::impl_multiple!( +                @(make_gen_item_macro) +                _gen_multiple_impl_item, +                ($($ty_param_matcher),*), +                ($($($extra_matcher),+)?), +                ($($item_tt)*) +            ); + +            $( +                impl $(<$($generic$(: $bound)?,)*>)? $type<$($lt_param,)* $($type_param),*> +                { +                    _gen_multiple_impl_item!( +                        type_params=($($type_param),*), +                        $($($extra_cb_arg),*)? +                    ); +                } +            )* +        }; +    }; + +    ( +        @(make_gen_item_macro) +        $name: ident, +        ($($ty_param_matcher: ident),*), +        ($($extra_matcher: ident),*), +        ($($transcriber: tt)*) +    ) => { +        $crate::util::impl_multiple!( +            @(make_gen_item_macro) +            ($), +            $name, +            ($($ty_param_matcher),*), +            ($($extra_matcher),*), +            ($($transcriber)*) +        ); +    }; + +    ( +        @(make_gen_item_macro) +        ($dollar: tt), +        $name: ident, +        ($($ty_param_matcher: ident),*), +        ($($extra_matcher: ident),*), +        ($($transcriber: tt)*) +    ) => { +        $crate::util::impl_multiple!( +            @(make_gen_item_macro) +            $name, +            ( +                type_params=($($dollar$ty_param_matcher: ty),*), +                $($dollar$extra_matcher: expr),* +            ) => { +                $($transcriber)* +            } +        ); +    }; + +    (@(make_gen_item_macro) $name: ident, $($rule: tt)*) => { +        macro_rules! $name { +            $($rule)* +        } +    }; +} + +pub(crate) use impl_multiple; +  mod sealed  {      pub trait Sealed {} @@ -152,4 +405,11 @@ mod tests      {          assert_eq!(BitMask::new(0b11000).field_prep(3), 0b11000);      } + +    #[test] +    #[should_panic] +    fn bitmask_field_prep_too_large_value_panics() +    { +        let _ = BitMask::new(0b001110).field_prep(9); +    }  } | 
