0

I want to write a program which recursively deletes a directory with async functions in Rust 1.39.

As a first step I have tried the following code, but it doesn't compile:

use std::env;
use failure::Error;
use futures::Future;
use std::path::PathBuf;
use tokio::prelude::*;

fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
    let task = tokio::fs::read_dir(path)
        .flatten_stream()
        .for_each(move |entry| {
            let filepath = entry.path();
            if filepath.is_dir() {
                future::Either::A(walk(filepath))
            } else {
                println!("File: {:?}", filepath);
                future::Either::B(future::ok(()))
            }
        })
        .map_err(Error::from)
        .and_then(|_| {
            println!("All tasks done");
        });
    Box::new(task)
}

fn main() -> Result<(), std::io::Error> {
    let args: Vec<String> = env::args().collect();
    let dir = &args[1];
    let t = walk(PathBuf::from(&dir)).map_err(drop);
    tokio::run(t);
    Ok(())
}

When I run cargo build I get the following output:

error[E0220]: associated type `Item` not found for `core::future::future::Future`
  --> src\main.rs:10:42
   |
10 | fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
   |                                          ^^^^^^^^^ associated type `Item` not found

error[E0220]: associated type `Error` not found for `core::future::future::Future`
  --> src\main.rs:10:53
   |
10 | fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
   |                                                     ^^^^^^^^^^^^^ associated type `Error` not found

error[E0191]: the value of the associated type `Output` (from the trait `core::future::future::Future`) must be specified
  --> src\main.rs:10:31
   |
10 | fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified

Cargo.toml:

[dependencies]
async-std = "1.0.1"
failure = "0.1.6"
futures = "0.3.1"
tokio = "0.1.22"

Any help?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Martin Bammer
  • 537
  • 7
  • 19
  • I've switched to futures = "0.1.29". Now I get completely different errors: – Martin Bammer Nov 12 '19 at 18:20
  • error[E0271]: type mismatch resolving ... main.rs:12:10 .for_each(move |entry| { ^^^^^^^^ expected struct `failure::error::Error`, found struct `std::io::Error` error[E0599]: no method named `map_err`... main.rs:21:10 ^^^^^^^ method not found... – Martin Bammer Nov 12 '19 at 18:22

1 Answers1

1

You are using futures 0.3, which tokio 0.1 doesn't support yet. Instead, import Tokio and use its prelude module, which re-exports the version of futures that it does support:

use std::{env, path::PathBuf};
use tokio::prelude::*; // 0.1.22

type Error = Box<dyn std::error::Error + Send + Sync>;

fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
    let task = tokio::fs::read_dir(path)
        .flatten_stream()
        .map_err(Error::from)
        .for_each(|entry| {
            let filepath = entry.path();
            if filepath.is_dir() {
                future::Either::A(walk(filepath))
            } else {
                println!("File: {:?}", filepath);
                future::Either::B(future::ok(()))
            }
        })
        .inspect(|_| {
            println!("All tasks done");
        });
    Box::new(task)
}

fn main() -> Result<(), std::io::Error> {
    let args: Vec<String> = env::args().collect();
    let dir = &args[1];
    let t = walk(PathBuf::from(&dir)).map_err(drop);
    tokio::run(t);
    Ok(())
}

You also need to convert the error after flatten_stream and cannot use and_then with println! as it doesn't return a future. Use inspect for side-effect debugging things.

Idiomatically, you don't need to collect all the arguments just to use one (use Iterator::nth) and you don't need to require a PathBuf as an argument. It's unclear why you return a Result from main as it can never be an Err.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366