Skip to main content

trellis_runner/
procedure.rs

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