-
Notifications
You must be signed in to change notification settings - Fork 510
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add Executor struct and Execute trait (#4648)
* feat: Add Executor struct and Execute trait Signed-off-by: Xuanwo <[email protected]> * Fix licenses Signed-off-by: Xuanwo <[email protected]> --------- Signed-off-by: Xuanwo <[email protected]>
- Loading branch information
Showing
7 changed files
with
307 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Licensed to the Apache Software Foundation (ASF) under one | ||
// or more contributor license agreements. See the NOTICE file | ||
// distributed with this work for additional information | ||
// regarding copyright ownership. The ASF licenses this file | ||
// to you under the Apache License, Version 2.0 (the | ||
// "License"); you may not use this file except in compliance | ||
// with the License. You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
use crate::raw::BoxedStaticFuture; | ||
use crate::*; | ||
use futures::future::RemoteHandle; | ||
use futures::FutureExt; | ||
use std::future::Future; | ||
use std::pin::Pin; | ||
use std::task::{Context, Poll}; | ||
|
||
/// Execute trait is used to execute task in background. | ||
pub trait Execute: 'static { | ||
/// Execute async task in background. | ||
/// | ||
/// # Behavior | ||
/// | ||
/// - Implementor must manage the executing futures and keep making progress. | ||
/// - Implementor must return `Error::Unexpected` if failed to execute new task. | ||
fn execute(&self, f: BoxedStaticFuture<()>) -> Result<()>; | ||
} | ||
|
||
/// Task is generated by Executor that represents an executing task. | ||
/// | ||
/// Users can fetch the results by calling `poll` or `.await` on this task. | ||
/// Or, users can cancel the task by `drop` this task handle. | ||
/// | ||
/// # Notes | ||
/// | ||
/// Users don't need to call `poll` to make progress. All tasks are running in | ||
/// the background. | ||
pub struct Task<T> { | ||
handle: RemoteHandle<T>, | ||
} | ||
|
||
impl<T: 'static> Task<T> { | ||
/// Create a new task. | ||
#[inline] | ||
#[allow(unused)] | ||
pub fn new(handle: RemoteHandle<T>) -> Self { | ||
Self { handle } | ||
} | ||
} | ||
|
||
impl<T: 'static> Future for Task<T> { | ||
type Output = T; | ||
|
||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
self.handle.poll_unpin(cx) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Licensed to the Apache Software Foundation (ASF) under one | ||
// or more contributor license agreements. See the NOTICE file | ||
// distributed with this work for additional information | ||
// regarding copyright ownership. The ASF licenses this file | ||
// to you under the Apache License, Version 2.0 (the | ||
// "License"); you may not use this file except in compliance | ||
// with the License. You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
use super::*; | ||
use crate::raw::MaybeSend; | ||
use crate::*; | ||
use futures::FutureExt; | ||
use std::future::Future; | ||
use std::sync::Arc; | ||
|
||
/// Executor that runs futures in background. | ||
/// | ||
/// Executor is created by users and used by opendal. So it's by design that Executor only | ||
/// expose constructor methods. | ||
/// | ||
/// Executor will run futures in background and return a [`Task`] as handle to the future. Users | ||
/// can call `task.await` to wait for the future to complete or drop the `Task` to cancel it. | ||
pub struct Executor { | ||
executor: Arc<dyn Execute>, | ||
} | ||
|
||
#[cfg(feature = "executors-tokio")] | ||
impl Default for Executor { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl Executor { | ||
/// Create a default executor. | ||
/// | ||
/// The default executor is enabled by feature flags. | ||
#[cfg(feature = "executors-tokio")] | ||
pub fn new() -> Self { | ||
Self::with(executors::TokioExecutor::default()) | ||
} | ||
|
||
/// Create a new executor with given execute impl. | ||
pub fn with(exec: impl Execute) -> Self { | ||
Self { | ||
executor: Arc::new(exec), | ||
} | ||
} | ||
|
||
/// Run given future in background immediately. | ||
#[allow(unused)] | ||
pub(crate) fn execute<F>(&self, f: F) -> Result<Task<F::Output>> | ||
where | ||
F: Future + MaybeSend + 'static, | ||
F::Output: MaybeSend + 'static, | ||
{ | ||
let (fut, handle) = f.remote_handle(); | ||
self.executor.execute(Box::pin(fut))?; | ||
Ok(Task::new(handle)) | ||
} | ||
} |
Oops, something went wrong.