use super::CTreeNodeID;
use super::ChildUpdate;
use crate::traits::*;
use crate::Status;
use derive_more::From;
#[derive(Debug, Clone, PartialEq, Eq, Hash, From)]
pub enum StandardDecorator {
Invert(Inverter),
Repeat(Repeater),
Subtree(Subtree),
}
impl StandardDecorator {
pub fn inverter() -> Self {
Inverter::default().into()
}
pub fn repeater(retries: usize) -> Self {
Repeater::new(retries).into()
}
pub fn subtree() -> Self {
Subtree::default().into()
}
}
impl Decorator for StandardDecorator {
fn child_updated(&mut self, update: ChildUpdate) -> Status {
match self {
StandardDecorator::Invert(i) => i.child_updated(update),
StandardDecorator::Repeat(r) => r.child_updated(update),
StandardDecorator::Subtree(s) => s.child_updated(update),
}
}
fn init(&mut self) {
match self {
StandardDecorator::Invert(i) => i.init(),
StandardDecorator::Repeat(r) => r.init(),
StandardDecorator::Subtree(s) => s.init(),
}
}
fn status(&self) -> Status {
match self {
StandardDecorator::Invert(i) => i.status(),
StandardDecorator::Repeat(r) => r.status(),
StandardDecorator::Subtree(s) => s.status(),
}
}
fn reset(&mut self) {
match self {
StandardDecorator::Invert(i) => i.reset(),
StandardDecorator::Repeat(r) => r.reset(),
StandardDecorator::Subtree(s) => s.reset(),
}
}
fn reset_request(&mut self) -> Option<CTreeNodeID> {
match self {
StandardDecorator::Invert(i) => i.reset_request(),
StandardDecorator::Repeat(r) => r.reset_request(),
StandardDecorator::Subtree(s) => s.reset_request(),
}
}
fn name(&self) -> String {
match self {
StandardDecorator::Invert(i) => i.name(),
StandardDecorator::Repeat(r) => r.name(),
StandardDecorator::Subtree(s) => s.name(),
}
}
fn details(&self) -> Option<String> {
match self {
StandardDecorator::Invert(i) => Some(format!("{i:#?}")),
StandardDecorator::Repeat(r) => Some(format!("{r:#?}")),
StandardDecorator::Subtree(s) => Some(format!("{s:#?}")),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
pub struct Subtree {
status: Option<Status>,
name: Option<String>,
}
impl Subtree {
pub fn new(name: String) -> Self {
Self {
status: None,
name: Some(name),
}
}
}
impl Decorator for Subtree {
fn child_updated(&mut self, update: ChildUpdate) -> Status {
self.status = Some(update.status);
update.status
}
fn init(&mut self) {}
fn status(&self) -> Status {
self.status.unwrap_or_default()
}
fn reset(&mut self) {
self.status = None;
}
fn name(&self) -> String {
self.name.clone().unwrap_or("Subtree".to_string())
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Inverter {
child_status: Option<Status>,
}
impl Decorator for Inverter {
fn child_updated(&mut self, update: ChildUpdate) -> Status {
self.child_status = Some(update.status);
!update.status
}
fn init(&mut self) {}
fn status(&self) -> Status {
!self.child_status.unwrap_or_default()
}
fn reset(&mut self) {
self.child_status = None;
}
fn name(&self) -> String {
"Inverter".to_string()
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
pub struct Repeater {
pub init_retry: usize,
pub retry: usize,
pub status: Option<Status>,
pub reset_request: Option<CTreeNodeID>,
}
impl Repeater {
pub fn new(retries: usize) -> Self {
Self {
init_retry: retries + 1,
retry: retries + 1,
status: None,
reset_request: None,
}
}
pub fn can_retry(&self) -> bool {
self.retry > 0
}
}
impl Decorator for Repeater {
fn child_updated(&mut self, update: ChildUpdate) -> Status {
if !self.can_retry() {
self.status = Some(Status::Failure);
return Status::Failure;
}
match update.status {
Status::Success => {
self.status = Some(Status::Success);
self.reset_request = None;
Status::Success
}
Status::Failure => {
self.retry -= 1;
self.status = Some(Status::Running);
self.reset_request = Some(update.child_id);
Status::Running
}
Status::Running => {
self.status = Some(Status::Running);
self.reset_request = Some(update.child_id);
Status::Running
}
}
}
fn init(&mut self) {
self.status = Some(Status::Running);
}
fn status(&self) -> Status {
if self.can_retry() {
self.status.unwrap_or_default()
} else {
self.status.unwrap_or(Status::Failure)
}
}
fn reset_request(&mut self) -> Option<CTreeNodeID> {
if self.can_retry() {
self.reset_request.take()
} else {
None
}
}
fn reset(&mut self) {
self.reset_request = None;
self.status = None;
self.retry = self.init_retry;
}
fn name(&self) -> String {
format!("Repeat({})", self.retry)
}
}