use core::num::{NonZeroU32, NonZeroU64};
use crate::{Participant, TimerCancellationRefusal, TimerOut, storage::warp_table::Capacity};
use super::*;
struct Worker;
struct Completed;
impl Participant for Worker {
type In<'message> = ();
type Out<'message> = Completed;
}
#[kani::proof]
#[kani::unwind(10)]
fn exactly_one_of_completion_or_expiry_resolves_an_admitted_continuation() {
let capacity = Capacity::new(NonZeroU32::MIN);
let Ok(mut ledger) = ContinuationLedger::<()>::try_new(capacity) else {
return;
};
let owed = Owed::wait(TimeoutAfter::nanoseconds(NonZeroU64::MIN));
let ContinuationAdmissionOutcome::Admitted { admission } = ledger.admit::<Worker>((), owed)
else {
return;
};
let token = admission.timer_token();
let Ok(armed) = (TimerOut::Armed { token }).into_arm_outcome() else {
return;
};
let Ok(ContinuationArmOutcome::Armed { work }) = admission.settle_timer_arm(armed) else {
return;
};
let completion = work.fulfill(Completed);
if kani::any::<bool>() {
let Ok(cancelled) = (TimerOut::Cancelled { token }).into_cancellation_outcome() else {
return;
};
let Ok(ContinuationCancellationOutcome::Cancelled { completion }) =
completion.settle_timer_cancellation(cancelled)
else {
return;
};
assert!(matches!(
ledger.resolve(completion),
ContinuationResolutionOutcome::Resolved { .. }
));
assert!(matches!(
ledger.expire(token),
ContinuationExpirationOutcome::Stale { .. }
));
} else {
assert!(matches!(
ledger.expire(token),
ContinuationExpirationOutcome::Expired { .. }
));
let Ok(refused) = (TimerOut::CancellationRefused {
token,
reason: TimerCancellationRefusal::NotArmed,
})
.into_cancellation_outcome() else {
return;
};
assert!(matches!(
completion.settle_timer_cancellation(refused),
Ok(ContinuationCancellationOutcome::Stale { .. })
));
}
assert!(ledger.is_empty());
}