use crate::{Stop, StopReason};
#[derive(Debug, Clone, Copy)]
pub struct OrStop<A, B> {
a: A,
b: B,
}
impl<A, B> OrStop<A, B> {
#[inline]
pub fn new(a: A, b: B) -> Self {
Self { a, b }
}
#[inline]
pub fn first(&self) -> &A {
&self.a
}
#[inline]
pub fn second(&self) -> &B {
&self.b
}
#[inline]
pub fn into_inner(self) -> (A, B) {
(self.a, self.b)
}
}
impl<A: Stop, B: Stop> Stop for OrStop<A, B> {
#[inline]
fn check(&self) -> Result<(), StopReason> {
self.a.check()?;
self.b.check()
}
#[inline]
fn should_stop(&self) -> bool {
self.a.should_stop() || self.b.should_stop()
}
#[inline]
fn may_stop(&self) -> bool {
self.a.may_stop() || self.b.may_stop()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{StopSource, Unstoppable};
#[test]
fn or_stop_neither() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
assert!(!combined.should_stop());
assert!(combined.check().is_ok());
}
#[test]
fn or_stop_first() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
a.cancel();
assert!(combined.should_stop());
assert_eq!(combined.check(), Err(StopReason::Cancelled));
}
#[test]
fn or_stop_second() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
b.cancel();
assert!(combined.should_stop());
assert_eq!(combined.check(), Err(StopReason::Cancelled));
}
#[test]
fn or_stop_both() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
a.cancel();
b.cancel();
assert!(combined.should_stop());
}
#[test]
fn or_stop_chain() {
let a = StopSource::new();
let b = StopSource::new();
let c = StopSource::new();
let combined = OrStop::new(OrStop::new(a.as_ref(), b.as_ref()), c.as_ref());
assert!(!combined.should_stop());
c.cancel();
assert!(combined.should_stop());
}
#[test]
fn or_stop_with_unstoppable() {
let source = StopSource::new();
let combined = OrStop::new(Unstoppable, source.as_ref());
assert!(!combined.should_stop());
source.cancel();
assert!(combined.should_stop());
}
#[test]
fn or_stop_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<OrStop<crate::StopRef<'_>, crate::StopRef<'_>>>();
}
#[test]
fn or_stop_accessors() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
assert!(!combined.first().should_stop());
assert!(!combined.second().should_stop());
a.cancel();
assert!(combined.first().should_stop());
let (first, second) = combined.into_inner();
assert!(first.should_stop());
assert!(!second.should_stop());
}
#[test]
fn or_stop_ref_is_copy() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
let combined2 = combined;
a.cancel();
assert!(combined.should_stop()); assert!(combined2.should_stop());
}
#[test]
fn or_stop_is_copy() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
let combined2 = combined; let _ = combined;
assert!(!combined2.should_stop());
}
#[test]
fn may_stop_both_unstoppable() {
let combined = OrStop::new(Unstoppable, Unstoppable);
assert!(!combined.may_stop());
}
#[test]
fn may_stop_one_side() {
let source = StopSource::new();
let combined = OrStop::new(Unstoppable, source.as_ref());
assert!(combined.may_stop());
}
#[test]
fn may_stop_both_sides() {
let a = StopSource::new();
let b = StopSource::new();
let combined = OrStop::new(a.as_ref(), b.as_ref());
assert!(combined.may_stop());
}
}