use std::ops::ControlFlow; use geo::Point; use thiserror::Error; use crate::{ autorouter::{ execution::ExecutionStepper, invoker::{ GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles, Invoker, InvokerError, }, }, board::mesadata::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, interactor::interaction::{InteractionError, InteractionStepper}, router::{navcord::NavcordStepper, navmesh::Navmesh}, stepper::{Abort, Step}, }; pub struct InteractiveInput { pub pointer_pos: Point, pub dt: f32, } pub struct ActivityContext<'a, M: AccessMesadata> { pub interactive_input: &'a InteractiveInput, 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 Step, String> for ActivityStepper { type Error = ActivityError; fn step( &mut self, context: &mut ActivityContext, ) -> Result, ActivityError> { match self { ActivityStepper::Interaction(interaction) => Ok(interaction.step(context)?), ActivityStepper::Execution(execution) => Ok(execution.step(context.invoker)?), } } } impl Abort> for ActivityStepper { fn abort(&mut self, context: &mut ActivityContext) { match self { ActivityStepper::Interaction(interaction) => interaction.abort(context), 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, String> for ActivityStepperWithStatus { type Error = ActivityError; fn step( &mut self, context: &mut ActivityContext, ) -> Result, ActivityError> { 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(ControlFlow::Break(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() } }