-
Notifications
You must be signed in to change notification settings - Fork 620
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
More tests 4 #1069
More tests 4 #1069
Conversation
@@ -30,57 +30,8 @@ macro_rules! if_std { | |||
)*) | |||
} | |||
|
|||
#[macro_export] | |||
macro_rules! pinned_deref { |
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.
I removed this macro. It was never used anywhere
} | ||
|
||
#[macro_export] | ||
macro_rules! pinned_field { |
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.
I removed this macro because it's an anti pattern. Better alternatives are:
- Usage of
PinMut::map_unchecked
unsafe_pinned!
macro
)* } | ||
} | ||
#[macro_use] | ||
mod macros; |
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.
I've put them in a macro module This is cleaner, but ultimately when macro imports are implemented I'd like to:
- Put the poll macros under
futures::task
- Put the pin macros... not sure where. We need to decide that once macros can be imported via
use
statements
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.
Correction: Macro imports via use are implemented. They‘re just feature gated. We could use them.
unsafe { | ||
$crate::core_reexport::mem::PinMut::map_unchecked( | ||
self.reborrow(), |x| &mut x.$f | ||
) |
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.
I've changed this to map_unchecked
. It works the same.
Also, here and in the following macros the $crate::core_reexport::
prefixes were partly missing.
@@ -43,6 +53,6 @@ impl<A> Future for Flatten<A> | |||
type Output = <A::Output as Future>::Output; | |||
|
|||
fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> { | |||
unsafe { pinned_field!(self, state) }.poll(cx, |a, ()| a) | |||
self.state().poll(cx, |a, ()| a) |
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.
I removed all occurences of the pinned_field!
macro
@@ -0,0 +1,7 @@ | |||
// Macros redefined here because macro re-exports are unstable. |
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.
That's the reason why all macros are duplicated
@@ -65,7 +65,7 @@ where | |||
impl<'a, T, U> Future for SendAll<'a, T, U> | |||
where | |||
T: Sink + Unpin + 'a + ?Sized, | |||
U: Stream<Item = Result<T::SinkItem, T::SinkError>> + Unpin + 'a + ?Sized, | |||
U: Stream<Item = T::SinkItem> + Unpin + 'a + ?Sized, |
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.
Signature was wrong
futures/tests/recurse.rs
Outdated
::std::thread::spawn(|| { | ||
block_on(do_it((1_000, 0)).map(move |x| tx.send(x).unwrap())) | ||
}); | ||
assert_eq!(500_500, rx.recv().unwrap()); |
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.
I made it a bit fancier than it was before. Now it adds the numbers 0 + 1 + ... + 1000 = 500,500
ee0dc8f
to
0c74e93
Compare
} | ||
|
||
#[test] | ||
fn unfold_err1() { |
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.
Streams are no longer error-aware, therefore this test doesn't apply anymore.
@aturon This can be reviewed |
|
||
#[must_use = "futures do nothing unless polled"] | ||
#[derive(Debug)] | ||
crate enum TryChain<Fut1, Fut2, Data> { |
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.
TryChain is a new mechanism so that and_then
and or_else
can share a single implementation.
} | ||
}; | ||
|
||
*this = TryChain::Empty; // Drop fut1 |
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.
The eager_drop tests want this: They expect that the old futures is dropped before the closure runs.
Self: Sized, | ||
{ | ||
map_ok::new(self, f) | ||
MapOk::new(self, op) |
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.
I made these new
functions methods
f: Option<F>, | ||
pub struct MapErr<Fut, F> { | ||
future: Fut, | ||
op: Option<F>, |
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.
op
is how the standard library's Result
methods call this
/// Converts a `TryFuture` into a normal `Future` | ||
#[derive(Debug)] | ||
#[must_use = "futures do nothing unless polled"] | ||
pub struct IntoFuture<Fut> { |
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.
This is a new invention. I originally planned to use it for something, but my plan then changed and I did it another way. I suggest to keep it, though. I think it could be useful.
Added tests for basic combinators and |
Woohoo. Green CI 🎉 And I didn't cheat. To the contrary: The docs now actually build and the CI runs the tests again |
@@ -23,126 +25,25 @@ | |||
|
|||
#![no_std] | |||
|
|||
#![deny(missing_docs, missing_debug_implementations, warnings)] | |||
#![deny(missing_docs, missing_debug_implementations)] |
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.
Rustdoc for reexports seems broken. The crates all build fine individually (e.g. cargo doc -p futures-core
). But when reexported in the futures crate we get a bunch of warnings
//! [`Receiver`]: struct.Receiver.html | ||
//! [`Stream`]: ../../futures_core/stream/trait.Stream.html | ||
//! [`Receiver::poll_next`]: | ||
//! ../../futures_core/stream/trait.Stream.html#tymethod.poll_next |
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.
I added these links like so. I wasn't able to make it build otherwise. Seems to be a bug in all //!
comments
pub use futures_core::stream::Stream; | ||
pub use futures_util::stream::StreamExt; | ||
pub use futures_sink::Sink; | ||
pub use futures_util::sink::SinkExt; |
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.
I removed these top level exports because using them is an anti-pattern. It's much easier to either import from the right location like futures::task::Poll
or to import the prelude futures::prelude::*
. Anything in-between doesn't make sense in my opinion, it just makes the layout of the futures crate less clear.
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.
I disagree. I don't see any anti-pattern. I frequently have use futures::{Future, Stream}
in modules. Making them harder to import doesn't improve anything.
Glob imports and preludes, however, definitely are an anti-pattern.
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.
I agree with @seanmonstar, having to begin every file with
use futures::{core::{future::Future, stream::Stream}, utils::{future::FutureExt, stream::StreamExt}};
Instead of
use futures::{Future, Stream, FutureExt, StreamExt};
Would be very annoying.
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.
@Nemo157 @seanmonstar Thanks for your comments!
My reaction is that all this top-level stuff accumulates. There is also:
Context, ContextExt, CoreFutureExt, FutureObj, LocalFutureObj, TryFuture, TryFutureExt and TryStream, TryStreamExt, Sink, SinkExt
These are just the most common imports, but there are obviously more that we could add. (FutureObj
exists because dyn Trait
is currently impossible for traits that use arbitrary self types) My intention behind removing these top-level imports is that it makes the docs better. Top level exports are a bad thing because they destroy the structure. If everything is exported at the top level anyway, there is no real reason to have submodules at all. How can we decide which things are considered important enough to be exported at the top level? How will it grow over time? How would it look like if the standard library did it? I think that it doesn't scale and we shouldn't do it.
The hierarchy I'm proposing here is the same as in libcore: libcore also differentiates between the submodules future
and task
. And a stream
submodule will probably exist in the future.
@Nemo157 FutureExt
is defined in the utils crate, but there's no such module. All extensions live in the respective submodules future
, stream
and sink
This is how I imagine it:
use futures::future::{Future, FutureExt};
use futures::stream::{Stream, StreamExt};
use futures::task::{Context, Poll};
I think that this actually looks pretty nice. That said, the approach I'm proposing here is just a suggestion. This PR has become rather large, so I explictly highlighted this change to make it absolutely obvious. I certainly don't want to decide that for everyone. If you all really dislike it, we can revert to the old approach. I'm confident, though, that the approach of clear separation is better. Now I want to sell it :) If you're on board, then we change it, otherwise we change it back to the old approach. But, take a little time and think about it. I really think this approach is better.
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.
I think idea of top-level re-exports serves both convenience for common case (easy to reach things you need without clutter) and discoverability. It's hard to argue that Future, Stream and Sink (and their extension traits since 0.2) are core concepts to futures crates. In my view, public submodules still make sense for things that are more specialized, e.g. deeper dive into streaming functionality for writing your own combinators. Being able to import things through futures::{Future, FutureExt, Stream, StreamExt}
and futures::stream::{Stream, StreamExt, FilterMap, Empty}
is both useful in my opinion if only in different contexts.
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.
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.
I don't see any problem with the traits list there at the bottom. If it were a big deal, they can be doc(hidden)
from the main page, but I don't think it's an issue.
I definitely wouldn't make actually using these traits harder just for the docs change.
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.
One thing to note is that futures
0.2 didn't export Context
to the top-level. As far as I am aware the standard was to use task::Context
everywhere. That doesn't reduce it much though 😦
I wonder if trait aliases could help with all those extension traits. In futures
have something like
trait Future = ::core::future::Future + CoreFutureExt + FutureExt;
(although currently the RFC doesn't specify that trait aliases bring methods into scope, I left a comment on the tracking issue to find out).
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.
@seanmonstar My main concern is the impression a new user gets when looking at the docs for the first time. I've added a commit that adds the reexports as doc(hidden)
. As long as there is no big pile of unsorted stuff visible to users, it's fine I guess.
@Nemo157 I think it would be confusing if more than one thing was called a Future
. Would impl Future for MyType
even work for a trait alias?
pub use futures_util::try_future::{ | ||
TryFutureExt, | ||
AndThen, ErrInto, FlattenSink, IntoFuture, MapErr, MapOk, OrElse, | ||
UnwrapOrElse, |
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.
I've put the stuff for TryFuture
into the future
module (they previously weren't exported)
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.
Currently the TryFuture
s do not implement the Future
trait. But, this is planned to change as soon as it becomes technically possible. Therefore, putting the extensions for both into a single module makes sense to me. What do you think?
942b033
to
ad744ac
Compare
@cramertj In case you're wondering: I moved the |
401d527
to
b66bfdf
Compare
unsafe_pinned!(future -> A); | ||
unsafe_unpinned!(f -> Option<F>); | ||
/// Creates a new Map. | ||
pub(super) fn new(future: Fut, op: F) -> Map<Fut, F> { |
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.
I'm fine with changing these new
functions to pub(super)
methods, but we should keep it consistent-- there are a bunch of other places where this pattern is used (most combinators) and those should be changed as well.
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.
I'll definitely do those in another PR. You know that I love consistency 🤓
🎉 |
No description provided.