Skip to main content

trellis_runner/
procedure.rs

1use crate::CancellationGuard;
2
3/// Trait implemented by all problems solveable by `Trellis`
4///
5/// A procedure defines the core loop of the solver. Typically we would write a for loop,
6/// consisting of an initialisation step where the procedure is arranged, a procedure carried out
7/// on each loop iteration, and a finalisation step prior to return. This trait separates these
8/// methods so they can be called by the [`Runner`]
9pub trait Procedure<P> {
10    /// The type returned to the caller.
11    ///
12    /// Trellis defines a data-rich [`Output`], which can be constructed from the procedure, and
13    /// internal state. In some circumstances it may be appropriate to return this type to the
14    /// caller. In other circumstances it may be preferential to bury this complexity, returning
15    /// the caller a custom datatype.
16    type Output;
17
18    type State;
19
20    /// An identifier for the procedure.
21    ///
22    /// This identifier is printed in tracing logs
23    const NAME: &'static str;
24    /// Initialisation.
25    ///
26    /// This step prepares the state object for the main procedure loop.
27    fn initialise(&self, _problem: &mut P, _state: &mut Self::State) {}
28    /// One iteration of the core algorithm
29    fn step(&self, problem: &mut P, state: &mut Self::State, guard: CancellationGuard<'_>);
30
31    /// Converts the internal state to the user-facing return datatype
32    fn finalise(&self, problem: &mut P, state: &Self::State) -> Self::Output;
33}
34
35pub trait FallibleProcedure<P> {
36    type Error: std::error::Error + 'static + Send + Sync;
37
38    type Output;
39
40    type State;
41
42    /// An identifier for the procedure.
43    ///
44    /// This identifier is printed in tracing logs
45    const NAME: &'static str;
46
47    fn initialise_fallible(
48        &self,
49        _problem: &mut P,
50        _state: &mut Self::State,
51    ) -> Result<(), Self::Error>;
52
53    fn step_fallible(
54        &self,
55        problem: &mut P,
56        state: &mut Self::State,
57        guard: CancellationGuard<'_>,
58    ) -> Result<(), Self::Error>;
59
60    fn finalise_fallible(
61        &self,
62        problem: &mut P,
63        state: &Self::State,
64    ) -> Result<Self::Output, Self::Error>;
65}
66
67impl<Proc, P> FallibleProcedure<P> for Proc
68where
69    Proc: Procedure<P>,
70{
71    const NAME: &'static str = <Proc as Procedure<P>>::NAME;
72    type State = <Proc as Procedure<P>>::State;
73    type Output = <Proc as Procedure<P>>::Output;
74    type Error = std::convert::Infallible;
75
76    fn initialise_fallible(
77        &self,
78        problem: &mut P,
79        state: &mut Self::State,
80    ) -> Result<(), Self::Error> {
81        let _: () = self.initialise(problem, state);
82        Ok(())
83    }
84
85    fn step_fallible(
86        &self,
87        problem: &mut P,
88        state: &mut Self::State,
89        guard: CancellationGuard<'_>,
90    ) -> Result<(), Self::Error> {
91        let _: () = self.step(problem, state, guard);
92        Ok(())
93    }
94
95    fn finalise_fallible(
96        &self,
97        problem: &mut P,
98        state: &Self::State,
99    ) -> Result<Self::Output, Self::Error> {
100        Ok(self.finalise(problem, state))
101    }
102}