How do I borrow a mutable reference from an Arc<Mutex<T>> and call an async member function on it? - asynchronous

I have a simple struct and an implementation that looks like this.
#[derive(Debug)]
struct MyStruct {
data: u64,
}
impl MyStruct {
async fn something_async(&mut self) -> Result<(), Box<dyn Error>> {
self.data += 1;
Ok(())
}
}
I want to use MyStruct on the heap using a smart pointer and a mutex so that I can use it from multiple threads.
However, when I try to call the async function called something_async()...
tokio::spawn(async move {
let ptr = Arc::new(Mutex::new(MyStruct { data: 1 }));
let mut s = ptr.lock().unwrap();
s.something_async().await.unwrap();
println!("{:?}", s);
});
...I get the following error:
error: future cannot be sent between threads safely
--> src/main.rs:18:5
|
18 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, MyStruct>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:21:9
|
20 | let mut s = ptr.lock().unwrap();
| ----- has type `std::sync::MutexGuard<'_, MyStruct>` which is not `Send`
21 | s.something_async().await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut s` maybe used later
22 | println!("{:?}", s);
23 | });
| - `mut s` is later dropped here
note: required by a bound in `tokio::spawn`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.16.1/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
I am assuming that the compiler does not like me keeping a MutexGuard held across an await, so I tried this instead:
let fut = {
let mut s = ptr.lock().unwrap();
s.something_async()
};
fut.await.unwrap();
But of course then it complains about the Future outliving the mutable reference not living long enough:
error[E0597]: `s` does not live long enough
--> src/main.rs:22:13
|
20 | let fut = {
| --- borrow later stored here
21 | let mut s = ptr.lock().unwrap();
22 | s.something_async()
| ^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
23 | };
| - `s` dropped here while still borrowed
How do I call an async method on an object wrapped in an Arc<Mutex<T>>?

Make MyStruct copyable.
#[derive(Debug, Copy, Clone)]
struct MyStruct {
data: u64,
}
impl MyStruct {
async fn something_async(&mut self) -> Result<(), Box<dyn Error>> {
self.data += 1;
Ok(())
}
}
#[tokio::main]
async fn main() {
tokio::spawn(async move {
let ptr = Arc::new(Mutex::new(MyStruct { data: 1 }));
let mut s = *ptr.lock().unwrap();
s.something_async().await.unwrap();
println!("{:?}", s);
});
}

Related

Which Generic Types are allowed in the `Vec<T>` implementation of `ParallelExtend`

I am new to Rust and I am writing a recursive directory traversal program. This project is just an opportunity to learn Rust and parallelism with Rayon. This question is a continuation of this question which #KevinReid helped out a lot with.
Below is my attempt to use partition_map() followed by the errors I am receiving.
use std::fs;
use std::path::PathBuf;
use rayon::iter::{Either, IntoParallelIterator, ParallelIterator};
#[derive(Debug)]
struct Node {
path: PathBuf,
files: Vec<PathBuf>,
folders: Vec<Box<Node>>,
}
impl Node {
pub fn new(path: PathBuf) -> Self {
Node {
path: path,
files: Vec::new(),
folders: Vec::new(),
}
}
pub fn burrow(&mut self) {
let mut contents: Vec<PathBuf> = ls_dir(&self.path);
let ret: (Vec<PathBuf>, Vec<Box<Node>>) = contents.into_par_iter().partition_map(|item|
if item.is_file() {
self.files.push(item);
Either::Left(self.files)
} else {
let mut new_folder = Node::new(item);
new_folder.burrow();
self.folders.push(Box::new(new_folder));
Either::Right(self.folders)
});
println!("{:?}", ret);
}
}
fn ls_dir(path: &PathBuf) -> Vec<PathBuf> {
let mut contents: Vec<PathBuf> = Vec::new();
let current_dir: fs::ReadDir = fs::read_dir(path).unwrap();
for file in current_dir {
contents.push(file.unwrap().path());
}
contents
}
fn main() {
let root_path: &str = ".";
let root: PathBuf = PathBuf::from(root_path);
let contents: Vec<PathBuf> = ls_dir(&root);
let mut node: Node = Node::new(root);
node.burrow();
}
error[E0277]: the trait bound `Vec<PathBuf>: ParallelExtend<Vec<PathBuf>>` is not satisfied
--> src/main.rs:31:76
|
31 | let ret: (Vec<PathBuf>, Vec<Box<Node>>) = contents.into_par_iter().partition_map(|item|
| ^^^^^^^^^^^^^ the trait `ParallelExtend<Vec<PathBuf>>` is not implemented for `Vec<PathBuf>`
|
= help: the following implementations were found:
<Vec<T> as ParallelExtend<&'a T>>
<Vec<T> as ParallelExtend<T>>
note: required by a bound in `partition_map`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/src/iter/mod.rs:2167:29
|
2167 | A: Default + Send + ParallelExtend<L>,
| ^^^^^^^^^^^^^^^^^ required by this bound in `partition_map`
error[E0277]: the trait bound `Vec<Box<Node>>: ParallelExtend<Vec<Box<Node>>>` is not satisfied
--> src/main.rs:31:76
|
31 | let ret: (Vec<PathBuf>, Vec<Box<Node>>) = contents.into_par_iter().partition_map(|item|
| ^^^^^^^^^^^^^ the trait `ParallelExtend<Vec<Box<Node>>>` is not implemented for `Vec<Box<Node>>`
|
= help: the following implementations were found:
<Vec<T> as ParallelExtend<&'a T>>
<Vec<T> as ParallelExtend<T>>
note: required by a bound in `partition_map`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/src/iter/mod.rs:2168:29
|
2168 | B: Default + Send + ParallelExtend<R>,
| ^^^^^^^^^^^^^^^^^ required by this bound in `partition_map`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `my-project` due to 2 previous errors
exit status 101
It appears that ParallelExtend<T> for Vec<T> is producing the error because of what T is, namely, PathBuf and Box<Node>. I have seen a smaller non-recursive example where T is &str, for example in which these errors are not present. So the question is if this is fixable and just not implemented correctly, or PathBuf and Box<T> inherently do not satisfy something that ParallelExtend requires.
To test if the type T was the issue I ran
pub fn burrow(&mut self) {
let mut contents: Vec<PathBuf> = ls_dir(&self.path);
let ret: (Vec<&str>, Vec<&str>) = contents.into_par_iter().partition_map(|item|
if item.is_file() {
self.files.push(item);
Either::Left("test")
} else {
let mut new_folder = Node::new(item);
new_folder.burrow();
self.folders.push(Box::new(new_folder));
Either::Right("test")
});
println!("{:?}", ret);
}
and received
error[E0596]: cannot borrow `*self.files` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:33:37
|
33 | ... self.files.push(item);
| ^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `*self.folders` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:38:37
|
38 | ... self.folders.push(Box::new(new_folder));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0596`.
error: could not compile `my-project` due to 2 previous errors
exit status 101
which is a totally different issue/concept. Needless to say, with the added recursive component, I am lost in the sauce.

How can I return a vector of responses from a set of concurrent GET requests?

I'm just getting started with Rust and am trying to work with concurrent requests. My aim is to have an asynchronous function that returns a vector of responses from a number of GET requests. What I have currently does successfully execute the requests concurrently but does not return anything from the function:
// main.rs
mod api_requester;
#[tokio::main]
async fn main() {
let values = vec!["dog".to_string(), "cat".to_string(), "bear".to_string()];
let responses = api_requester::get_data(values).await;
println!("{:?}", responses)
// do more stuff with responses
}
// api_requester.rs
use serde::Deserialize;
use futures::{stream, StreamExt};
use reqwest::Client;
const CONCURRENT_REQUESTS: usize = 2;
const API_ENDPOINT: &str = "https://httpbin.org/response-headers";
#[derive(Deserialize, Debug)]
struct ApiResponse {
#[serde(rename(deserialize = "Content-Length"))]
content_length: String,
#[serde(rename(deserialize = "Content-Type"))]
content_type: String,
freeform: String
}
pub async fn get_data(values: Vec<String>) {
let client = Client::new();
let bodies = stream::iter(values)
.map(|value| {
let client = &client;
async move {
let resp = client.get(API_ENDPOINT)
.query(&[("freeform", value)])
.send().await?;
resp.json::<ApiResponse>().await
}
})
.buffer_unordered(CONCURRENT_REQUESTS);
bodies
.for_each(|body| async {
match body {
Ok(body) => println!("Got {:?}", body),
Err(e) => eprintln!("Got an error: {:?}", e),
}
})
.await;
}
My goal is to return a vector of the responses received from the GET requests back to the main function for further use. But this is where I'm having some serious confusion. I thought I would be able to just await the value in the function and return the vector when the futures have been resolved. something like this:
// api_requester.rs
...
pub async fn get_data(values: Vec<String>) -> Vec<ApiResponse> {
let client = Client::new();
let bodies = stream::iter(values)
.map(|value| {
let client = &client;
async move {
let resp = client.get(API_ENDPOINT)
.query(&[("freeform", value)])
.send().await?;
resp.json::<ApiResponse>().await
}
})
.buffer_unordered(CONCURRENT_REQUESTS);
bodies
}
This produces the following error:
error[E0308]: mismatched types
--> src/api_requester.rs:37:5
|
24 | .map(|value| {
| ------- the found closure
...
27 | async move {
| ________________________-
28 | | let resp = client.get(API_ENDPOINT)
29 | | .query(&[("freeform", value)])
30 | | .send().await?;
31 | |
32 | | resp.json::<ApiResponse>().await
33 | | }
| |_____________- the found `async` block
...
37 | bodies
| ^^^^^^ expected struct `Vec`, found struct `BufferUnordered`
|
::: /home/seraub/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:72:43
|
72 | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| ------------------------------- the found opaque type
|
= note: expected struct `Vec<ApiResponse>`
found struct `BufferUnordered<futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<std::string::String>>, [closure#src/api_requester.rs:24:14: 24:21]>>`
For more information about this error, try `rustc --explain E0308`.
I'm guessing that the BufferUnordered<futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<std::string::String>>, [closure#src/api_requester.rs:24:14: 24:21]>> struct found by the compiler needs to be realized/completed?
How can I turn this BufferUnordered object into a simple vector of responses and return it back to the main function?

Using !Send object on async function works, but does not work on trait function

Suppose we have a type that is not Send.
struct NotSend {
field: std::rc::Rc<i32>
}
Then, following async function can still take NotSend as its parameter and compiles well:
async fn func(not_send: NotSend) -> i32 {
0
}
But when I define the same function inside of the trait, then anything that implements it does not compile.
#[async_trait]
trait A {
async fn func(not_send: NotSend) -> i32;
}
struct S {
}
#[async_trait]
impl A for S {
async fn func(not_send: NotSend) -> i32 {
0
}
}
This fails with the following message:
error: future cannot be sent between threads safely
--> src/main.rs:23:46
|
23 | async fn func( not_send: NotSend) -> i32 {
| ______________________________________________^
24 | | 0
25 | | }
| |_____^ future created by async block is not `Send`
|
= help: within `impl Future<Output = i32>`, the trait `Send` is not implemented for `Rc<i32>`
note: captured value is not `Send`
--> src/main.rs:23:20
|
23 | async fn func( not_send: NotSend) -> i32 {
| ^^^^^^^^ has type `NotSend` which is not `Send`
= note: required for the cast to the object type `dyn Future<Output = i32> + Send`
What's so different from the naive function and the function in the trait? Why one does works but not the other? Playground Link
It's because async_trait expands to something like Pin<Box<dyn Future>>. If we want the resulting future to be Send, it needs to be Pin<Box<dyn Future + Send>>. But this forces it to be Send, i.e. will error on non-Send futures. The async_trait crate does not have a way to know whether the future is Send (because the implementation of the trait is different from its declaration, and we need to decide at declaration site whether the future will be Send or not), so it opts to use user-defined annotations.
By default, the generated type is Send since most futures needs to be Send. However, as explained in the documentation, you can use #[async_trait(?Send)] to opt this out:
#[async_trait(?Send)]
trait A {
async fn func(not_send: NotSend) -> i32;
}
struct S {
}
#[async_trait(?Send)]
impl A for S {
async fn func(not_send: NotSend) -> i32 {
0
}
}

How to asynchronously explore a directory and its sub-directories?

I need to explore a directory and all its sub-directories. I can explore the directory easily with recursion in a synchronous way:
use failure::Error;
use std::fs;
use std::path::Path;
fn main() -> Result<(), Error> {
visit(Path::new("."))
}
fn visit(path: &Path) -> Result<(), Error> {
for e in fs::read_dir(path)? {
let e = e?;
let path = e.path();
if path.is_dir() {
visit(&path)?;
} else if path.is_file() {
println!("File: {:?}", path);
}
}
Ok(())
}
When I try to do the same in an asynchronous manner using tokio_fs:
use failure::Error; // 0.1.6
use futures::Future; // 0.1.29
use std::path::PathBuf;
use tokio::{fs, prelude::*}; // 0.1.22
fn visit(path: PathBuf) -> impl Future<Item = (), Error = Error> {
let task = fs::read_dir(path)
.flatten_stream()
.for_each(|entry| {
println!("{:?}", entry.path());
let path = entry.path();
if path.is_dir() {
let task = visit(entry.path());
tokio::spawn(task.map_err(drop));
}
future::ok(())
})
.map_err(Error::from);
task
}
Playground
I get the following error:
error[E0391]: cycle detected when processing `visit::{{opaque}}#0`
--> src/lib.rs:6:28
|
6 | fn visit(path: PathBuf) -> impl Future<Item = (), Error = Error> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires processing `visit`...
--> src/lib.rs:6:1
|
6 | fn visit(path: PathBuf) -> impl Future<Item = (), Error = Error> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `futures::future::map_err::MapErr<impl futures::future::Future, fn(failure::error::Error) {std::mem::drop::<failure::error::Error>}>: std::marker::Send`...
= note: ...which again requires processing `visit::{{opaque}}#0`, completing the cycle
note: cycle used when checking item types in top-level module
--> src/lib.rs:1:1
|
1 | / use failure::Error; // 0.1.6
2 | | use futures::Future; // 0.1.29
3 | | use std::path::PathBuf;
4 | | use tokio::{fs, prelude::*}; // 0.1.22
... |
20| | task
21| | }
| |_^
error[E0391]: cycle detected when processing `visit::{{opaque}}#0`
--> src/lib.rs:6:28
|
6 | fn visit(path: PathBuf) -> impl Future<Item = (), Error = Error> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires processing `visit`...
--> src/lib.rs:6:1
|
6 | fn visit(path: PathBuf) -> impl Future<Item = (), Error = Error> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires processing `visit::{{opaque}}#0`, completing the cycle
note: cycle used when checking item types in top-level module
--> src/lib.rs:1:1
|
1 | / use failure::Error; // 0.1.6
2 | | use futures::Future; // 0.1.29
3 | | use std::path::PathBuf;
4 | | use tokio::{fs, prelude::*}; // 0.1.22
... |
20| | task
21| | }
| |_^
What is the correct way of exploring a directory and its sub-directories asynchronously while propagating all the errors?
I would make several modifications to rodrigo's existing answer:
Return a Stream from the function, allowing the caller to do what they need with a given file entry.
Return an impl Stream instead of a Box<dyn Stream>. This leaves room for more flexibility in implementation. For example, a custom type could be created that uses an internal stack instead of the less-efficient recursive types.
Return io::Error from the function to allow the user to deal with any errors.
Accept a impl Into<PathBuf> to allow a nicer API.
Create an inner hidden implementation function that uses concrete types in its API.
Futures 0.3 / Tokio 0.2
In this version, I avoided the deeply recursive calls, keeping a local stack of paths to visit (to_visit).
use futures::{stream, Stream, StreamExt}; // 0.3.1
use std::{io, path::PathBuf};
use tokio::fs::{self, DirEntry}; // 0.2.4
fn visit(path: impl Into<PathBuf>) -> impl Stream<Item = io::Result<DirEntry>> + Send + 'static {
async fn one_level(path: PathBuf, to_visit: &mut Vec<PathBuf>) -> io::Result<Vec<DirEntry>> {
let mut dir = fs::read_dir(path).await?;
let mut files = Vec::new();
while let Some(child) = dir.next_entry().await? {
if child.metadata().await?.is_dir() {
to_visit.push(child.path());
} else {
files.push(child)
}
}
Ok(files)
}
stream::unfold(vec![path.into()], |mut to_visit| {
async {
let path = to_visit.pop()?;
let file_stream = match one_level(path, &mut to_visit).await {
Ok(files) => stream::iter(files).map(Ok).left_stream(),
Err(e) => stream::once(async { Err(e) }).right_stream(),
};
Some((file_stream, to_visit))
}
})
.flatten()
}
#[tokio::main]
async fn main() {
let root_path = std::env::args().nth(1).expect("One argument required");
let paths = visit(root_path);
paths
.for_each(|entry| {
async {
match entry {
Ok(entry) => println!("visiting {:?}", entry),
Err(e) => eprintln!("encountered an error: {}", e),
}
}
})
.await;
}
Futures 0.1 / Tokio 0.1
use std::path::PathBuf;
use tokio::{fs, prelude::*}; // 0.1.22
use tokio_fs::DirEntry; // 1.0.6
fn visit(
path: impl Into<PathBuf>,
) -> impl Stream<Item = DirEntry, Error = std::io::Error> + Send + 'static {
fn visit_inner(
path: PathBuf,
) -> Box<dyn Stream<Item = DirEntry, Error = std::io::Error> + Send + 'static> {
Box::new({
fs::read_dir(path)
.flatten_stream()
.map(|entry| {
let path = entry.path();
if path.is_dir() {
// Optionally include `entry` if you want to
// include directories in the resulting
// stream.
visit_inner(path)
} else {
Box::new(stream::once(Ok(entry)))
}
})
.flatten()
})
}
visit_inner(path.into())
}
fn main() {
tokio::run({
let root_path = std::env::args().nth(1).expect("One argument required");
let paths = visit(root_path);
paths
.then(|entry| {
match entry {
Ok(entry) => println!("visiting {:?}", entry),
Err(e) => eprintln!("encountered an error: {}", e),
};
Ok(())
})
.for_each(|_| Ok(()))
});
}
See also:
How do I synchronously return a value calculated in an asynchronous Future in stable Rust?
Your code has two errors:
First, a function returning impl Trait cannot currently be recursive, because the actual type returned would depend on itself.
To make your example work, you need to return a sized type. The simple candidate is a trait object, that is, a Box<dyn Future<...>>:
fn visit(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error>> {
// ...
let task = visit(entry.path());
tokio::spawn(task.map_err(drop));
// ...
Box::new(task)
}
There is still your second error:
error[E0277]: `dyn futures::future::Future<Item = (), Error = failure::error::Error>` cannot be sent between threads safely
--> src/lib.rs:14:30
|
14 | tokio::spawn(task.map_err(drop));
| ^^^^^^^^^^^^^^^^^^ `dyn futures::future::Future<Item = (), Error = failure::error::Error>` cannot be sent between threads safely
|
::: /root/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.22/src/executor/mod.rs:131:52
|
131 | where F: Future<Item = (), Error = ()> + 'static + Send
| ---- required by this bound in `tokio::executor::spawn`
|
= help: the trait `std::marker::Send` is not implemented for `dyn futures::future::Future<Item = (), Error = failure::error::Error>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dyn futures::future::Future<Item = (), Error = failure::error::Error>>`
= note: required because it appears within the type `std::boxed::Box<dyn futures::future::Future<Item = (), Error = failure::error::Error>>`
= note: required because it appears within the type `futures::future::map_err::MapErr<std::boxed::Box<dyn futures::future::Future<Item = (), Error = failure::error::Error>>, fn(failure::error::Error) {std::mem::drop::<failure::error::Error>}>`
This means that your trait object is not Send so it cannot be scheduled for execution in another thread using tokio::spawn(). Fortunately, this is easy to fix: just add + Send to your trait object:
fn visit(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
//...
}
See the full code in the Playground.

How do I convert an iterator into a stream on success or an empty stream on failure?

I'd like to take a regular iterator and turn it into a stream so that I can do further stream processing. The trouble is that I may have an iterator or an error to deal with. I think I'm pretty close with this:
#[macro_use]
extern crate log;
extern crate futures; // 0.1.21
extern crate tokio;
use futures::prelude::*;
use futures::{future, stream};
use std::fmt::Debug;
use std::net::{SocketAddr, ToSocketAddrs};
fn resolve(addrs: impl ToSocketAddrs + Debug) -> impl Stream<Item = SocketAddr, Error = ()> {
match addrs.to_socket_addrs() {
Ok(iter) => stream::unfold(iter, |iter| match iter.next() {
Some(a) => Some(future::ok((a, iter))),
None => None,
}),
Err(e) => {
error!("could not resolve socket addresses {:?}: {:?}", addrs, e);
stream::empty()
}
}
}
fn main() {
let task = resolve("1.2.3.4:12345")
.map_err(|e| error!("{:?}", e))
.for_each(|addr| info!("{:?}", addr))
.fold();
tokio::run(task);
}
playground
error[E0308]: match arms have incompatible types
--> src/main.rs:12:5
|
12 | / match addrs.to_socket_addrs() {
13 | | Ok(iter) => stream::unfold(iter, |iter| match iter.next() {
14 | | Some(a) => Some(future::ok((a, iter))),
15 | | None => None,
... |
20 | | }
21 | | }
| |_____^ expected struct `futures::stream::Unfold`, found struct `futures::stream::Empty`
|
= note: expected type `futures::stream::Unfold<<impl ToSocketAddrs + Debug as std::net::ToSocketAddrs>::Iter, [closure#src/main.rs:13:42: 16:10], futures::FutureResult<(std::net::SocketAddr, <impl ToSocketAddrs + Debug as std::net::ToSocketAddrs>::Iter), _>>`
found type `futures::stream::Empty<_, _>`
note: match arm with an incompatible type
--> src/main.rs:17:19
|
17 | Err(e) => {
| ___________________^
18 | | error!("could not resolve socket addresses {:?}: {:?}", addrs, e);
19 | | stream::empty()
20 | | }
| |_________^
error[E0277]: the trait bound `(): futures::Future` is not satisfied
--> src/main.rs:27:10
|
27 | .for_each(|addr| info!("{:?}", addr))
| ^^^^^^^^ the trait `futures::Future` is not implemented for `()`
|
= note: required because of the requirements on the impl of `futures::IntoFuture` for `()`
error[E0599]: no method named `fold` found for type `futures::stream::ForEach<futures::stream::MapErr<impl futures::Stream, [closure#src/main.rs:26:18: 26:39]>, [closure#src/main.rs:27:19: 27:45], ()>` in the current scope
--> src/main.rs:28:10
|
28 | .fold();
| ^^^^
|
= note: the method `fold` exists but the following trait bounds were not satisfied:
`&mut futures::stream::ForEach<futures::stream::MapErr<impl futures::Stream, [closure#src/main.rs:26:18: 26:39]>, [closure#src/main.rs:27:19: 27:45], ()> : futures::Stream`
`&mut futures::stream::ForEach<futures::stream::MapErr<impl futures::Stream, [closure#src/main.rs:26:18: 26:39]>, [closure#src/main.rs:27:19: 27:45], ()> : std::iter::Iterator`
The hint is pretty obvious. The two Results I'm returning from the match differ and should be the same. Now, how can I do that so that I return a stream?
Rust is a statically typed language which means that the return type of a function has to be a single type, known at compile time. You are attempting to return multiple types, decided at runtime.
The closest solution to your original is to always return the Unfold stream:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::unfold(addrs.to_socket_addrs(), |r| {
match r {
Ok(mut iter) => iter.next().map(|addr| future::ok((addr, Ok(iter)))),
Err(_) => None,
}
})
}
But why reinvent the wheel?
futures::stream::iter_ok
Converts an Iterator into a Stream which is always ready to yield the next value.
Subsequent versions of the futures crate implement Stream for Either, which makes this very elegant:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
match addrs.to_socket_addrs() {
Ok(iter) => stream::iter_ok(iter).left_stream(),
Err(_) => stream::empty().right_stream(),
}
}
It's straightforward to backport this functionality to futures 0.1 (maybe someone should submit it as a PR for those who are stuck on 0.1...):
enum MyEither<L, R> {
Left(L),
Right(R),
}
impl<L, R> Stream for MyEither<L, R>
where
L: Stream,
R: Stream<Item = L::Item, Error = L::Error>,
{
type Item = L::Item;
type Error = L::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self {
MyEither::Left(l) => l.poll(),
MyEither::Right(r) => r.poll(),
}
}
}
trait EitherStreamExt {
fn left_stream<R>(self) -> MyEither<Self, R>
where
Self: Sized;
fn right_stream<L>(self) -> MyEither<L, Self>
where
Self: Sized;
}
impl<S: Stream> EitherStreamExt for S {
fn left_stream<R>(self) -> MyEither<Self, R> {
MyEither::Left(self)
}
fn right_stream<L>(self) -> MyEither<L, Self> {
MyEither::Right(self)
}
}
Even better, use the fact that Result is an iterator and Stream::flatten exists:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::iter_ok(addrs.to_socket_addrs())
.map(stream::iter_ok)
.flatten()
}
Or if you really want to print errors:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::once(addrs.to_socket_addrs())
.map(stream::iter_ok)
.map_err(|e| eprintln!("err: {}", e))
.flatten()
}
See also:
Conditionally return empty iterator from flat_map
Conditionally iterate over one of several possible iterators
What is the correct way to return an Iterator (or any other trait)?

Resources