feat(core): async_runtime handle API, spawn returns JoinHandle (#2399)

This commit is contained in:
Lucas Fernandes Nogueira 2021-08-11 21:49:09 -03:00 committed by GitHub
parent bdda79cfbc
commit 9aeb04faf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 9 deletions

View File

@ -0,0 +1,5 @@
---
"tauri": patch
---
Add `handle` API to `tauri::async_runtime`.

View File

@ -0,0 +1,5 @@
---
"tauri": patch
---
**Breaking change:** The `tauri::async_runtime::spawn` function now returns `tauri::async_runtime::JoinHandle<T>`.

View File

@ -69,7 +69,8 @@ os_pipe = { version = "0.9", optional = true }
rfd = "0.4.2"
raw-window-handle = { version = "0.3.3", optional = true }
minisign-verify = { version = "0.1", optional = true }
os_info = { version = "3.0.6", optional = true}
os_info = { version = "3.0.6", optional = true }
futures-lite = "1.12"
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
gtk = { version = "0.14", features = [ "v3_20" ] }
@ -86,6 +87,7 @@ serde = { version = "1.0", features = [ "derive" ] }
quickcheck = "1.0.3"
quickcheck_macros = "1.0.0"
tokio-test = "0.4.2"
tokio = { version = "1.9", features = [ "full" ] }
mockito = "0.30"
[features]

View File

@ -7,17 +7,73 @@
//! Fox more complex use cases, consider creating your own runtime.
//! For command handlers, it's recommended to use a plain `async fn` command.
use futures_lite::future::FutureExt;
use once_cell::sync::OnceCell;
use tokio::runtime::Runtime;
pub use tokio::sync::{
mpsc::{channel, Receiver, Sender},
Mutex, RwLock,
pub use tokio::{
runtime::Handle,
sync::{
mpsc::{channel, Receiver, Sender},
Mutex, RwLock,
},
task::JoinHandle as TokioJoinHandle,
};
use std::future::Future;
use std::{
fmt,
future::Future,
pin::Pin,
task::{Context, Poll},
};
static RUNTIME: OnceCell<Runtime> = OnceCell::new();
/// An owned permission to join on a task (await its termination).
#[derive(Debug)]
pub struct JoinHandle<T>(TokioJoinHandle<T>);
impl<T> Future for JoinHandle<T> {
type Output = crate::Result<T>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self
.0
.poll(cx)
.map_err(|e| crate::Error::JoinError(Box::new(e)))
}
}
/// Runtime handle definition.
pub trait RuntimeHandle: fmt::Debug + Clone + Sync + Sync {
/// Spawn a future onto the runtime.
fn spawn<F: Future>(&self, task: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static;
/// Run a future to completion on runtime.
fn block_on<F: Future>(&self, task: F) -> F::Output;
}
impl RuntimeHandle for Handle {
fn spawn<F: Future>(&self, task: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
JoinHandle(self.spawn(task))
}
fn block_on<F: Future>(&self, task: F) -> F::Output {
self.block_on(task)
}
}
/// Returns a handle to the async runtime.
pub fn handle() -> impl RuntimeHandle {
let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap());
runtime.handle().clone()
}
/// Run a future to completion on runtime.
pub fn block_on<F: Future>(task: F) -> F::Output {
let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap());
@ -25,11 +81,28 @@ pub fn block_on<F: Future>(task: F) -> F::Output {
}
/// Spawn a future onto the runtime.
pub fn spawn<F>(task: F)
pub fn spawn<F>(task: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap());
runtime.spawn(task);
JoinHandle(runtime.spawn(task))
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn handle_spawn() {
let handle = handle();
let join = handle.spawn(async { 5 });
assert_eq!(join.await.unwrap(), 5);
}
#[test]
fn handle_block_on() {
let handle = handle();
assert_eq!(handle.block_on(async { 0 }), 0);
}
}

View File

@ -80,6 +80,9 @@ pub enum Error {
/// user-provided URLs and paths.
#[error("invalid url: {0}")]
InvalidUrl(url::ParseError),
/// Task join error.
#[error(transparent)]
JoinError(Box<dyn std::error::Error + Send>),
}
impl From<serde_json::Error> for Error {

View File

@ -490,7 +490,7 @@ pub(crate) fn listener<R: Runtime>(
// emit {"status": "DONE"}
send_status_update(window.clone(), EVENT_STATUS_SUCCESS, None);
}
})
});
});
} else {
send_status_update(window.clone(), EVENT_STATUS_UPTODATE, None);
@ -500,7 +500,7 @@ pub(crate) fn listener<R: Runtime>(
send_status_update(window.clone(), EVENT_STATUS_ERROR, Some(e.to_string()));
}
}
})
});
});
}