use std::marker::PhantomData;
use crate::{Bhv, Status};
pub(crate) trait StatusPolicy {
const STATUS: Status;
}
pub(crate) struct SelPolicy;
pub(crate) struct SeqPolicy;
pub(crate) struct List<Ctx, Policy>
where
Policy: StatusPolicy,
{
nodes: Vec<Box<dyn Bhv<Context=Ctx>>>,
current: usize,
_tag: PhantomData<Policy>,
}
pub struct Sel<Ctx>(pub(crate) List<Ctx, SelPolicy>);
pub struct Seq<Ctx>(pub(crate) List<Ctx, SeqPolicy>);
impl<Ctx> Sel<Ctx> {
#[inline]
pub fn with_nodes(nodes: Vec<Box<dyn Bhv<Context=Ctx>>>) -> Self {
Self(List {
nodes,
current: 0,
_tag: PhantomData,
})
}
}
impl<Ctx> Seq<Ctx> {
#[inline]
pub fn with_nodes(nodes: Vec<Box<dyn Bhv<Context=Ctx>>>) -> Self {
Self(List {
nodes,
current: 0,
_tag: PhantomData,
})
}
}
impl<Ctx, Policy> Bhv for List<Ctx, Policy>
where
Policy: StatusPolicy,
{
type Context = Ctx;
fn update(&mut self, ctx: &mut Self::Context) -> Status {
loop {
if self.current >= self.nodes.len() {
self.reset(Policy::STATUS);
return Policy::STATUS;
} else {
let s = self.nodes[self.current].update(ctx);
if s == Policy::STATUS {
self.current += 1;
continue;
} else if s == Status::Running {
return Status::Running;
} else {
self.reset(s);
return s;
}
}
}
}
fn reset(&mut self, _status: Status) {
let count = self.current.clamp(0, self.nodes.len());
self.nodes[..count]
.iter_mut()
.for_each(|n| n.reset(Policy::STATUS));
self.current = 0;
}
}
impl<Ctx> Bhv for Sel<Ctx> {
type Context = Ctx;
#[inline]
fn update(&mut self, ctx: &mut Self::Context) -> Status {
self.0.update(ctx)
}
#[inline]
fn reset(&mut self, _status: Status) {
self.0.reset(_status)
}
}
impl<Ctx> Bhv for Seq<Ctx> {
type Context = Ctx;
#[inline]
fn update(&mut self, ctx: &mut Self::Context) -> Status {
self.0.update(ctx)
}
#[inline]
fn reset(&mut self, _status: Status) {
self.0.reset(_status)
}
}
impl StatusPolicy for SelPolicy {
const STATUS: Status = Status::Failure;
}
impl StatusPolicy for SeqPolicy {
const STATUS: Status = Status::Success;
}
#[macro_export]
macro_rules! sel {
() => {
compile_error!("`sel` should have at least one argument!")
};
($($x:expr),+$(,)?) => {
$crate::Sel::with_nodes(
vec![$(Box::new($x)),+],
)
};
}
#[macro_export]
macro_rules! seq {
() => {
compile_error!("`seq` should have at least one argument!")
};
($($x:expr),+$(,)?) => {
$crate::Seq::with_nodes(
vec![$(Box::new($x)),+],
)
};
}