cancel_this/triggers/
chain.rs1use crate::{CancelNever, CancellationTrigger, DynamicCancellationTrigger};
2
3#[derive(Clone, Default)]
10pub struct CancelChain(Vec<DynamicCancellationTrigger>);
11
12impl CancellationTrigger for CancelChain {
13 fn is_cancelled(&self) -> bool {
14 self.0.iter().rev().any(|t| t.is_cancelled())
16 }
17
18 fn type_name(&self) -> &'static str {
19 self.0
20 .iter()
21 .rev()
22 .find(|t| t.is_cancelled())
23 .map(|it| it.type_name())
24 .unwrap_or("CancelChain")
25 }
26}
27
28impl CancelChain {
29 pub fn pop(&mut self) -> Option<DynamicCancellationTrigger> {
31 self.0.pop()
32 }
33
34 pub fn push<T: CancellationTrigger + 'static>(&mut self, trigger: T) {
37 self.0.push(Box::new(trigger));
38 }
39
40 pub fn clone_and_flatten(&self) -> DynamicCancellationTrigger {
43 if self.0.is_empty() {
44 Box::new(CancelNever)
45 } else if self.0.len() == 1 {
46 self.0[0].clone()
47 } else {
48 Box::new(self.clone())
49 }
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use crate::{CancelAtomic, CancelChain, CancelTimer, CancellationTrigger};
56 use std::time::Duration;
57
58 #[test]
59 fn chain_flattening() {
60 let mut chain = CancelChain::default();
62 assert_eq!(chain.type_name(), "CancelChain");
63 assert_eq!(chain.clone_and_flatten().type_name(), "CancelNever");
64
65 let trigger = CancelAtomic::new();
67 chain.push(trigger.clone());
68 assert_eq!(chain.type_name(), "CancelChain");
69 assert_eq!(chain.clone_and_flatten().type_name(), "CancelAtomic");
70
71 let timer = CancelTimer::start(Duration::from_secs(1));
73 chain.push(timer);
74 assert_eq!(chain.type_name(), "CancelChain");
75 assert_eq!(chain.clone_and_flatten().type_name(), "CancelChain");
76
77 trigger.cancel();
79 assert_eq!(chain.type_name(), "CancelAtomic");
80 assert_eq!(chain.clone_and_flatten().type_name(), "CancelAtomic");
81 }
82}