Remove some unsafe code (#540)

This commit is contained in:
Stjepan Glavina 2020-09-21 22:13:40 +02:00 committed by GitHub
parent fd1d6a388d
commit 5aa77979d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 9 additions and 25 deletions

View File

@ -65,11 +65,8 @@ impl TaskPool {
{ {
let executor = async_executor::LocalExecutor::new(); let executor = async_executor::LocalExecutor::new();
let executor: &async_executor::LocalExecutor = &executor;
let executor: &'scope async_executor::LocalExecutor = unsafe { mem::transmute(executor) };
let mut scope = Scope { let mut scope = Scope {
executor, executor: &executor,
results: Vec::new(), results: Vec::new(),
}; };
@ -87,26 +84,18 @@ impl TaskPool {
} }
pub struct Scope<'scope, T> { pub struct Scope<'scope, T> {
executor: &'scope async_executor::LocalExecutor, executor: &'scope async_executor::LocalExecutor<'scope>,
// Vector to gather results of all futures spawned during scope run // Vector to gather results of all futures spawned during scope run
results: Vec<Arc<Mutex<Option<T>>>>, results: Vec<Arc<Mutex<Option<T>>>>,
} }
impl<'scope, T: Send + 'static> Scope<'scope, T> { impl<'scope, T: Send + 'scope> Scope<'scope, T> {
pub fn spawn<Fut: Future<Output = T> + 'scope + Send>(&mut self, f: Fut) { pub fn spawn<Fut: Future<Output = T> + 'scope + Send>(&mut self, f: Fut) {
let result = Arc::new(Mutex::new(None)); let result = Arc::new(Mutex::new(None));
self.results.push(result.clone()); self.results.push(result.clone());
let f = async move { let f = async move {
result.lock().unwrap().replace(f.await); result.lock().unwrap().replace(f.await);
}; };
self.executor.spawn(f).detach();
// SAFETY: This function blocks until all futures complete, so we do not read/write the
// data from futures outside of the 'scope lifetime. However, rust has no way of knowing
// this so we must convert to 'static here to appease the compiler as it is unable to
// validate safety.
let fut: Pin<Box<dyn Future<Output = ()> + 'scope>> = Box::pin(f);
let fut: Pin<Box<dyn Future<Output = ()> + 'static>> = unsafe { mem::transmute(fut) };
self.executor.spawn(fut).detach();
} }
} }

View File

@ -38,8 +38,7 @@ impl<T> Task<T> {
impl<T> Future for Task<T> { impl<T> Future for Task<T> {
type Output = T; type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Safe because Task is pinned and contains async_executor::Task by value Pin::new(&mut self.0).poll(cx)
unsafe { self.map_unchecked_mut(|x| &mut x.0).poll(cx) }
} }
} }

View File

@ -6,7 +6,7 @@ use std::{
thread::{self, JoinHandle}, thread::{self, JoinHandle},
}; };
use futures_lite::future; use futures_lite::{future, pin};
/// Used to create a TaskPool /// Used to create a TaskPool
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@ -180,12 +180,8 @@ impl TaskPool {
results results
}; };
// Move the value to ensure that it is owned // Pin the future on the stack.
let mut fut = fut; pin!(fut);
// Shadow the original binding so that it can't be directly accessed
// ever again.
let fut = unsafe { Pin::new_unchecked(&mut fut) };
// SAFETY: This function blocks until all futures complete, so we do not read/write the // SAFETY: This function blocks until all futures complete, so we do not read/write the
// data from futures outside of the 'scope lifetime. However, rust has no way of knowing // data from futures outside of the 'scope lifetime. However, rust has no way of knowing