|
1 | 1 | use std::{
|
2 | 2 | future::Future,
|
| 3 | + marker::PhantomData, |
3 | 4 | mem,
|
4 | 5 | sync::{Arc, Mutex},
|
5 | 6 | };
|
@@ -61,27 +62,34 @@ impl TaskPool {
|
61 | 62 | /// to spawn tasks. This function will await the completion of all tasks before returning.
|
62 | 63 | ///
|
63 | 64 | /// This is similar to `rayon::scope` and `crossbeam::scope`
|
64 |
| - pub fn scope<'scope, F, T>(&self, f: F) -> Vec<T> |
| 65 | + pub fn scope<'env, F, T>(&self, f: F) -> Vec<T> |
65 | 66 | where
|
66 |
| - F: FnOnce(&mut Scope<'scope, T>) + 'scope + Send, |
| 67 | + F: for<'scope> FnOnce(&'env mut Scope<'scope, 'env, T>), |
67 | 68 | T: Send + 'static,
|
68 | 69 | {
|
69 | 70 | let executor = &async_executor::LocalExecutor::new();
|
70 |
| - let executor: &'scope async_executor::LocalExecutor<'scope> = |
| 71 | + let executor: &'env async_executor::LocalExecutor<'env> = |
71 | 72 | unsafe { mem::transmute(executor) };
|
72 | 73 |
|
| 74 | + let results: Mutex<Vec<Arc<Mutex<Option<T>>>>> = Mutex::new(Vec::new()); |
| 75 | + let results: &'env Mutex<Vec<Arc<Mutex<Option<T>>>>> = unsafe { mem::transmute(&results) }; |
| 76 | + |
73 | 77 | let mut scope = Scope {
|
74 | 78 | executor,
|
75 |
| - results: Vec::new(), |
| 79 | + results, |
| 80 | + scope: PhantomData, |
| 81 | + env: PhantomData, |
76 | 82 | };
|
77 | 83 |
|
78 |
| - f(&mut scope); |
| 84 | + let scope_ref: &'env mut Scope<'_, 'env, T> = unsafe { mem::transmute(&mut scope) }; |
| 85 | + |
| 86 | + f(scope_ref); |
79 | 87 |
|
80 | 88 | // Loop until all tasks are done
|
81 | 89 | while executor.try_tick() {}
|
82 | 90 |
|
83 |
| - scope |
84 |
| - .results |
| 91 | + let results = scope.results.lock().unwrap(); |
| 92 | + results |
85 | 93 | .iter()
|
86 | 94 | .map(|result| result.lock().unwrap().take().unwrap())
|
87 | 95 | .collect()
|
@@ -127,32 +135,36 @@ impl FakeTask {
|
127 | 135 | ///
|
128 | 136 | /// For more information, see [`TaskPool::scope`].
|
129 | 137 | #[derive(Debug)]
|
130 |
| -pub struct Scope<'scope, T> { |
131 |
| - executor: &'scope async_executor::LocalExecutor<'scope>, |
| 138 | +pub struct Scope<'scope, 'env: 'scope, T> { |
| 139 | + executor: &'env async_executor::LocalExecutor<'env>, |
132 | 140 | // Vector to gather results of all futures spawned during scope run
|
133 |
| - results: Vec<Arc<Mutex<Option<T>>>>, |
| 141 | + results: &'env Mutex<Vec<Arc<Mutex<Option<T>>>>>, |
| 142 | + |
| 143 | + // make `Scope` invariant over 'scope and 'env |
| 144 | + scope: PhantomData<&'scope mut &'scope ()>, |
| 145 | + env: PhantomData<&'env mut &'env ()>, |
134 | 146 | }
|
135 | 147 |
|
136 |
| -impl<'scope, T: Send + 'scope> Scope<'scope, T> { |
| 148 | +impl<'scope, 'env, T: Send + 'env> Scope<'scope, 'env, T> { |
137 | 149 | /// Spawns a scoped future onto the thread-local executor. The scope *must* outlive
|
138 | 150 | /// the provided future. The results of the future will be returned as a part of
|
139 | 151 | /// [`TaskPool::scope`]'s return value.
|
140 | 152 | ///
|
141 | 153 | /// On the single threaded task pool, it just calls [`Scope::spawn_local`].
|
142 | 154 | ///
|
143 | 155 | /// For more information, see [`TaskPool::scope`].
|
144 |
| - pub fn spawn<Fut: Future<Output = T> + 'scope + Send>(&mut self, f: Fut) { |
145 |
| - self.spawn_local(f); |
| 156 | + pub fn spawn<Fut: Future<Output = T> + 'env>(&self, f: Fut) { |
| 157 | + self.spawn_on_scope(f); |
146 | 158 | }
|
147 | 159 |
|
148 |
| - /// Spawns a scoped future onto the thread-local executor. The scope *must* outlive |
149 |
| - /// the provided future. The results of the future will be returned as a part of |
150 |
| - /// [`TaskPool::scope`]'s return value. |
| 160 | + /// Spawns a scoped future that runs on the thread the scope called from. The |
| 161 | + /// scope *must* outlive the provided future. The results of the future will be |
| 162 | + /// returned as a part of [`TaskPool::scope`]'s return value. |
151 | 163 | ///
|
152 | 164 | /// For more information, see [`TaskPool::scope`].
|
153 |
| - pub fn spawn_local<Fut: Future<Output = T> + 'scope>(&mut self, f: Fut) { |
| 165 | + pub fn spawn_on_scope<Fut: Future<Output = T> + 'env>(&self, f: Fut) { |
154 | 166 | let result = Arc::new(Mutex::new(None));
|
155 |
| - self.results.push(result.clone()); |
| 167 | + self.results.lock().unwrap().push(result.clone()); |
156 | 168 | let f = async move {
|
157 | 169 | result.lock().unwrap().replace(f.await);
|
158 | 170 | };
|
|
0 commit comments