2

I have a function to download a file which is async:

async fn download_file() {
    fn main() {
        let resp = reqwest::blocking::get("https://sh.rustup.rs").expect("request failed");
        let body = resp.text().expect("body invalid");
        let mut out = File::create("rustup-init.sh").expect("failed to create file");
        io::copy(&mut body.as_bytes(), &mut out).expect("failed to copy content");
    }
}

I want to call this function to download a file and then await it when I need it.
But the problem is if I do it like this, I get an error:

fn main() {
    let download = download_file();
    // Do some work
    download.await; // `await` is only allowed inside `async` functions and blocks\nonly allowed inside `async` functions and blocks
    // Do some work
}

So I have to make the main function async, but when I do that I get another error:

async fn main() { // `main` function is not allowed to be `async`\n`main` function is not allowed to be `async`"
    let download = download_file();
    // Do some work
    download.await;
    // Do some work
}

So how can I use async and await
Thanks for helping

msrd0
  • 7,002
  • 9
  • 41
  • 74
NightmareXD
  • 139
  • 6
  • Related: [Do you always need an async fn main() if using async in Rust?](https://stackoverflow.com/questions/62309065/do-you-always-need-an-async-fn-main-if-using-async-in-rust) – Chayim Friedman Feb 14 '22 at 19:51

2 Answers2

3

The most commonly used runtime, tokio, provides an attribute macro so that you can make your main function async:

#[tokio::main]
async fn main() {
    let download = download_file().await;
}
msrd0
  • 7,002
  • 9
  • 41
  • 74
2

An established pattern for this is here.

From a synchronous block, build a new runtime then call block_on() on it:

let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();

let res = rt.block_on(async { something_async(&args).await });
t56k
  • 6,448
  • 8
  • 43
  • 105