use thiserror::Error; use topola::{ autorouter::{ execution::ExecutionStepper, invoker::{ GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles, Invoker, InvokerError, InvokerStatus, }, }, board::mesadata::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, router::{navcord::NavcordStepper, navmesh::Navmesh}, stepper::{Abort, Step}, }; use crate::interaction::{ InteractionContext, InteractionError, InteractionStatus, InteractionStepper, }; pub struct ActivityContext<'a, M: AccessMesadata> { pub interaction: InteractionContext, pub invoker: &'a mut Invoker, } #[derive(Debug, Clone)] pub enum ActivityStatus { Running, Finished(String), } impl From for ActivityStatus { fn from(status: InteractionStatus) -> Self { match status { InteractionStatus::Running => ActivityStatus::Running, InteractionStatus::Finished(msg) => ActivityStatus::Finished(msg), } } } impl From for ActivityStatus { fn from(status: InvokerStatus) -> Self { match status { InvokerStatus::Running => ActivityStatus::Running, InvokerStatus::Finished(msg) => ActivityStatus::Finished(msg), } } } impl TryInto<()> for ActivityStatus { type Error = (); fn try_into(self) -> Result<(), ()> { match self { ActivityStatus::Running => Err(()), ActivityStatus::Finished(..) => Ok(()), } } } #[derive(Error, Debug, Clone)] pub enum ActivityError { #[error(transparent)] Interaction(#[from] InteractionError), #[error(transparent)] Invoker(#[from] InvokerError), } pub enum ActivityStepper { Interaction(InteractionStepper), Execution(ExecutionStepper), } impl Step, ActivityStatus, ActivityError, ()> for ActivityStepper { fn step(&mut self, context: &mut ActivityContext) -> Result { match self { ActivityStepper::Interaction(interaction) => { Ok(interaction.step(&mut context.interaction)?.into()) } ActivityStepper::Execution(execution) => Ok(execution.step(context.invoker)?.into()), } } } impl Abort> for ActivityStepper { fn abort(&mut self, context: &mut ActivityContext) { match self { ActivityStepper::Interaction(interaction) => { Ok(interaction.abort(&mut context.interaction)) } ActivityStepper::Execution(execution) => execution.finish(context.invoker), // TODO. }; } } impl GetMaybeNavmesh for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn maybe_navmesh(&self) -> Option<&Navmesh> { match self { ActivityStepper::Interaction(interaction) => interaction.maybe_navmesh(), ActivityStepper::Execution(execution) => execution.maybe_navmesh(), } } } impl GetMaybeNavcord for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn maybe_navcord(&self) -> Option<&NavcordStepper> { match self { ActivityStepper::Interaction(interaction) => interaction.maybe_navcord(), ActivityStepper::Execution(execution) => execution.maybe_navcord(), } } } impl GetGhosts for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn ghosts(&self) -> &[PrimitiveShape] { match self { ActivityStepper::Interaction(interaction) => interaction.ghosts(), ActivityStepper::Execution(execution) => execution.ghosts(), } } } impl GetObstacles for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn obstacles(&self) -> &[PrimitiveIndex] { match self { ActivityStepper::Interaction(interaction) => interaction.obstacles(), ActivityStepper::Execution(execution) => execution.obstacles(), } } } pub struct ActivityStepperWithStatus { activity: ActivityStepper, maybe_status: Option, } impl ActivityStepperWithStatus { pub fn new_execution(execution: ExecutionStepper) -> ActivityStepperWithStatus { Self { activity: ActivityStepper::Execution(execution), maybe_status: None, } } pub fn maybe_status(&self) -> Option { self.maybe_status.clone() } } impl Step, ActivityStatus, ActivityError, ()> for ActivityStepperWithStatus { fn step(&mut self, context: &mut ActivityContext) -> Result { let status = self.activity.step(context)?; self.maybe_status = Some(status.clone()); Ok(status.into()) } } impl Abort> for ActivityStepperWithStatus { fn abort(&mut self, context: &mut ActivityContext) { self.maybe_status = Some(ActivityStatus::Finished(String::from("aborted"))); self.activity.abort(context); } } impl GetMaybeNavmesh for ActivityStepperWithStatus { fn maybe_navmesh(&self) -> Option<&Navmesh> { self.activity.maybe_navmesh() } } impl GetMaybeNavcord for ActivityStepperWithStatus { fn maybe_navcord(&self) -> Option<&NavcordStepper> { self.activity.maybe_navcord() } } impl GetGhosts for ActivityStepperWithStatus { fn ghosts(&self) -> &[PrimitiveShape] { self.activity.ghosts() } } impl GetObstacles for ActivityStepperWithStatus { fn obstacles(&self) -> &[PrimitiveIndex] { self.activity.obstacles() } }