use crate::status::Status::*;
use crate::tracer::{first_child_id, next_sibling_id, NodeMeta, Tracer};
use crate::Float;
use crate::{event::UpdateEvent, state::State, ActionArgs, Status, RUNNING};
pub struct WhenAllArgs<'a, A, E, F, B, T> {
pub any: bool,
pub upd: Option<Float>,
pub cursors: &'a mut [Option<State<A>>],
pub e: &'a E,
pub blackboard: &'a mut B,
pub f: &'a mut F,
pub parent_id: usize,
pub metas: &'a [NodeMeta],
pub tracer: &'a mut T,
}
pub fn when_all<A, E, F, B, T>(args: WhenAllArgs<A, E, F, B, T>) -> (Status, Float)
where
A: Clone,
E: UpdateEvent,
F: FnMut(ActionArgs<E, A>, &mut B) -> (Status, Float),
T: Tracer,
{
let WhenAllArgs {
any,
upd,
cursors,
e,
blackboard,
f,
parent_id,
metas,
tracer,
} = args;
let (status, inv_status) = if any {
(Status::Failure, Status::Success)
} else {
(Status::Success, Status::Failure)
};
let mut min_dt = Float::MAX;
let mut terminated = 0;
let mut child_id = first_child_id::<T>(parent_id);
for cur in cursors.iter_mut() {
let this_id = child_id;
child_id = next_sibling_id::<T>(metas, this_id);
match *cur {
None => {}
Some(ref mut cur) => {
match cur.tick(this_id, metas, e, blackboard, f, tracer) {
(Running, _) => {
continue;
}
(s, new_dt) if s == inv_status => {
return (inv_status, new_dt);
}
(s, new_dt) if s == status => {
min_dt = min_dt.min(new_dt);
}
_ => unreachable!(),
}
}
}
terminated += 1;
*cur = None;
}
#[allow(clippy::manual_unwrap_or)]
match terminated {
0 if cursors.is_empty() => (
status,
match upd {
Some(dt) => dt,
_ => 0.0,
},
),
n if cursors.len() == n => (status, min_dt),
_ => RUNNING,
}
}