Skip to content
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

WIP: Compat blog post #1226

Closed

Conversation

MajorBreakfast
Copy link
Contributor

I'm going to continue writing this tomorrow if I find the time. In the meantime, here's what I have so far 🙂

@MajorBreakfast
Copy link
Contributor Author

MajorBreakfast commented Aug 27, 2018

Alright. Now it's done. Plz review

Note: I plan to turn various code snippets into links once we've released the docs for alpha.4. The docs for alpha.3 don't include the compatibility layer (an oversight ^^').

The compatibility layer can be enabled by setting the `compat` feature your `Cargo.toml`:

```toml
futures-preview = { version = "0.3.0-alpha.3", features = ["compat"] }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably also include the "tokio-compat" feature, otherwise the two examples won't run.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

futures-preview = { version = "0.3.0-alpha.3", features = ["compat"] }
```

To use `futures@0.1` and `futures@0.3` together in a single project, we can make use of the new cargo feature for renaming dependencies. Why? Because, even though the `futures@0.3` crate is called `futures-preview` on crates.io, it's lib name is also `futures`. By renaming `futures` version 0.1 to `futures01`, we can avoid a name colision:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

colision => collision

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


# Futures 0.1 Compatibility Layer

Rust's futures ecosystem is currenlty split in two: On the one hand we have the vibrant ecosystem built around `futures@0.1` with its many libraries working on stable Rust and on the other hand there's the unstable `futures@0.3` ecosystem with support for the ergonomic and powerful `async`/`await` language feature. To bridge the gap between these two worlds we've introduced with `0.3.0-alpha.3` a compatibility layer that makes it possible to use `futures@0.1` and `futures@0.3` futures and streams together in one project. This blog post aims to give an overview over how to use it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we've introduced with 0.3.1-alpha.3 a compatibility layer

reads weirdly on first glance, maybe something like

To bridge the gap between these two worlds we have introduced a compatibility layer (first released as part of futures 0.3.0-alpha.3)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

let future03 = future01.compat();
```

It converts a 0.1 `Future<Item = T, Error = E>` into a 0.3 `Future<Output = Result<T, E>>`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a note that even with this it's not possible to run a tokio based future on a 0.3 executor because there is no reactor available? (I have an idea for another combinator that would allow this, but haven't gotten round to trying it out yet).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware of this limitation. I'm not sure how to phrase this. Could you maybe formulate how to explain this best?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try and throw together a short failing example, I think that might be the best way to show why it doesn't work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, damn, it's not even just that there's no reactor available, the current compat01to03 implementation won't work on any futures(0.3) executor because there's no thread-local Task to store the Notify in:

#![feature(async_await, await_macro, futures_api)]

use std::net::ToSocketAddrs;
use futures::compat::Future01CompatExt;

const MSG: &[u8] = &[0x44, 0x01, 0x6d, 0xb3, 0xb3, 0xb1, 0x28, 0xba, 0xb4, 0x74, 0x65, 0x73, 0x74];

async fn do_request() {
    let addr = ("coap.me", 5683).to_socket_addrs().unwrap().next().unwrap();
    let bind_addr = "0.0.0.0:0".parse().unwrap();
    let socket = tokio::net::UdpSocket::bind(&bind_addr).unwrap();
    let (socket, _) = await!(socket.send_dgram(MSG, &addr).compat()).unwrap();
    let buffer = vec![0; 256];
    let (_, buffer, length, _) = await!(socket.recv_dgram(buffer).compat()).unwrap();
    let result = String::from_utf8_lossy(&buffer[..length]);
    assert!(result.contains("welcome to the ETSI plugtest"))
}

fn main() {
    futures::executor::block_on(do_request())
}

gives an error:

thread 'main' panicked at 'no Task is currently running', libcore/option.rs:1000:5
stack backtrace:
[...]
   9: <futures::task_impl::NotifyHandle as core::clone::Clone>::clone
             at /Users/travis/build/rust-lang/rust/src/libcore/option.rs:312
  10: futures::task_impl::with
             at /Users/Nemo157/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.23/src/task_impl/mod.rs:43
  11: futures::task_impl::with_notify
              at /Users/Nemo157/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.23/src/task_impl/mod.rs:471
  12: futures_util::compat::compat01to03::<impl core::future::future::Future for futures_util::compat::compat::Compat<Fut, ()>>::poll
             at /Users/Nemo157/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-preview-0.3.0-alpha.3/src/compat/compat01to03.rs:21
[...]
  26: futures_executor::local_pool::block_on
              at /Users/Nemo157/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-preview-0.3.0-alpha.3/src/local_pool.rs:224
[...]

The conversion from a 0.1 future to a 0.3 future also works via a `compat` combinator method:

```rust
use futures::compat::Futures01CompatExt;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be use futures::compat::Future01CompatExt;

@MajorBreakfast
Copy link
Contributor Author

@carllerche This blog post talks about compatibility between 0.1 and 0.3 futures in general, but also about Tokio compatibility. Now, that tokio-async-await is released, I think we should update this post before we release it so that it only presents a single solution on that topic.

I think it'd be best to place the general 0.1 <-> 0.3 compatibility layer in futures-util and to keep all Tokio related compatibility layer functionality in tokio-async-await (and remove it form futures-util). Also, I think it'd be nice if tokio-async-await used the compatibility layer from the futures crate internally. We should improve the compatibility layer if it lacks required functionality.

I'd love to hear your take on this. Would you be open for collaboration?

@carllerche
Copy link
Member

I don't really have many thoughts as to what collaboration would look like. I have not dug into the compat layer in the futures lib.

General thoughts:

tokio-async-await doesn't bother trying to bridge the two task systems. It assumes that leaf futures are 0.1 and users are on Tokio. Given this, it just passes a Waker that panics if used.

Also, tokio-async-await does not bother trying to set the spawn handle with the context. I presonally think it is an incorrect API. I provided more details to @cramertj and will be pushing back against it once there is a forum to do so. Given this, I would rather not burden Tokio users with having to worry about it.

Last, keeping what I need in tokio-async-await to make things work allows me to make progress and publish on my schedule, which is more convenient at this point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants