use rustev_contract::remote::{CancelSupport, RemoteCode};
use rustev_contract::run::Charge;
use rustev_core::seams::{AdapterFailure, AttemptReport, CancelAck, RemoteEnd};
use crate::taxonomy::failure_detail;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CancelOutcome {
pub ack: CancelAck,
pub charge: Charge,
pub remote: RemoteEnd,
}
pub fn cancel_outcome(
sent: bool,
support: CancelSupport,
confirmed_charge: Option<Charge>,
) -> CancelOutcome {
if !sent {
return CancelOutcome {
ack: CancelAck::Stopped,
charge: Charge::Observed { units: 0 },
remote: RemoteEnd::Finished,
};
}
match (support, confirmed_charge) {
(CancelSupport::Confirmed, Some(c)) if c != Charge::Unknown => CancelOutcome {
ack: CancelAck::Stopped,
charge: c,
remote: RemoteEnd::Finished,
},
_ => CancelOutcome {
ack: CancelAck::Unconfirmed,
charge: Charge::Unknown,
remote: RemoteEnd::PossiblyContinuing,
},
}
}
pub fn cancelled_report(outcome: CancelOutcome, detail: &str) -> AttemptReport {
AttemptReport {
result: Err((
AdapterFailure::Cancelled,
failure_detail(RemoteCode::Cancelled, detail),
)),
charge: outcome.charge,
cancel: outcome.ack,
remote: outcome.remote,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stopped_only_when_unsent_or_confirmed() {
for support in [
CancelSupport::None,
CancelSupport::BestEffort,
CancelSupport::Confirmed,
] {
let o = cancel_outcome(false, support, None);
assert_eq!(
(o.ack, o.charge),
(CancelAck::Stopped, Charge::Observed { units: 0 })
);
let o = cancel_outcome(true, support, None);
assert_eq!((o.ack, o.charge), (CancelAck::Unconfirmed, Charge::Unknown));
assert_eq!(o.remote, RemoteEnd::PossiblyContinuing);
}
let c = Some(Charge::Observed { units: 2 });
assert_eq!(
cancel_outcome(true, CancelSupport::Confirmed, c).ack,
CancelAck::Stopped
);
assert_eq!(
cancel_outcome(true, CancelSupport::BestEffort, c).ack,
CancelAck::Unconfirmed
);
assert_eq!(
cancel_outcome(true, CancelSupport::Confirmed, Some(Charge::Unknown)).ack,
CancelAck::Unconfirmed
);
}
}