-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make custom trait object for Future
generic
#51944
Merged
Merged
Changes from 6 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
3d43f82
Make custom trait object for `Future` generic
MajorBreakfast 9f70e7f
Use `From` impls for `FutureObj<()>`
MajorBreakfast d8bf222
Add lifetime to `FutureObj`
MajorBreakfast 042928f
`UnsafeFutureObj` impl for `PinMut`
MajorBreakfast dd3b033
Improve doc comments for `FutureObj`
MajorBreakfast 4e61729
Make `drop` method for `PinMut`'s `UnsafeFutureObj` impl empty
MajorBreakfast 9eee0d2
Fix naming convention issue
MajorBreakfast cb2c757
Add explanation for custom trait object
MajorBreakfast 5fde8b9
Remove unnecessary `PhantomData` field
MajorBreakfast ae40894
Implement `UnsafeFutureObj` for `&mut Future`
MajorBreakfast e666c2b
Implemented `UnsafeFutureObj` on `Box`
MajorBreakfast File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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,150 @@ | ||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
#![unstable(feature = "futures_api", | ||
reason = "futures in libcore are unstable", | ||
issue = "50547")] | ||
|
||
use fmt; | ||
use future::Future; | ||
use marker::PhantomData; | ||
use mem::PinMut; | ||
use task::{Context, Poll}; | ||
|
||
/// A custom trait object for polling futures, roughly akin to | ||
/// `Box<dyn Future<Output = T> + 'a>`. | ||
/// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound. | ||
pub struct LocalFutureObj<'a, T> { | ||
ptr: *mut (), | ||
poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<T>, | ||
drop_fn: unsafe fn(*mut ()), | ||
_marker1: PhantomData<T>, | ||
_marker2: PhantomData<&'a ()>, | ||
} | ||
|
||
impl<'a, T> LocalFutureObj<'a, T> { | ||
/// Create a `LocalFutureObj` from a custom trait object representation. | ||
#[inline] | ||
pub fn new<F: UnsafeFutureObj<'a, T> + 'a>(f: F) -> LocalFutureObj<'a, T> { | ||
LocalFutureObj { | ||
ptr: f.into_raw(), | ||
poll_fn: F::poll, | ||
drop_fn: F::drop, | ||
_marker1: PhantomData, | ||
_marker2: PhantomData, | ||
} | ||
} | ||
|
||
/// Converts the `LocalFutureObj` into a `FutureObj` | ||
/// To make this operation safe one has to ensure that the `UnsafeFutureObj` | ||
/// instance from which this `LocalFutureObj` was created actually | ||
/// implements `Send`. | ||
#[inline] | ||
pub unsafe fn as_future_obj(self) -> FutureObj<'a, T> { | ||
FutureObj(self) | ||
} | ||
} | ||
|
||
impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_struct("LocalFutureObj") | ||
.finish() | ||
} | ||
} | ||
|
||
impl<'a, T> From<FutureObj<'a, T>> for LocalFutureObj<'a, T> { | ||
#[inline] | ||
fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> { | ||
f.0 | ||
} | ||
} | ||
|
||
impl<'a, T> Future for LocalFutureObj<'a, T> { | ||
type Output = T; | ||
|
||
#[inline] | ||
fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> { | ||
unsafe { | ||
(self.poll_fn)(self.ptr, cx) | ||
} | ||
} | ||
} | ||
|
||
impl<'a, T> Drop for LocalFutureObj<'a, T> { | ||
fn drop(&mut self) { | ||
unsafe { | ||
(self.drop_fn)(self.ptr) | ||
} | ||
} | ||
} | ||
|
||
/// A custom trait object for polling futures, roughly akin to | ||
/// `Box<dyn Future<Output = T> + Send + 'a>`. | ||
pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>); | ||
|
||
unsafe impl<'a, T> Send for FutureObj<'a, T> {} | ||
|
||
impl<'a, T> FutureObj<'a, T> { | ||
/// Create a `FutureObj` from a custom trait object representation. | ||
#[inline] | ||
pub fn new<F: UnsafeFutureObj<'a, T> + Send>(f: F) -> FutureObj<'a, T> { | ||
FutureObj(LocalFutureObj::new(f)) | ||
} | ||
} | ||
|
||
impl<'a, T> fmt::Debug for FutureObj<'a, T> { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_struct("FutureObj") | ||
.finish() | ||
} | ||
} | ||
|
||
impl<'a, T> Future for FutureObj<'a, T> { | ||
type Output = T; | ||
|
||
#[inline] | ||
fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> { | ||
let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; | ||
pinned_field.poll(cx) | ||
} | ||
} | ||
|
||
/// A custom implementation of a future trait object for `FutureObj`, providing | ||
/// a hand-rolled vtable. | ||
/// | ||
/// This custom representation is typically used only in `no_std` contexts, | ||
/// where the default `Box`-based implementation is not available. | ||
/// | ||
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in | ||
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is | ||
/// called. | ||
pub unsafe trait UnsafeFutureObj<'a, T>: 'a { | ||
/// Convert an owned instance into a (conceptually owned) void pointer. | ||
fn into_raw(self) -> *mut (); | ||
|
||
/// Poll the future represented by the given void pointer. | ||
/// | ||
/// # Safety | ||
/// | ||
/// The trait implementor must guarantee that it is safe to repeatedly call | ||
/// `poll` with the result of `into_raw` until `drop` is called; such calls | ||
/// are not, however, allowed to race with each other or with calls to | ||
/// `drop`. | ||
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T>; | ||
|
||
/// Drops the future represented by the given void pointer. | ||
/// | ||
/// # Safety | ||
/// | ||
/// The trait implementor must guarantee that it is safe to call this | ||
/// function once per `into_raw` invocation; that call cannot race with | ||
/// other calls to `drop` or `poll`. | ||
unsafe fn drop(ptr: *mut ()); | ||
} |
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,21 @@ | ||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
#![unstable(feature = "futures_api", | ||
reason = "futures in libcore are unstable", | ||
issue = "50547")] | ||
|
||
//! Asynchronous values. | ||
|
||
mod future; | ||
pub use self::future::Future; | ||
|
||
mod future_obj; | ||
pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj}; |
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
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this marker for?
T
is already used in the signature ofpoll_fn
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's for uhm... kicks it under the rug ...what marker do you mean? :)