mirror of https://codeberg.org/topola/topola.git
199 lines
6.0 KiB
Rust
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(),
|
|
}
|
|
}
|
|
}
|