use core::task::Poll; use thiserror::Error; use topola::{ autorouter::{ execution::ExecutionStepper, invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles, Invoker, InvokerError}, }, board::mesadata::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, router::{navmesh::Navmesh, trace::TraceStepper}, specctra::mesadata::SpecctraMesadata, stepper::{Abort, PollStep, StepError}, }; use crate::interaction::{InteractionContext, InteractionError, InteractionStepper}; pub struct ActivityContext<'a> { pub interaction: InteractionContext, pub invoker: &'a mut Invoker, } #[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 StepError for ActivityStepper { type Error = ActivityError; } impl PollStep, String> for ActivityStepper { fn poll_step( &mut self, context: &mut ActivityContext<'_>, ) -> Poll> { match self { ActivityStepper::Interaction(interaction) => interaction .poll_step(&mut context.interaction) .map(|x| x.map_err(Into::into)), ActivityStepper::Execution(execution) => execution .poll_step(context.invoker) .map(|x| x.map_err(Into::into)), } } } impl Abort> for ActivityStepper { fn abort(&mut self, context: &mut ActivityContext) { match self { ActivityStepper::Interaction(interaction) => { interaction.abort(&mut context.interaction); } ActivityStepper::Execution(execution) => { PollStep::finish(execution, 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 GetMaybeTrace for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn maybe_trace(&self) -> Option<&TraceStepper> { match self { ActivityStepper::Interaction(interaction) => interaction.maybe_trace(), ActivityStepper::Execution(execution) => execution.maybe_trace(), } } } 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(), } } } #[derive(Default)] pub struct ActivityStepperWithStatus { pub maybe_activity: Option, pub maybe_status: Option>, } impl ActivityStepperWithStatus { pub fn new_execution(execution: ExecutionStepper) -> ActivityStepperWithStatus { Self { maybe_activity: Some(ActivityStepper::Execution(execution)), maybe_status: None, } } pub fn is_busy(&self) -> bool { if self.maybe_activity.is_none() { return false; } // this might be left over from a previous execution //if let Some(Poll::Ready(_)) = &self.maybe_status { // return false; //} true } } impl StepError for ActivityStepperWithStatus { type Error = ActivityError; } impl PollStep, String> for ActivityStepperWithStatus { fn poll_step( &mut self, context: &mut ActivityContext<'_>, ) -> Poll> { let res = match &mut self.maybe_activity { None => return Poll::Pending, Some(act) => act.poll_step(context), }; // fused stepping if let Poll::Ready(_) = &res { self.maybe_activity = None; } self.maybe_status = match &res { Poll::Pending => Some(Poll::Pending), Poll::Ready(Ok(msg)) => Some(Poll::Ready(msg.clone())), Poll::Ready(Err(_)) => None, }; res } } impl Abort> for ActivityStepperWithStatus { fn abort(&mut self, context: &mut ActivityContext<'_>) { if let Some(mut act) = self.maybe_activity.take() { self.maybe_status = Some(Poll::Ready("aborted".to_string())); act.abort(context); } } } impl GetMaybeNavmesh for ActivityStepperWithStatus { fn maybe_navmesh(&self) -> Option<&Navmesh> { self.maybe_activity.as_ref()?.maybe_navmesh() } } impl GetMaybeTrace for ActivityStepperWithStatus { fn maybe_trace(&self) -> Option<&TraceStepper> { self.maybe_activity.as_ref()?.maybe_trace() } } impl GetGhosts for ActivityStepperWithStatus { fn ghosts(&self) -> &[PrimitiveShape] { match &self.maybe_activity { None => &[], Some(act) => act.ghosts(), } } } impl GetObstacles for ActivityStepperWithStatus { fn obstacles(&self) -> &[PrimitiveIndex] { match &self.maybe_activity { None => &[], Some(act) => act.obstacles(), } } }