1use std::fmt;
8use std::io::{self, Read};
9use std::sync::atomic::{AtomicBool, Ordering};
10use std::sync::Arc;
11use std::time::{Duration, Instant};
12
13#[derive(Debug, Clone, Default)]
15pub struct CancelToken {
16 flag: Arc<AtomicBool>,
17}
18
19impl CancelToken {
20 pub fn new() -> Self {
21 Self::default()
22 }
23 pub fn from_flag(flag: Arc<AtomicBool>) -> Self {
26 Self { flag }
27 }
28 pub fn flag(&self) -> &Arc<AtomicBool> {
30 &self.flag
31 }
32 pub fn cancel(&self) {
34 self.flag.store(true, Ordering::SeqCst);
35 }
36 pub fn is_cancelled(&self) -> bool {
37 self.flag.load(Ordering::SeqCst)
38 }
39 pub fn as_atomic(&self) -> &AtomicBool {
41 &self.flag
42 }
43}
44
45#[derive(Debug)]
47pub(crate) struct CancelledIo;
48
49impl fmt::Display for CancelledIo {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.write_str("request cancelled")
52 }
53}
54
55impl std::error::Error for CancelledIo {}
56
57pub(crate) fn cancelled_io() -> io::Error {
58 io::Error::other(CancelledIo)
59}
60
61pub fn is_cancelled_io(err: &io::Error) -> bool {
63 err.get_ref().is_some_and(|inner| inner.is::<CancelledIo>())
64}
65
66pub(crate) fn is_set(cancel: Option<&AtomicBool>) -> bool {
67 cancel.is_some_and(|flag| flag.load(Ordering::SeqCst))
68}
69
70pub(crate) fn sleep_cancellable(total: Duration, cancel: Option<&AtomicBool>) -> bool {
73 let until = Instant::now() + total;
74 loop {
75 if is_set(cancel) {
76 return false;
77 }
78 let now = Instant::now();
79 if now >= until {
80 return true;
81 }
82 std::thread::sleep((until - now).min(Duration::from_millis(50)));
83 }
84}
85
86pub(crate) struct CheckedReader<'a> {
88 pub(crate) inner: &'a mut dyn Read,
89 pub(crate) cancel: Option<&'a AtomicBool>,
90}
91
92impl Read for CheckedReader<'_> {
93 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
94 if is_set(self.cancel) {
95 return Err(cancelled_io());
96 }
97 self.inner.read(buf)
98 }
99}