fyrox_core/
task.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21#[cfg(not(target_arch = "wasm32"))]
22use crate::futures::executor::ThreadPool;
23use parking_lot::Mutex;
24use std::{
25    any::Any,
26    future::Future,
27    sync::mpsc::{self, Receiver, Sender},
28};
29use uuid::Uuid;
30
31// ========
32// Non-WASM
33#[cfg(not(target_arch = "wasm32"))]
34pub trait AsyncTaskResult: Any + Send + 'static {
35    fn into_any(self: Box<Self>) -> Box<dyn Any>;
36}
37
38#[cfg(not(target_arch = "wasm32"))]
39impl<T> AsyncTaskResult for T
40where
41    T: Any + Send + 'static,
42{
43    fn into_any(self: Box<Self>) -> Box<dyn Any> {
44        self
45    }
46}
47
48#[cfg(not(target_arch = "wasm32"))]
49pub trait AsyncTask<R: AsyncTaskResult>: Future<Output = R> + Send + 'static {}
50
51#[cfg(not(target_arch = "wasm32"))]
52impl<T, R: AsyncTaskResult> AsyncTask<R> for T where T: Future<Output = R> + Send + 'static {}
53
54// ========
55// WASM
56#[cfg(target_arch = "wasm32")]
57pub trait AsyncTaskResult: Any + 'static {
58    fn into_any(self: Box<Self>) -> Box<dyn Any>;
59}
60
61#[cfg(target_arch = "wasm32")]
62impl<T> AsyncTaskResult for T
63where
64    T: Any + 'static,
65{
66    fn into_any(self: Box<Self>) -> Box<dyn Any> {
67        self
68    }
69}
70
71#[cfg(target_arch = "wasm32")]
72pub trait AsyncTask<R: AsyncTaskResult>: Future<Output = R> + 'static {}
73
74#[cfg(target_arch = "wasm32")]
75impl<T, R: AsyncTaskResult> AsyncTask<R> for T where T: Future<Output = R> + 'static {}
76
77// ========
78// Common
79impl dyn AsyncTaskResult {
80    pub fn downcast<T: AsyncTaskResult>(self: Box<Self>) -> Result<Box<T>, Box<dyn Any>> {
81        self.into_any().downcast()
82    }
83}
84
85pub struct TaskResult {
86    pub id: Uuid,
87    pub payload: Box<dyn AsyncTaskResult>,
88}
89
90pub struct TaskPool {
91    #[cfg(not(target_arch = "wasm32"))]
92    thread_pool: ThreadPool,
93    sender: Sender<TaskResult>,
94    receiver: Mutex<Receiver<TaskResult>>,
95}
96
97impl Default for TaskPool {
98    fn default() -> Self {
99        Self::new()
100    }
101}
102
103impl TaskPool {
104    #[inline]
105    pub fn new() -> Self {
106        let (sender, receiver) = mpsc::channel();
107        Self {
108            #[cfg(not(target_arch = "wasm32"))]
109            thread_pool: ThreadPool::new().unwrap(),
110            sender,
111            receiver: Mutex::new(receiver),
112        }
113    }
114
115    #[inline]
116    #[cfg(target_arch = "wasm32")]
117    pub fn spawn_task<F>(&self, future: F)
118    where
119        F: Future<Output = ()> + 'static,
120    {
121        crate::wasm_bindgen_futures::spawn_local(future);
122    }
123
124    #[inline]
125    #[cfg(not(target_arch = "wasm32"))]
126    pub fn spawn_task<F>(&self, future: F)
127    where
128        F: Future<Output = ()> + Send + 'static,
129    {
130        self.thread_pool.spawn_ok(future);
131    }
132
133    #[inline]
134    pub fn spawn_with_result<F, T>(&self, future: F) -> Uuid
135    where
136        F: AsyncTask<T>,
137        T: AsyncTaskResult,
138    {
139        let id = Uuid::new_v4();
140        let sender = self.sender.clone();
141        self.spawn_task(async move {
142            let result = future.await;
143            sender
144                .send(TaskResult {
145                    id,
146                    payload: Box::new(result),
147                })
148                .unwrap();
149        });
150        id
151    }
152
153    #[inline]
154    pub fn next_task_result(&self) -> Option<TaskResult> {
155        self.receiver.lock().try_recv().ok()
156    }
157}