use crate::codec::LoopDecision;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "_loop", content = "value")]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
pub enum LoopResult<T> {
#[serde(rename = "again")]
Again(T),
#[serde(rename = "done")]
Done(T),
}
pub trait LoopOutput {
type Inner;
}
impl<T> LoopOutput for LoopResult<T> {
type Inner = T;
}
impl<T> LoopResult<T> {
#[must_use]
pub fn is_done(&self) -> bool {
matches!(self, Self::Done(_))
}
#[must_use]
pub fn is_again(&self) -> bool {
matches!(self, Self::Again(_))
}
#[must_use]
pub fn into_inner(self) -> T {
match self {
Self::Again(v) | Self::Done(v) => v,
}
}
#[must_use]
pub fn into_decision(self) -> (LoopDecision, T) {
match self {
Self::Again(v) => (LoopDecision::Again, v),
Self::Done(v) => (LoopDecision::Done, v),
}
}
}
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing
)]
mod tests {
use super::*;
#[test]
fn done_is_done() {
let r = LoopResult::Done(42);
assert!(r.is_done());
assert!(!r.is_again());
}
#[test]
fn again_is_again() {
let r = LoopResult::Again(42);
assert!(r.is_again());
assert!(!r.is_done());
}
#[test]
fn into_inner_done() {
assert_eq!(LoopResult::Done("hello").into_inner(), "hello");
}
#[test]
fn into_inner_again() {
assert_eq!(LoopResult::Again(99).into_inner(), 99);
}
#[test]
fn into_decision_done() {
let (decision, val) = LoopResult::Done(10).into_decision();
assert_eq!(decision, LoopDecision::Done);
assert_eq!(val, 10);
}
#[test]
fn into_decision_again() {
let (decision, val) = LoopResult::Again(5).into_decision();
assert_eq!(decision, LoopDecision::Again);
assert_eq!(val, 5);
}
#[test]
fn serde_round_trip_done() {
let r = LoopResult::Done(42u32);
let json = serde_json::to_string(&r).unwrap();
let back: LoopResult<u32> = serde_json::from_str(&json).unwrap();
assert!(back.is_done());
assert_eq!(back.into_inner(), 42);
}
#[test]
fn serde_round_trip_again() {
let r = LoopResult::Again("next".to_string());
let json = serde_json::to_string(&r).unwrap();
let back: LoopResult<String> = serde_json::from_str(&json).unwrap();
assert!(back.is_again());
assert_eq!(back.into_inner(), "next");
}
}