Skip to content

Commit 9aeb04f

Browse files
authored
feat(core): async_runtime handle API, spawn returns JoinHandle (#2399)
1 parent bdda79c commit 9aeb04f

File tree

6 files changed

+97
-9
lines changed

6 files changed

+97
-9
lines changed

.changes/async-runtime-handle-api.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
Add `handle` API to `tauri::async_runtime`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
**Breaking change:** The `tauri::async_runtime::spawn` function now returns `tauri::async_runtime::JoinHandle<T>`.

core/tauri/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ os_pipe = { version = "0.9", optional = true }
6969
rfd = "0.4.2"
7070
raw-window-handle = { version = "0.3.3", optional = true }
7171
minisign-verify = { version = "0.1", optional = true }
72-
os_info = { version = "3.0.6", optional = true}
72+
os_info = { version = "3.0.6", optional = true }
73+
futures-lite = "1.12"
7374

7475
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
7576
gtk = { version = "0.14", features = [ "v3_20" ] }
@@ -86,6 +87,7 @@ serde = { version = "1.0", features = [ "derive" ] }
8687
quickcheck = "1.0.3"
8788
quickcheck_macros = "1.0.0"
8889
tokio-test = "0.4.2"
90+
tokio = { version = "1.9", features = [ "full" ] }
8991
mockito = "0.30"
9092

9193
[features]

core/tauri/src/async_runtime.rs

+79-6
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,102 @@
77
//! Fox more complex use cases, consider creating your own runtime.
88
//! For command handlers, it's recommended to use a plain `async fn` command.
99
10+
use futures_lite::future::FutureExt;
1011
use once_cell::sync::OnceCell;
1112
use tokio::runtime::Runtime;
12-
pub use tokio::sync::{
13-
mpsc::{channel, Receiver, Sender},
14-
Mutex, RwLock,
13+
pub use tokio::{
14+
runtime::Handle,
15+
sync::{
16+
mpsc::{channel, Receiver, Sender},
17+
Mutex, RwLock,
18+
},
19+
task::JoinHandle as TokioJoinHandle,
1520
};
1621

17-
use std::future::Future;
22+
use std::{
23+
fmt,
24+
future::Future,
25+
pin::Pin,
26+
task::{Context, Poll},
27+
};
1828

1929
static RUNTIME: OnceCell<Runtime> = OnceCell::new();
2030

31+
/// An owned permission to join on a task (await its termination).
32+
#[derive(Debug)]
33+
pub struct JoinHandle<T>(TokioJoinHandle<T>);
34+
35+
impl<T> Future for JoinHandle<T> {
36+
type Output = crate::Result<T>;
37+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
38+
self
39+
.0
40+
.poll(cx)
41+
.map_err(|e| crate::Error::JoinError(Box::new(e)))
42+
}
43+
}
44+
45+
/// Runtime handle definition.
46+
pub trait RuntimeHandle: fmt::Debug + Clone + Sync + Sync {
47+
/// Spawn a future onto the runtime.
48+
fn spawn<F: Future>(&self, task: F) -> JoinHandle<F::Output>
49+
where
50+
F: Future + Send + 'static,
51+
F::Output: Send + 'static;
52+
53+
/// Run a future to completion on runtime.
54+
fn block_on<F: Future>(&self, task: F) -> F::Output;
55+
}
56+
57+
impl RuntimeHandle for Handle {
58+
fn spawn<F: Future>(&self, task: F) -> JoinHandle<F::Output>
59+
where
60+
F: Future + Send + 'static,
61+
F::Output: Send + 'static,
62+
{
63+
JoinHandle(self.spawn(task))
64+
}
65+
66+
fn block_on<F: Future>(&self, task: F) -> F::Output {
67+
self.block_on(task)
68+
}
69+
}
70+
71+
/// Returns a handle to the async runtime.
72+
pub fn handle() -> impl RuntimeHandle {
73+
let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap());
74+
runtime.handle().clone()
75+
}
76+
2177
/// Run a future to completion on runtime.
2278
pub fn block_on<F: Future>(task: F) -> F::Output {
2379
let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap());
2480
runtime.block_on(task)
2581
}
2682

2783
/// Spawn a future onto the runtime.
28-
pub fn spawn<F>(task: F)
84+
pub fn spawn<F>(task: F) -> JoinHandle<F::Output>
2985
where
3086
F: Future + Send + 'static,
3187
F::Output: Send + 'static,
3288
{
3389
let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap());
34-
runtime.spawn(task);
90+
JoinHandle(runtime.spawn(task))
91+
}
92+
93+
#[cfg(test)]
94+
mod tests {
95+
use super::*;
96+
#[tokio::test]
97+
async fn handle_spawn() {
98+
let handle = handle();
99+
let join = handle.spawn(async { 5 });
100+
assert_eq!(join.await.unwrap(), 5);
101+
}
102+
103+
#[test]
104+
fn handle_block_on() {
105+
let handle = handle();
106+
assert_eq!(handle.block_on(async { 0 }), 0);
107+
}
35108
}

core/tauri/src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ pub enum Error {
8080
/// user-provided URLs and paths.
8181
#[error("invalid url: {0}")]
8282
InvalidUrl(url::ParseError),
83+
/// Task join error.
84+
#[error(transparent)]
85+
JoinError(Box<dyn std::error::Error + Send>),
8386
}
8487

8588
impl From<serde_json::Error> for Error {

core/tauri/src/updater/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ pub(crate) fn listener<R: Runtime>(
490490
// emit {"status": "DONE"}
491491
send_status_update(window.clone(), EVENT_STATUS_SUCCESS, None);
492492
}
493-
})
493+
});
494494
});
495495
} else {
496496
send_status_update(window.clone(), EVENT_STATUS_UPTODATE, None);
@@ -500,7 +500,7 @@ pub(crate) fn listener<R: Runtime>(
500500
send_status_update(window.clone(), EVENT_STATUS_ERROR, Some(e.to_string()));
501501
}
502502
}
503-
})
503+
});
504504
});
505505
}
506506

0 commit comments

Comments
 (0)