topola/src/bin/topola-egui/activity.rs

199 lines
6.0 KiB
Rust

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<SpecctraMesadata>,
}
#[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<ActivityContext<'_>, String> for ActivityStepper {
fn poll_step(
&mut self,
context: &mut ActivityContext<'_>,
) -> Poll<Result<String, ActivityError>> {
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<ActivityContext<'_>> 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<ActivityStepper>,
pub maybe_status: Option<Poll<String>>,
}
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<ActivityContext<'_>, String> for ActivityStepperWithStatus {
fn poll_step(
&mut self,
context: &mut ActivityContext<'_>,
) -> Poll<Result<String, ActivityError>> {
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<ActivityContext<'_>> 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(),
}
}
}