use super::Container;
use crate::{ids::UnitTypeId, unit::Unit};
use indexmap::map::IntoIter;
use std::borrow::Borrow;
pub struct IntoUnits(pub(super) IntoIter<u64, Unit>);
impl Iterator for IntoUnits {
type Item = Unit;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|x| x.1)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
#[inline]
fn count(self) -> usize {
self.0.len()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n).map(|x| x.1)
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl DoubleEndedIterator for IntoUnits {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(|x| x.1)
}
}
impl ExactSizeIterator for IntoUnits {
fn len(&self) -> usize {
self.0.len()
}
}
pub(crate) fn filter_fold<T, Acc>(
mut pred: impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, u| if pred(&u) { fold(acc, u) } else { acc }
}
macro_rules! iterator_methods {
() => {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let pred = self.predicate();
self.iter.find(|u| pred(u.borrow()))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.iter.size_hint().1)
}
#[inline]
fn count(self) -> usize {
let pred = self.predicate();
self.iter.map(|u| pred(u.borrow()) as usize).sum()
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
let pred = self.predicate();
self.iter
.fold(init, filter_fold(|u| pred(u.borrow()), fold))
}
};
}
macro_rules! double_ended_iterator_methods {
() => {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let pred = self.predicate();
self.iter.rfind(|u| pred(u.borrow()))
}
#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
let pred = self.predicate();
self.iter
.rfold(init, filter_fold(|u| pred(u.borrow()), fold))
}
};
}
macro_rules! impl_simple_iterator {
($name:ident $(<$a:lifetime>)?) => {
impl<$($a,)? I> Iterator for $name<$($a,)? I>
where
I: Iterator,
I::Item: Borrow<Unit>,
{
type Item = I::Item;
iterator_methods!();
}
impl<$($a,)? I> DoubleEndedIterator for $name<$($a,)? I>
where
I: DoubleEndedIterator,
I::Item: Borrow<Unit>,
{
double_ended_iterator_methods!();
}
};
}
macro_rules! make_simple_iterator {
($(#[$attr:meta])* $name:ident, $pred:expr) => {
$(#[$attr])*
#[derive(Clone)]
pub struct $name<I> {
iter: I,
}
impl<I> $name<I> {
pub(super) fn new(iter: I) -> Self {
Self { iter }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool {
$pred
}
}
impl_simple_iterator!($name);
};
}
#[derive(Clone)]
pub struct FindTags<'a, I, T> {
iter: I,
tags: &'a T,
}
impl<'a, I, T: Container<u64>> FindTags<'a, I, T> {
pub(super) fn new(iter: I, tags: &'a T) -> Self {
Self { iter, tags }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool + 'a {
let tags = self.tags;
move |u| tags.contains(&u.tag())
}
}
impl<'a, I, T> Iterator for FindTags<'a, I, T>
where
I: Iterator,
I::Item: Borrow<Unit>,
T: Container<u64>,
{
type Item = I::Item;
iterator_methods!();
}
impl<'a, I, T> DoubleEndedIterator for FindTags<'a, I, T>
where
I: DoubleEndedIterator,
I::Item: Borrow<Unit>,
T: Container<u64>,
{
double_ended_iterator_methods!();
}
#[derive(Clone)]
pub struct OfType<I> {
iter: I,
unit_type: UnitTypeId,
}
impl<I> OfType<I> {
pub(super) fn new(iter: I, unit_type: UnitTypeId) -> Self {
Self { iter, unit_type }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool {
let unit_type = self.unit_type;
move |u| u.type_id() == unit_type
}
}
impl_simple_iterator!(OfType);
#[derive(Clone)]
pub struct ExcludeType<I> {
iter: I,
unit_type: UnitTypeId,
}
impl<I> ExcludeType<I> {
pub(super) fn new(iter: I, unit_type: UnitTypeId) -> Self {
Self { iter, unit_type }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool {
let unit_type = self.unit_type;
move |u| u.type_id() != unit_type
}
}
impl_simple_iterator!(ExcludeType);
#[derive(Clone)]
pub struct OfTypes<'a, I, T> {
iter: I,
types: &'a T,
}
impl<'a, I, T: Container<UnitTypeId>> OfTypes<'a, I, T> {
pub(super) fn new(iter: I, types: &'a T) -> Self {
Self { iter, types }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool + 'a {
let types = self.types;
move |u| types.contains(&u.type_id())
}
}
impl<'a, I, T> Iterator for OfTypes<'a, I, T>
where
I: Iterator,
I::Item: Borrow<Unit>,
T: Container<UnitTypeId>,
{
type Item = I::Item;
iterator_methods!();
}
impl<'a, I, T> DoubleEndedIterator for OfTypes<'a, I, T>
where
I: DoubleEndedIterator,
I::Item: Borrow<Unit>,
T: Container<UnitTypeId>,
{
double_ended_iterator_methods!();
}
#[derive(Clone)]
pub struct ExcludeTypes<'a, I, T> {
iter: I,
types: &'a T,
}
impl<'a, I, T: Container<UnitTypeId>> ExcludeTypes<'a, I, T> {
pub(super) fn new(iter: I, types: &'a T) -> Self {
Self { iter, types }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool + 'a {
let types = self.types;
move |u| !types.contains(&u.type_id())
}
}
impl<'a, I, T> Iterator for ExcludeTypes<'a, I, T>
where
I: Iterator,
I::Item: Borrow<Unit>,
T: Container<UnitTypeId>,
{
type Item = I::Item;
iterator_methods!();
}
impl<'a, I, T> DoubleEndedIterator for ExcludeTypes<'a, I, T>
where
I: DoubleEndedIterator,
I::Item: Borrow<Unit>,
T: Container<UnitTypeId>,
{
double_ended_iterator_methods!();
}
make_simple_iterator!(
Ground,
|u| !u.is_flying()
);
make_simple_iterator!(
Flying,
|u| u.is_flying()
);
make_simple_iterator!(
Ready,
|u| u.is_ready()
);
make_simple_iterator!(
NotReady,
|u| !u.is_ready()
);
make_simple_iterator!(
Idle,
|u| u.is_idle()
);
make_simple_iterator!(
AlmostIdle,
|u| u.is_almost_idle()
);
make_simple_iterator!(
Unused,
|u| u.is_unused()
);
make_simple_iterator!(
AlmostUnused,
|u| u.is_almost_unused()
);
make_simple_iterator!(
Visible,
|u| u.is_visible()
);
#[derive(Clone)]
pub struct InRangeOf<'a, I> {
iter: I,
unit: &'a Unit,
gap: f32,
}
impl<'a, I> InRangeOf<'a, I> {
pub(super) fn new(iter: I, unit: &'a Unit, gap: f32) -> Self {
Self { iter, unit, gap }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool + 'a {
let unit = self.unit;
let gap = self.gap;
move |u| unit.in_range(u, gap)
}
}
impl_simple_iterator!(InRangeOf<'a>);
#[derive(Clone)]
pub struct InRange<'a, I> {
iter: I,
unit: &'a Unit,
gap: f32,
}
impl<'a, I> InRange<'a, I> {
pub(super) fn new(iter: I, unit: &'a Unit, gap: f32) -> Self {
Self { iter, unit, gap }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool + 'a {
let unit = self.unit;
let gap = self.gap;
move |u| u.in_range(unit, gap)
}
}
impl_simple_iterator!(InRange<'a>);
#[derive(Clone)]
pub struct InRealRangeOf<'a, I> {
iter: I,
unit: &'a Unit,
gap: f32,
}
impl<'a, I> InRealRangeOf<'a, I> {
pub(super) fn new(iter: I, unit: &'a Unit, gap: f32) -> Self {
Self { iter, unit, gap }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool + 'a {
let unit = self.unit;
let gap = self.gap;
move |u| unit.in_real_range(u, gap)
}
}
impl_simple_iterator!(InRealRangeOf<'a>);
#[derive(Clone)]
pub struct InRealRange<'a, I> {
iter: I,
unit: &'a Unit,
gap: f32,
}
impl<'a, I> InRealRange<'a, I> {
pub(super) fn new(iter: I, unit: &'a Unit, gap: f32) -> Self {
Self { iter, unit, gap }
}
fn predicate(&self) -> impl Fn(&Unit) -> bool + 'a {
let unit = self.unit;
let gap = self.gap;
move |u| u.in_real_range(unit, gap)
}
}
impl_simple_iterator!(InRealRange<'a>);
pub trait UnitsIterator: Iterator + Sized
where
Self::Item: Borrow<Unit>,
{
fn find_tag(mut self, tag: u64) -> Option<Self::Item> {
self.find(|u| u.borrow().tag() == tag)
}
fn find_tags<T: Container<u64>>(self, tags: &T) -> FindTags<Self, T> {
FindTags::new(self, tags)
}
fn of_type(self, unit_type: UnitTypeId) -> OfType<Self> {
OfType::new(self, unit_type)
}
fn exclude_type(self, unit_type: UnitTypeId) -> ExcludeType<Self> {
ExcludeType::new(self, unit_type)
}
fn of_types<T: Container<UnitTypeId>>(self, types: &T) -> OfTypes<Self, T> {
OfTypes::new(self, types)
}
fn exclude_types<T: Container<UnitTypeId>>(self, types: &T) -> ExcludeTypes<Self, T> {
ExcludeTypes::new(self, types)
}
fn ground(self) -> Ground<Self> {
Ground::new(self)
}
fn flying(self) -> Flying<Self> {
Flying::new(self)
}
fn ready(self) -> Ready<Self> {
Ready::new(self)
}
fn not_ready(self) -> NotReady<Self> {
NotReady::new(self)
}
fn idle(self) -> Idle<Self> {
Idle::new(self)
}
fn almost_idle(self) -> AlmostIdle<Self> {
AlmostIdle::new(self)
}
fn unused(self) -> Unused<Self> {
Unused::new(self)
}
fn almost_unused(self) -> AlmostUnused<Self> {
AlmostUnused::new(self)
}
fn visible(self) -> Visible<Self> {
Visible::new(self)
}
fn in_range_of(self, unit: &Unit, gap: f32) -> InRangeOf<Self> {
InRangeOf::new(self, unit, gap)
}
fn in_range(self, unit: &Unit, gap: f32) -> InRange<Self> {
InRange::new(self, unit, gap)
}
fn in_real_range_of(self, unit: &Unit, gap: f32) -> InRealRangeOf<Self> {
InRealRangeOf::new(self, unit, gap)
}
fn in_real_range(self, unit: &Unit, gap: f32) -> InRealRange<Self> {
InRealRange::new(self, unit, gap)
}
}
impl<I> UnitsIterator for I
where
I: Iterator + Sized,
I::Item: Borrow<Unit>,
{
}