Convert Option<T>
into ControlFlow<T, _>
or ControlFlow<_, T>
.
Analogically to ok_or
and ok_or_else
for converting into Result
, this crate introduces:
break_or
/continue_or
,break_or_else
/continue_or_else
andbreak_or_default
/continue_or_default
for converting intoControlFlow
.
Since ControlFlow
is more symmetrical than Result
, functions exist for converting the Some
variant both into Break
and Continue
.
Suppose you are receiving some messages:
async fn process_messages(mut msgs: mpsc::Receiver<i32>) {
while let Some(msg) = msgs.recv().await {
println!("msg = {}", msg)
}
}
but now you need to support cancellation, so you do this:
async fn process_messages(mut msgs: mpsc::Receiver<i32>, token: CancellationToken) {
while let Some(msg) = select! { biased;
_ = token.cancelled() => None,
m = msgs.recv() => m,
} {
println!("msg = {}", msg)
}
}
and that's fine, but now you're using Option
for controlling flow. None
used to mean there will
be no more messages. This is semantically correct for a receiver and it's fine to pattern-match on
it in a loop condition. But now, None
means "there will be no more messages OR processing is
cancelled". As the logic becomes more complicated, you might want to pattern-match on
ControlFlow::Continue
instead, which is there for a reason - it conveys whether to continue or to
break.
So you can do this:
async fn process_messages(mut msgs: mpsc::Receiver<i32>, token: CancellationToken) {
while let ControlFlow::Continue(msg) = select! { biased;
_ = token.cancelled() => ControlFlow::Break(()),
m = msgs.recv() => {
if let Some(m) = m {
ControlFlow::Continue(m)
} else {
ControlFlow::Break(())
}
},
} {
println!("msg = {}", msg)
}
}
but it's so verbose, so, of course, you use option_into_controlflow
:
async fn process_messages(mut msgs: mpsc::Receiver<i32>, token: CancellationToken) {
while let ControlFlow::Continue(msg) = select! { biased;
_ = token.cancelled() => ControlFlow::Break(()),
m = msgs.recv() => m.continue_or(()),
} {
println!("msg = {}", msg)
}
}
which is the best of both worlds - you no longer use Option
for controlling the loop, but your
code becomes semantic, idiomatic and understandable.