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}