vv_agent/runtime/
cancellation.rs1use std::sync::atomic::{AtomicBool, Ordering};
2use std::sync::{Arc, Mutex};
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct CancelledError {
6 message: String,
7}
8
9impl CancelledError {
10 pub fn new(message: impl Into<String>) -> Self {
11 Self {
12 message: message.into(),
13 }
14 }
15
16 pub fn message(&self) -> &str {
17 &self.message
18 }
19}
20
21impl std::fmt::Display for CancelledError {
22 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 formatter.write_str(&self.message)
24 }
25}
26
27impl std::error::Error for CancelledError {}
28
29#[derive(Clone, Default)]
30pub struct CancellationToken {
31 inner: Arc<CancellationState>,
32}
33
34#[derive(Default)]
35struct CancellationState {
36 cancelled: AtomicBool,
37 callbacks: Mutex<Vec<Arc<dyn Fn() + Send + Sync + 'static>>>,
38}
39
40impl std::fmt::Debug for CancellationToken {
41 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 formatter
43 .debug_struct("CancellationToken")
44 .field("cancelled", &self.is_cancelled())
45 .finish()
46 }
47}
48
49impl CancellationToken {
50 pub fn cancel(&self) {
51 if self.inner.cancelled.swap(true, Ordering::SeqCst) {
52 return;
53 }
54 let callbacks = std::mem::take(
55 &mut *self
56 .inner
57 .callbacks
58 .lock()
59 .expect("cancellation callbacks lock"),
60 );
61 for callback in callbacks {
62 callback();
63 }
64 }
65
66 pub fn is_cancelled(&self) -> bool {
67 self.inner.cancelled.load(Ordering::SeqCst)
68 }
69
70 pub fn cancelled(&self) -> bool {
71 self.is_cancelled()
72 }
73
74 pub fn check(&self) -> Result<(), String> {
75 if self.is_cancelled() {
76 Err("Operation was cancelled".to_string())
77 } else {
78 Ok(())
79 }
80 }
81
82 pub fn on_cancel(&self, callback: impl Fn() + Send + Sync + 'static) {
83 let callback: Arc<dyn Fn() + Send + Sync + 'static> = Arc::new(callback);
84 let call_immediately = {
85 let mut callbacks = self
86 .inner
87 .callbacks
88 .lock()
89 .expect("cancellation callbacks lock");
90 if self.is_cancelled() {
91 true
92 } else {
93 callbacks.push(callback.clone());
94 false
95 }
96 };
97 if call_immediately {
98 callback();
99 }
100 }
101
102 pub fn child(&self) -> Self {
103 let child = Self::default();
104 let child_to_cancel = child.clone();
105 self.on_cancel(move || child_to_cancel.cancel());
106 child
107 }
108}