nrf_modem/
cancellation.rs

1use crate::Error;
2use core::{
3    sync::atomic::{AtomicBool, Ordering},
4    task::{Context, Poll},
5};
6use futures::task::AtomicWaker;
7
8/// A token you can pass to certain async functions that let you cancel them.
9///
10/// This can be nice for example when you have a task that is 'stuck' receiving data that never arrives,
11/// but you want it to stop doing that so it can continue doing something else.
12#[derive(Default)]
13pub struct CancellationToken {
14    canceled: AtomicBool,
15    waker: AtomicWaker,
16}
17
18impl CancellationToken {
19    /// Create a new token
20    pub const fn new() -> Self {
21        Self {
22            canceled: AtomicBool::new(false),
23            waker: AtomicWaker::new(),
24        }
25    }
26
27    /// Registers the waker of the task that executes this function.
28    /// When the cancel function is called, the waker is used to wake the future for which this token is used.
29    pub(crate) async fn bind_to_current_task(&self) {
30        core::future::poll_fn(|cx| {
31            self.bind_to_context(cx);
32            Poll::Ready(())
33        })
34        .await;
35    }
36
37    pub(crate) fn bind_to_context(&self, cx: &Context) {
38        self.waker.register(cx.waker())
39    }
40
41    /// Set the token to cancel the operation that uses this token.
42    ///
43    /// This may not cancel the task immediately because that may not always be possible.
44    pub fn cancel(&self) {
45        self.canceled.store(true, Ordering::SeqCst);
46        self.waker.wake();
47    }
48
49    /// Returns whether or not the cancel function has been called already
50    pub fn is_cancelled(&self) -> bool {
51        self.canceled.load(Ordering::SeqCst)
52    }
53
54    /// Restore the token to the non-cancelled state. This can be used so you can reuse the same token multiple times.
55    ///
56    /// Calling this may prevent a cancellation, but the cancellation may have already started.
57    pub fn restore(&self) {
58        self.canceled.store(false, Ordering::SeqCst);
59    }
60
61    /// Creates a result of this type to the `?` operator can be used to return from code.
62    ///
63    /// It returns an OK if the token hasn't been cancelled yet and an error if it has been cancelled.
64    pub(crate) fn as_result(&self) -> Result<(), Error> {
65        match self.is_cancelled() {
66            true => Err(Error::OperationCancelled),
67            false => Ok(()),
68        }
69    }
70}