blob: eea57b6a0a6e79ff47440f16ae471f0538073d32 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
use std::ptr::null_mut;
use tokio::task::JoinHandle;
use super::{completion::SwiftCompletionHandler, response::SwiftMullvadApiResponse};
#[repr(C)]
pub struct SwiftCancelHandle {
ptr: *mut RequestCancelHandle,
}
impl SwiftCancelHandle {
pub fn empty() -> Self {
Self { ptr: null_mut() }
}
/// This consumes and nulls out the pointer. The caller is responsible for the pointer being valid
/// when calling `to_handle`.
///
/// SAFETY:
/// This call is safe as long as the pointer is only ever used from a single thread and the
/// instance of `SwiftCancelHandle` was created with a valid pointer to
/// `RequestCancelHandle`.
unsafe fn as_handle(&mut self) -> RequestCancelHandle {
// SAFETY: See safety notes above
let handle = unsafe { *Box::from_raw(self.ptr) };
self.ptr = null_mut();
handle
}
}
pub struct RequestCancelHandle {
task: JoinHandle<()>,
completion: SwiftCompletionHandler,
}
impl RequestCancelHandle {
pub fn new(task: JoinHandle<()>, completion: SwiftCompletionHandler) -> Self {
Self { task, completion }
}
pub fn into_swift(self) -> SwiftCancelHandle {
SwiftCancelHandle {
ptr: Box::into_raw(Box::new(self)),
}
}
pub fn cancel(self) {
let Self { task, completion } = self;
task.abort();
// TODO: should this call block until the task returns?
// We can make it do that.
// let _ = handle.block_on(self.task);
completion.finish(SwiftMullvadApiResponse::cancelled());
}
}
/// Called by the Swift side to signal that a Mullvad API call should be cancelled.
/// After this call, the cancel token is no longer valid.
///
/// # Safety
///
/// `handle_ptr` must be pointing to a valid instance of `SwiftCancelHandle`.
#[unsafe(no_mangle)]
extern "C" fn mullvad_api_cancel_task(handle_ptr: &mut SwiftCancelHandle) {
if handle_ptr.ptr.is_null() {
return;
}
// SAFETY: See notes for `as_handle`
let handle = unsafe { handle_ptr.as_handle() };
handle.cancel()
}
/// Called by the Swift side to signal that the Rust `SwiftCancelHandle` can be safely
/// dropped from memory.
///
/// # Safety
///
/// `handle_ptr` must be pointing to a valid instance of `SwiftCancelHandle`.
#[unsafe(no_mangle)]
extern "C" fn mullvad_api_cancel_task_drop(handle_ptr: &mut SwiftCancelHandle) {
if handle_ptr.ptr.is_null() {
return;
}
// SAFETY: See notes for `as_handle`
let _handle = unsafe { handle_ptr.as_handle() };
}
|