mirror of https://codeberg.org/topola/topola.git
feat(topola-egui): Add progress bar for the currently routed ratline
The capability to measure progress will later be useful to choose slower but better optimization strategies if more time is available.
This commit is contained in:
parent
29dc59df04
commit
68d9844d0d
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use topola::interactor::activity::ActivityStepperWithStatus;
|
||||
use topola::{interactor::activity::ActivityStepperWithStatus, stepper::EstimateProgress};
|
||||
|
||||
use crate::{translator::Translator, viewport::Viewport};
|
||||
|
||||
|
|
@ -38,6 +38,20 @@ impl StatusBar {
|
|||
"x: {} y: {} \t {}",
|
||||
latest_pos.x, -latest_pos.y, message
|
||||
));
|
||||
|
||||
if let Some(activity) = maybe_activity {
|
||||
let value = activity.estimate_progress_value();
|
||||
let maximum = activity.estimate_progress_maximum();
|
||||
|
||||
ui.add(
|
||||
egui::ProgressBar::new((value / maximum) as f32).text(format!(
|
||||
"{:.1} ({:.1}/{:.1})",
|
||||
value / maximum * 100.0,
|
||||
value,
|
||||
maximum
|
||||
)),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,7 +376,6 @@ impl Viewport {
|
|||
};
|
||||
|
||||
if menu_bar.show_pathfinding_scores {
|
||||
//TODO "{astar.scores[index]} ({astar.estimate_scores[index]}) (...)"
|
||||
let score_text = thetastar
|
||||
.scores()
|
||||
.get(&navnode)
|
||||
|
|
@ -384,7 +383,7 @@ impl Viewport {
|
|||
format!("g={:.2}", s)
|
||||
});
|
||||
let estimate_score_text = thetastar
|
||||
.estimate_scores()
|
||||
.cost_to_goal_estimate_scores()
|
||||
.get(&navnode)
|
||||
.map_or_else(String::new, |s| {
|
||||
format!("(f={:.2})", s)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
router::{
|
||||
navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper, RouteStepper, Router,
|
||||
},
|
||||
stepper::Step,
|
||||
stepper::{EstimateProgress, Step},
|
||||
};
|
||||
|
||||
use super::{invoker::GetDebugOverlayData, Autorouter, AutorouterError, AutorouterOptions};
|
||||
|
|
@ -164,6 +164,22 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateProgress for AutorouteExecutionStepper {
|
||||
type Value = f64;
|
||||
|
||||
fn estimate_progress_value(&self) -> f64 {
|
||||
self.route
|
||||
.as_ref()
|
||||
.map_or(0.0, |route| route.estimate_progress_value())
|
||||
}
|
||||
|
||||
fn estimate_progress_maximum(&self) -> f64 {
|
||||
self.route
|
||||
.as_ref()
|
||||
.map_or(0.0, |route| route.estimate_progress_maximum())
|
||||
}
|
||||
}
|
||||
|
||||
impl GetDebugOverlayData for AutorouteExecutionStepper {
|
||||
fn maybe_thetastar(&self) -> Option<&ThetastarStepper<Navmesh, f64>> {
|
||||
self.route.as_ref().map(|route| route.thetastar())
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
geometry::{primitive::PrimitiveShape, shape::MeasureLength},
|
||||
graph::MakeRef,
|
||||
router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper},
|
||||
stepper::Step,
|
||||
stepper::{EstimateProgress, Step},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -100,6 +100,10 @@ impl<M: AccessMesadata> Step<Autorouter<M>, (f64, f64)> for CompareDetoursExecut
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateProgress for CompareDetoursExecutionStepper {
|
||||
type Value = f64;
|
||||
}
|
||||
|
||||
impl GetDebugOverlayData for CompareDetoursExecutionStepper {
|
||||
fn maybe_thetastar(&self) -> Option<&ThetastarStepper<Navmesh, f64>> {
|
||||
self.autoroute.maybe_thetastar()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
board::AccessMesadata,
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
router::ng,
|
||||
stepper::{Abort, Step},
|
||||
stepper::{Abort, EstimateProgress, Step},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -165,3 +165,39 @@ impl<M: AccessMesadata + Clone> Abort<Invoker<M>> for ExecutionStepper<M> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since enum_dispatch does not really support generics, we implement this the
|
||||
// long way.
|
||||
impl<M> EstimateProgress for ExecutionStepper<M> {
|
||||
type Value = f64;
|
||||
|
||||
fn estimate_progress_value(&self) -> f64 {
|
||||
match self {
|
||||
ExecutionStepper::Autoroute(autoroute) => autoroute.estimate_progress_value(),
|
||||
ExecutionStepper::TopoAutoroute(toporoute) => toporoute.estimate_progress_value(),
|
||||
ExecutionStepper::PlaceVia(place_via) => place_via.estimate_progress_value(),
|
||||
ExecutionStepper::RemoveBands(remove_bands) => remove_bands.estimate_progress_value(),
|
||||
ExecutionStepper::CompareDetours(compare_detours) => {
|
||||
compare_detours.estimate_progress_value()
|
||||
}
|
||||
ExecutionStepper::MeasureLength(measure_length) => {
|
||||
measure_length.estimate_progress_value()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn estimate_progress_maximum(&self) -> f64 {
|
||||
match self {
|
||||
ExecutionStepper::Autoroute(autoroute) => autoroute.estimate_progress_maximum(),
|
||||
ExecutionStepper::TopoAutoroute(toporoute) => toporoute.estimate_progress_maximum(),
|
||||
ExecutionStepper::PlaceVia(place_via) => place_via.estimate_progress_maximum(),
|
||||
ExecutionStepper::RemoveBands(remove_bands) => remove_bands.estimate_progress_maximum(),
|
||||
ExecutionStepper::CompareDetours(compare_detours) => {
|
||||
compare_detours.estimate_progress_maximum()
|
||||
}
|
||||
ExecutionStepper::MeasureLength(measure_length) => {
|
||||
measure_length.estimate_progress_maximum()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,10 +150,10 @@ impl<M: AccessMesadata + Clone> Invoker<M> {
|
|||
}
|
||||
}
|
||||
|
||||
#[debug_requires(self.ongoing_command.is_none())]
|
||||
/// Pass given command to be executed.
|
||||
///
|
||||
/// Function used to set given [`Command`] to ongoing state, dispatch and execute it.
|
||||
#[debug_requires(self.ongoing_command.is_none())]
|
||||
pub fn execute_stepper(
|
||||
&mut self,
|
||||
command: Command,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
use crate::{
|
||||
board::AccessMesadata, geometry::shape::MeasureLength as MeasureLengthTrait, graph::MakeRef,
|
||||
stepper::EstimateProgress,
|
||||
};
|
||||
|
||||
use super::{invoker::GetDebugOverlayData, selection::BandSelection, Autorouter, AutorouterError};
|
||||
|
|
@ -47,4 +48,7 @@ impl MeasureLengthExecutionStepper {
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateProgress for MeasureLengthExecutionStepper {
|
||||
type Value = f64;
|
||||
}
|
||||
impl GetDebugOverlayData for MeasureLengthExecutionStepper {}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
use crate::{
|
||||
board::AccessMesadata,
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
stepper::EstimateProgress,
|
||||
};
|
||||
|
||||
use super::{invoker::GetDebugOverlayData, Autorouter, AutorouterError};
|
||||
|
|
@ -46,4 +47,7 @@ impl PlaceViaExecutionStepper {
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateProgress for PlaceViaExecutionStepper {
|
||||
type Value = f64;
|
||||
}
|
||||
impl GetDebugOverlayData for PlaceViaExecutionStepper {}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
//! Provides functionality to remove bands from the layout.
|
||||
|
||||
use crate::{board::AccessMesadata, layout::LayoutEdit};
|
||||
use crate::{board::AccessMesadata, layout::LayoutEdit, stepper::EstimateProgress};
|
||||
|
||||
use super::{invoker::GetDebugOverlayData, selection::BandSelection, Autorouter, AutorouterError};
|
||||
|
||||
|
|
@ -44,4 +44,7 @@ impl RemoveBandsExecutionStepper {
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateProgress for RemoveBandsExecutionStepper {
|
||||
type Value = f64;
|
||||
}
|
||||
impl GetDebugOverlayData for RemoveBandsExecutionStepper {}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::{
|
|||
ng,
|
||||
thetastar::ThetastarStepper,
|
||||
},
|
||||
stepper::{Abort, OnEvent, Step},
|
||||
stepper::{Abort, EstimateProgress, OnEvent, Step},
|
||||
};
|
||||
|
||||
/// Stores the interactive input data from the user.
|
||||
|
|
@ -98,6 +98,26 @@ impl<M: AccessMesadata + Clone> Abort<Invoker<M>> for ActivityStepper<M> {
|
|||
}
|
||||
}
|
||||
|
||||
// Since enum_dispatch does not really support generics, we implement this the
|
||||
// long way.
|
||||
impl<M> EstimateProgress for ActivityStepper<M> {
|
||||
type Value = f64;
|
||||
|
||||
fn estimate_progress_value(&self) -> f64 {
|
||||
match self {
|
||||
ActivityStepper::Interaction(..) => 0.0,
|
||||
ActivityStepper::Execution(execution) => execution.estimate_progress_value(),
|
||||
}
|
||||
}
|
||||
|
||||
fn estimate_progress_maximum(&self) -> f64 {
|
||||
match self {
|
||||
ActivityStepper::Interaction(..) => 0.0,
|
||||
ActivityStepper::Execution(execution) => execution.estimate_progress_maximum(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: AccessMesadata> OnEvent<ActivityContext<'_, M>, InteractiveEvent> for ActivityStepper<M> {
|
||||
type Output = Result<(), InteractionError>;
|
||||
|
||||
|
|
@ -179,6 +199,18 @@ impl<M: AccessMesadata + Clone> OnEvent<ActivityContext<'_, M>, InteractiveEvent
|
|||
}
|
||||
}
|
||||
|
||||
impl<M> EstimateProgress for ActivityStepperWithStatus<M> {
|
||||
type Value = f64;
|
||||
|
||||
fn estimate_progress_value(&self) -> f64 {
|
||||
self.activity.estimate_progress_value()
|
||||
}
|
||||
|
||||
fn estimate_progress_maximum(&self) -> f64 {
|
||||
self.activity.estimate_progress_maximum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> GetDebugOverlayData for ActivityStepperWithStatus<M> {
|
||||
fn maybe_thetastar(&self) -> Option<&ThetastarStepper<Navmesh, f64>> {
|
||||
self.activity.maybe_thetastar()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
geometry::primitive::PrimitiveShape,
|
||||
graph::GenericIndex,
|
||||
layout::{poly::PolyWeight, Layout, LayoutEdit},
|
||||
stepper::Abort,
|
||||
stepper::{Abort, EstimateProgress},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -232,6 +232,10 @@ impl<R: AccessRules + Clone + std::panic::RefUnwindSafe> AutorouteExecutionStepp
|
|||
}
|
||||
}
|
||||
|
||||
impl<M> EstimateProgress for AutorouteExecutionStepper<M> {
|
||||
type Value = f64;
|
||||
}
|
||||
|
||||
impl<M> GetDebugOverlayData for AutorouteExecutionStepper<M> {
|
||||
fn maybe_topo_navmesh(&self) -> Option<pie::navmesh::NavmeshRef<'_, super::PieNavmeshBase>> {
|
||||
Some(pie::navmesh::NavmeshRef {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::{
|
|||
thetastar::{ThetastarError, ThetastarStepper},
|
||||
Router, RouterThetastarStrategy,
|
||||
},
|
||||
stepper::Step,
|
||||
stepper::{EstimateProgress, Step},
|
||||
};
|
||||
|
||||
#[derive(Getters, Dissolve)]
|
||||
|
|
@ -80,6 +80,7 @@ impl<R: AccessRules> Step<Router<'_, R>, BandTermsegIndex> for RouteStepper {
|
|||
let target = self.thetastar.graph().destination();
|
||||
let mut strategy = RouterThetastarStrategy::new(layout, &mut self.navcord, target);
|
||||
let result = self.thetastar.step(&mut strategy);
|
||||
|
||||
self.ghosts = strategy.probe_ghosts;
|
||||
self.obstacles = strategy.probe_obstacles;
|
||||
|
||||
|
|
@ -97,3 +98,15 @@ impl<R: AccessRules> Step<Router<'_, R>, BandTermsegIndex> for RouteStepper {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EstimateProgress for RouteStepper {
|
||||
type Value = f64;
|
||||
|
||||
fn estimate_progress_value(&self) -> f64 {
|
||||
self.thetastar.estimate_progress_value()
|
||||
}
|
||||
|
||||
fn estimate_progress_maximum(&self) -> f64 {
|
||||
self.thetastar.estimate_progress_maximum()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ impl<R: AccessRules> ThetastarStrategy<Navmesh, f64, BandTermsegIndex>
|
|||
self.navcord.step_back(self.layout);
|
||||
}
|
||||
|
||||
fn estimate_cost(&mut self, navmesh: &Navmesh, vertex: NavnodeIndex) -> f64 {
|
||||
fn estimate_cost_to_goal(&mut self, navmesh: &Navmesh, vertex: NavnodeIndex) -> f64 {
|
||||
let start_point = PrimitiveIndex::from(navmesh.node_weight(vertex).unwrap().node)
|
||||
.primitive(self.layout.drawing())
|
||||
.shape()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
use std::collections::btree_map::Entry;
|
||||
use std::collections::{BTreeMap, BinaryHeap};
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
use std::ops::{ControlFlow, Sub};
|
||||
|
||||
use derive_getters::Getters;
|
||||
use petgraph::algo::Measure;
|
||||
|
|
@ -20,7 +20,7 @@ use thiserror::Error;
|
|||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::stepper::Step;
|
||||
use crate::stepper::{EstimateProgress, Step};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MinScored<K, T>(pub K, pub T);
|
||||
|
|
@ -122,7 +122,7 @@ where
|
|||
) -> Result<Option<R>, ()>;
|
||||
fn place_probe_to_navnode<'a>(&mut self, graph: &'a G, probed_navnode: G::NodeId) -> Option<K>;
|
||||
fn remove_probe(&mut self, graph: &G);
|
||||
fn estimate_cost(&mut self, graph: &G, navnode: G::NodeId) -> K;
|
||||
fn estimate_cost_to_goal(&mut self, graph: &G, navnode: G::NodeId) -> K;
|
||||
}
|
||||
|
||||
pub trait MakeEdgeRef: IntoEdgeReferences {
|
||||
|
|
@ -155,21 +155,28 @@ where
|
|||
G: GraphBase,
|
||||
G::NodeId: Eq + Ord,
|
||||
for<'a> &'a G: IntoEdges<NodeId = G::NodeId, EdgeId = G::EdgeId> + MakeEdgeRef,
|
||||
K: Measure + Copy,
|
||||
K: Measure + Copy + Sub<Output = K>,
|
||||
{
|
||||
state: ThetastarState<G::NodeId, G::EdgeId>,
|
||||
graph: G,
|
||||
/// The priority queue of the navnodes to expand.
|
||||
#[getter(skip)]
|
||||
visit_next: BinaryHeap<MinScored<K, G::NodeId>>,
|
||||
frontier: BinaryHeap<MinScored<K, G::NodeId>>,
|
||||
/// Also known as the g-scores, or just g.
|
||||
scores: BTreeMap<G::NodeId, K>,
|
||||
/// Also known as the f-scores, or just f.
|
||||
estimate_scores: BTreeMap<G::NodeId, K>,
|
||||
cost_to_goal_estimate_scores: BTreeMap<G::NodeId, K>,
|
||||
#[getter(skip)]
|
||||
path_tracker: PathTracker<G>,
|
||||
// FIXME: To work around edge references borrowing from the graph we collect then reiterate over them.
|
||||
#[getter(skip)]
|
||||
edge_ids: Vec<G::EdgeId>,
|
||||
|
||||
#[getter(skip)]
|
||||
progress_estimate_value: K,
|
||||
|
||||
#[getter(skip)]
|
||||
progress_estimate_maximum: K,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Clone)]
|
||||
|
|
@ -183,29 +190,55 @@ where
|
|||
G: GraphBase,
|
||||
G::NodeId: Eq + Ord,
|
||||
for<'a> &'a G: IntoEdges<NodeId = G::NodeId, EdgeId = G::EdgeId> + MakeEdgeRef,
|
||||
K: Measure + Copy,
|
||||
K: Measure + Copy + Sub<Output = K>,
|
||||
{
|
||||
pub fn new<R>(
|
||||
graph: G,
|
||||
start: G::NodeId,
|
||||
strategy: &mut impl ThetastarStrategy<G, K, R>,
|
||||
) -> Self {
|
||||
let estimated_cost_from_start_to_goal = strategy.estimate_cost_to_goal(&graph, start);
|
||||
|
||||
let mut this = Self {
|
||||
state: ThetastarState::Scanning,
|
||||
graph,
|
||||
visit_next: BinaryHeap::new(),
|
||||
frontier: BinaryHeap::new(),
|
||||
scores: BTreeMap::new(),
|
||||
estimate_scores: BTreeMap::new(),
|
||||
cost_to_goal_estimate_scores: BTreeMap::new(),
|
||||
path_tracker: PathTracker::<G>::new(),
|
||||
edge_ids: Vec::new(),
|
||||
progress_estimate_value: K::default(),
|
||||
progress_estimate_maximum: estimated_cost_from_start_to_goal,
|
||||
};
|
||||
|
||||
let zero_score = K::default();
|
||||
this.scores.insert(start, zero_score);
|
||||
this.visit_next
|
||||
.push(MinScored(strategy.estimate_cost(&this.graph, start), start));
|
||||
this.frontier
|
||||
.push(MinScored(estimated_cost_from_start_to_goal, start));
|
||||
this
|
||||
}
|
||||
|
||||
fn push_to_frontier<R>(
|
||||
&mut self,
|
||||
next: G::NodeId,
|
||||
next_score: K,
|
||||
predecessor: G::NodeId,
|
||||
strategy: &mut impl ThetastarStrategy<G, K, R>,
|
||||
) {
|
||||
let cost_to_goal_estimate = strategy.estimate_cost_to_goal(&self.graph, next);
|
||||
|
||||
if cost_to_goal_estimate > self.progress_estimate_maximum {
|
||||
self.progress_estimate_maximum = cost_to_goal_estimate;
|
||||
}
|
||||
|
||||
if self.progress_estimate_maximum - cost_to_goal_estimate > self.progress_estimate_value {
|
||||
self.progress_estimate_value = self.progress_estimate_maximum - cost_to_goal_estimate;
|
||||
}
|
||||
|
||||
self.path_tracker.set_predecessor(next, predecessor);
|
||||
let next_estimate_score = next_score + cost_to_goal_estimate;
|
||||
self.frontier.push(MinScored(next_estimate_score, next));
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, K, R, S: ThetastarStrategy<G, K, R>>
|
||||
|
|
@ -214,7 +247,7 @@ where
|
|||
G: GraphBase,
|
||||
G::NodeId: Eq + Ord,
|
||||
for<'a> &'a G: IntoEdges<NodeId = G::NodeId, EdgeId = G::EdgeId> + MakeEdgeRef,
|
||||
K: Measure + Copy,
|
||||
K: Measure + Copy + Sub<Output = K>,
|
||||
{
|
||||
type Error = ThetastarError;
|
||||
|
||||
|
|
@ -227,7 +260,7 @@ where
|
|||
> {
|
||||
match self.state {
|
||||
ThetastarState::Scanning => {
|
||||
let Some(MinScored(estimate_score, navnode)) = self.visit_next.pop() else {
|
||||
let Some(MinScored(estimate_score, navnode)) = self.frontier.pop() else {
|
||||
return Err(ThetastarError::NotFound);
|
||||
};
|
||||
|
||||
|
|
@ -243,7 +276,7 @@ where
|
|||
return Ok(ControlFlow::Break((cost, path, result)));
|
||||
}
|
||||
|
||||
match self.estimate_scores.entry(navnode) {
|
||||
match self.cost_to_goal_estimate_scores.entry(navnode) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
// If the node has already been visited with an equal or lower
|
||||
// estimated score than now, then we do not need to re-visit it.
|
||||
|
|
@ -299,10 +332,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
self.path_tracker.set_predecessor(next, parent_navnode);
|
||||
let next_estimate_score =
|
||||
next_score + strategy.estimate_cost(&self.graph, next);
|
||||
self.visit_next.push(MinScored(next_estimate_score, next));
|
||||
self.push_to_frontier(next, next_score, parent_navnode, strategy);
|
||||
|
||||
self.state = ThetastarState::Probing(visited_navnode);
|
||||
Ok(ControlFlow::Continue(self.state))
|
||||
|
|
@ -353,10 +383,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
self.path_tracker.set_predecessor(next, visited_navnode);
|
||||
let next_estimate_score =
|
||||
next_score + strategy.estimate_cost(&self.graph, next);
|
||||
self.visit_next.push(MinScored(next_estimate_score, next));
|
||||
self.push_to_frontier(next, next_score, visited_navnode, strategy);
|
||||
|
||||
self.state = ThetastarState::Probing(visited_navnode);
|
||||
Ok(ControlFlow::Continue(self.state))
|
||||
|
|
@ -374,3 +401,21 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, K> EstimateProgress for ThetastarStepper<G, K>
|
||||
where
|
||||
G: GraphBase,
|
||||
G::NodeId: Eq + Ord,
|
||||
for<'a> &'a G: IntoEdges<NodeId = G::NodeId, EdgeId = G::EdgeId> + MakeEdgeRef,
|
||||
K: Measure + Copy + Sub<Output = K>,
|
||||
{
|
||||
type Value = K;
|
||||
|
||||
fn estimate_progress_value(&self) -> K {
|
||||
self.progress_estimate_value
|
||||
}
|
||||
|
||||
fn estimate_progress_maximum(&self) -> K {
|
||||
self.progress_estimate_maximum
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ use core::ops::ControlFlow;
|
|||
///
|
||||
/// An object that implements this trait is called a "stepper".
|
||||
///
|
||||
/// Steppers always progress linearly, that is, it is presumed that the context
|
||||
/// does not change between calls in a way that can affect the stepper's future
|
||||
/// states. Advanceable data structures designed for uses where the future state
|
||||
/// intentionally *may* change from the information supplied as arguments are
|
||||
/// not considered steppers. An example of such an advanceable non-stepper is
|
||||
/// the [`Navcord`](crate::router::navcord::Navcord) struct, as it does not progress
|
||||
/// linearly because it branches out by on each call taking in a
|
||||
/// changeable `to` argument that affects the future states.
|
||||
/// Steppers always progress linearly and their future states are determined by
|
||||
/// the initial state. It is assumed that the changes in context cannot change
|
||||
/// the stepper's execution. Advanceable data structures designed for uses where
|
||||
/// the future state intentionally *may* change from the information supplied
|
||||
/// after initialization are not considered steppers. An example of such an
|
||||
/// advanceable non-stepper is the [`Navcord`] (crate::router::navcord::Navcord)
|
||||
/// struct, as it does not progress linearly because it branches out on each
|
||||
/// call by taking in a changeable `to` argument that affects the future states.
|
||||
///
|
||||
/// Petgraph's counterpart of this trait is its
|
||||
/// [`petgraph::visit::Walker<Context>`] trait.
|
||||
|
|
@ -53,9 +53,25 @@ pub trait Abort<C> {
|
|||
fn abort(&mut self, context: &mut C);
|
||||
}
|
||||
|
||||
/// Steppers that may receive discrete events and act on them, implement this trait.
|
||||
/// Steppers that can receive discrete events and act on them, implement this
|
||||
/// trait.
|
||||
// XXX: Doesn't this violate the rule that stepper's future states are
|
||||
// determined by its initial state?
|
||||
pub trait OnEvent<Ctx, Event> {
|
||||
type Output;
|
||||
|
||||
fn on_event(&mut self, context: &mut Ctx, event: Event) -> Self::Output;
|
||||
}
|
||||
|
||||
/// Some steppers report estimates of how far they are from completion.
|
||||
pub trait EstimateProgress {
|
||||
type Value: Default;
|
||||
|
||||
fn estimate_progress_value(&self) -> Self::Value {
|
||||
Self::Value::default()
|
||||
}
|
||||
|
||||
fn estimate_progress_maximum(&self) -> Self::Value {
|
||||
Self::Value::default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue