scuttle_core/
termination.rs1use std::fmt;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum Termination {
11 PPLimit,
13 SolsLimit,
15 CandidatesLimit,
17 OracleCallsLimit,
19 Interrupted,
21}
22
23impl fmt::Display for Termination {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Termination::PPLimit => {
27 write!(f, "Solver terminated early because of Pareto point limit")
28 }
29 Termination::SolsLimit => {
30 write!(f, "Solver terminated early because of solution limit")
31 }
32 Termination::CandidatesLimit => {
33 write!(f, "Solver terminated early because of candidate limit")
34 }
35 Termination::OracleCallsLimit => {
36 write!(f, "Solver terminated early because of oracle call limit")
37 }
38 Termination::Interrupted => {
39 write!(f, "Solver terminated early because of interrupt signal")
40 }
41 }
42 }
43}
44
45#[derive(Debug, PartialEq)]
47pub enum MaybeTerminated<T = ()> {
48 Done(T),
50 Terminated(Termination),
52}
53
54impl<T> MaybeTerminated<T> {
55 pub fn unwrap(self) -> T {
56 match self {
57 MaybeTerminated::Done(val) => val,
58 MaybeTerminated::Terminated(term) => {
59 panic!("called `MaybeTerminated::unwrap()` on a `Terminated` value: {term}")
60 }
61 }
62 }
63}
64
65impl<T> std::ops::Try for MaybeTerminated<T> {
66 type Output = T;
67
68 type Residual = MaybeTerminated<std::convert::Infallible>;
69
70 fn from_output(output: Self::Output) -> Self {
71 MaybeTerminated::Done(output)
72 }
73
74 fn branch(self) -> std::ops::ControlFlow<Self::Residual, Self::Output> {
75 match self {
76 MaybeTerminated::Done(val) => std::ops::ControlFlow::Continue(val),
77 MaybeTerminated::Terminated(term) => {
78 std::ops::ControlFlow::Break(MaybeTerminated::Terminated(term))
79 }
80 }
81 }
82}
83
84impl<T> std::ops::FromResidual<MaybeTerminated<std::convert::Infallible>> for MaybeTerminated<T> {
85 fn from_residual(residual: <Self as std::ops::Try>::Residual) -> Self {
86 let MaybeTerminated::Terminated(term) = residual;
87 MaybeTerminated::Terminated(term)
88 }
89}
90
91#[derive(Debug)]
93pub enum MaybeTerminatedError<T = ()> {
94 Done(T),
96 Terminated(Termination),
98 Error(anyhow::Error),
100}
101
102impl<T> MaybeTerminatedError<T> {
103 pub fn unwrap(self) -> T {
104 match self {
105 MaybeTerminatedError::Done(val) => val,
106 MaybeTerminatedError::Terminated(term) => {
107 panic!("called `MaybeTerminatedError::unwrap()` on a `Terminated` value: {term}")
108 }
109 MaybeTerminatedError::Error(err) => {
110 panic!("called `MaybeTerminatedError::unwrap()` on an `Error` value: {err}")
111 }
112 }
113 }
114}
115
116impl<T> From<MaybeTerminated<T>> for MaybeTerminatedError<T> {
117 fn from(value: MaybeTerminated<T>) -> Self {
118 match value {
119 MaybeTerminated::Done(val) => MaybeTerminatedError::Done(val),
120 MaybeTerminated::Terminated(term) => MaybeTerminatedError::Terminated(term),
121 }
122 }
123}
124
125impl<T> From<anyhow::Result<T>> for MaybeTerminatedError<T> {
126 fn from(value: anyhow::Result<T>) -> Self {
127 match value {
128 Ok(val) => MaybeTerminatedError::Done(val),
129 Err(err) => MaybeTerminatedError::Error(err),
130 }
131 }
132}
133
134impl<T> std::ops::Try for MaybeTerminatedError<T> {
135 type Output = T;
136
137 type Residual = MaybeTerminatedError<std::convert::Infallible>;
138
139 fn from_output(output: Self::Output) -> Self {
140 MaybeTerminatedError::Done(output)
141 }
142
143 fn branch(self) -> std::ops::ControlFlow<Self::Residual, Self::Output> {
144 match self {
145 MaybeTerminatedError::Done(val) => std::ops::ControlFlow::Continue(val),
146 MaybeTerminatedError::Terminated(term) => {
147 std::ops::ControlFlow::Break(MaybeTerminatedError::Terminated(term))
148 }
149 MaybeTerminatedError::Error(err) => {
150 std::ops::ControlFlow::Break(MaybeTerminatedError::Error(err))
151 }
152 }
153 }
154}
155
156impl<T> std::ops::FromResidual<MaybeTerminatedError<std::convert::Infallible>>
157 for MaybeTerminatedError<T>
158{
159 fn from_residual(residual: <Self as std::ops::Try>::Residual) -> Self {
160 match residual {
161 MaybeTerminatedError::Terminated(term) => MaybeTerminatedError::Terminated(term),
162 MaybeTerminatedError::Error(err) => MaybeTerminatedError::Error(err),
163 }
164 }
165}
166
167impl<T> std::ops::FromResidual<MaybeTerminated<std::convert::Infallible>>
168 for MaybeTerminatedError<T>
169{
170 fn from_residual(residual: MaybeTerminated<std::convert::Infallible>) -> Self {
171 let MaybeTerminated::Terminated(term) = residual;
172 MaybeTerminatedError::Terminated(term)
173 }
174}
175
176impl<T, E> std::ops::FromResidual<Result<std::convert::Infallible, E>> for MaybeTerminatedError<T>
177where
178 E: Into<anyhow::Error>,
179{
180 fn from_residual(residual: Result<std::convert::Infallible, E>) -> Self {
181 let Err(err) = residual;
182 MaybeTerminatedError::Error(err.into())
183 }
184}
185
186macro_rules! ensure {
188 ($cond:expr, $msg:literal) => {
189 if !$cond {
190 return crate::MaybeTerminatedError::Error(anyhow::anyhow!($msg));
191 }
192 };
193 ($cond:expr, $err:expr) => {
194 if !$cond {
195 return crate::MaybeTerminatedError::Error(anyhow::anyhow!($err));
196 }
197 };
198 ($cond:expr, $fmt:expr, $($arg:tt)*) => {
199 if !$cond {
200 return crate::MaybeTerminatedError::Error(anyhow::anyhow!($fmt, $($arg)*));
201 }
202 };
203}
204pub(crate) use ensure;