use super::MaybeJoin;
use hibitset::{BitIter, BitSetLike};
use crate::world::{Entities, Entity, Index};
#[nougat::gat]
pub unsafe trait LendJoin {
type Type<'next>
where
Self: 'next;
type Value;
type Mask: BitSetLike;
fn lend_join(self) -> JoinLendIter<Self>
where
Self: Sized,
{
JoinLendIter::new(self)
}
fn maybe(self) -> MaybeJoin<Self>
where
Self: Sized,
{
MaybeJoin(self)
}
unsafe fn open(self) -> (Self::Mask, Self::Value);
unsafe fn get<'next>(value: &'next mut Self::Value, id: Index) -> Self::Type<'next>;
#[inline]
fn is_unconstrained() -> bool {
false
}
}
pub unsafe trait RepeatableLendGet: LendJoin {}
pub type LendJoinType<'next, J> = nougat::Gat!(<J as LendJoin>::Type<'next>);
#[must_use]
pub struct JoinLendIter<J: LendJoin> {
keys: BitIter<J::Mask>,
values: J::Value,
}
impl<J: LendJoin> JoinLendIter<J> {
pub fn new(j: J) -> Self {
if <J as LendJoin>::is_unconstrained() {
log::warn!(
"`LendJoin` possibly iterating through all indices, \
you might've made a join with all `MaybeJoin`s, \
which is unbounded in length."
);
}
let (keys, values) = unsafe { j.open() };
JoinLendIter {
keys: keys.iter(),
values,
}
}
}
impl<J: LendJoin> JoinLendIter<J> {
#[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Option<LendJoinType<'_, J>> {
self.keys
.next()
.map(|idx| unsafe { J::get(&mut self.values, idx) })
}
pub fn for_each(mut self, mut f: impl FnMut(LendJoinType<'_, J>)) {
self.keys.for_each(|idx| {
let item = unsafe { J::get(&mut self.values, idx) };
f(item);
})
}
pub fn get(&mut self, entity: Entity, entities: &Entities) -> Option<LendJoinType<'_, J>>
where
J: RepeatableLendGet,
{
if self.keys.contains(entity.id()) && entities.is_alive(entity) {
Some(unsafe { J::get(&mut self.values, entity.id()) })
} else {
None
}
}
pub fn get_unchecked(&mut self, index: Index) -> Option<LendJoinType<'_, J>>
where
J: RepeatableLendGet,
{
if self.keys.contains(index) {
Some(unsafe { J::get(&mut self.values, index) })
} else {
None
}
}
}