Print inside async function - rust

pub async fn twitterauth() -> String {
let con_token = egg_mode::KeyPair::new("public_token", "secret_token");
let request_token = egg_mode::auth::request_token(&con_token, "oob").await.unwrap();
let auth_url = egg_mode::auth::authorize_url(&request_token);
return auth_url;
}
fn output() -> impl Future<Output = String> {
twitterauth()
}
fn main() {
let authurl = output();
println!("{}", authurl);
}
I am having trouble returning this variable auth_url to the user by printing it in the console or the GUI.
When I put the printing statement in the async function, nothing happens and I can't call the function in main() either.
Right now it gives me this error:
`impl Future<Output = String>` doesn't implement `std::fmt::Display`
If i use this approach, it throws me another error.

Your twitterauth() function isn't actually run.
async functions don't run when you call them. They return a future. Only when this future is .awaited they will run.
The problem is that you cannot .await in main(). The solution is to plug in a runtime, like tokio.
With it, it is as simple as:
#[tokio::main]
async fn main() {
let authurl = output().await;
println!("{}", authurl);
}

Related

rust async update of HashMap with "or_insert_with"

I am trying to lazily populate a HashMap from a DB with async calls when the map does not already have an entry.
Rust compiler warns async closures are unstable but that I should try async {.
I am trying to follow that suggestion but I get the expected a FnOnce<()> closure error in the comments:
use std::collections::HashMap;
use tokio::runtime::Runtime;
async fn get_from_store(key: String) -> String {
// pretend to get this from an async sqlx db call
String::from(format!("value-for-{key}"))
}
async fn do_work() {
let mut map: HashMap<String, String> = HashMap::new();
let key = String::from("key1");
// the compiler advised async closures were unstable and...
// to use an async block, remove the `||`: `async {` (rustc E0658)
map.entry(key.clone())
.or_insert_with(async { get_from_store(key) }.await);
// the above now gives the error:
//expected a `FnOnce<()>` closure, found `impl Future<Output = String>...xpected an `FnOnce<()>` closure, found `impl Future<Output = String>`
for (key, value) in &map {
println!("{}: {}", key, value);
}
}
fn main() {
let runtime = Runtime::new().unwrap_or_else(|e| panic!("Haha: {e}"));
let result = do_work();
match runtime.block_on(result) {
_ => {}
}
}
There may be reasons not to update HashMap via async but the error above gave me hope I was just doing this wrong...
You won't be able to use .await in that position. That's because it requires that the return type of the closure is a Future, but the signature of or_insert_with does not expect that.
I would do it more simply, keeping the .await inside the async function that you already have:
use std::collections::hash_map::Entry;
async fn do_work() {
let mut map: HashMap<String, String> = HashMap::new();
let key = String::from("key1");
if let Entry::Vacant(entry) = map.entry(key.clone()) {
entry.insert(get_from_store(key).await);
}
for (key, value) in &map {
println!("{}: {}", key, value);
}
}

Ignore errors in FuturesUnordered

I have the following setup
use futures::{
future,
stream::{self, Stream, FuturesUnordered},
};
use tokio;
fn foo(futures: FuturesUnordered<impl futures::Future<Output = std::io::Result<impl std::fmt::Binary>>>) {}
fn bar(futures: FuturesUnordered<impl futures::Future<Output = impl std::fmt::Binary>>) {}
#[tokio::main]
async fn main() {
let futures: FuturesUnordered<_> = (0..10).map(move |i| async move {
let mut delay = core::time::Duration::from_secs(rand::Rng::gen_range(&mut rand::thread_rng(), 1..3));
tokio::time::sleep(delay).await;
Ok::<i32, std::io::Error>(i) // this line can't be changed
}).collect();
// this is ok
foo(futures);
// this will not compile
bar(futures);
}
playground link
I want to be able to call the bar function with futures. Given that I can't change how futures is initialized, how do I ignore the errors in the stream and only process the elements which are not errors?
There is a similar SO question about this here: How can I remove or otherwise ignore errors when processing a stream?
But the answer uses stream::iter_ok which I think is deprecated or something?
I expected the following to work:
use futures::{
future,
stream::{self, Stream, FuturesUnordered},
StreamExt,
};
use tokio;
fn foo(futures: FuturesUnordered<impl futures::Future<Output = std::io::Result<impl std::fmt::Binary>>>) {}
async fn bar(futures: FuturesUnordered<impl futures::Future<Output = impl std::fmt::Binary>>) {
futures.for_each(|n| {
async move {
println!("Success on {:b}", n);
}
}).await
}
#[tokio::main]
async fn main() {
let futures: FuturesUnordered<_> = (0..10).map(move |i| async move {
let mut delay = core::time::Duration::from_secs(rand::Rng::gen_range(&mut rand::thread_rng(), 1..3));
tokio::time::sleep(delay).await;
Ok::<i32, std::io::Error>(i)
}).collect();
let futures = futures
.then(|r| future::ok(iter_ok::<_, ()>(r)))
.flatten();
bar(futures).await;
}
playground link
You can create a stream over the successful values of another stream like so:
use futures::{
stream::{self, Stream, FuturesUnordered},
StreamExt,
};
use tokio;
async fn bar(futures: impl Stream<Item = impl std::fmt::Binary>) {
futures.for_each(|n| {
async move {
println!("Success on {:b}", n);
}
}).await
}
#[tokio::main]
async fn main() {
let futures: FuturesUnordered<_> = (0..10).map(move |i| async move {
let delay = core::time::Duration::from_secs(rand::Rng::gen_range(&mut rand::thread_rng(), 1..3));
tokio::time::sleep(delay).await;
Ok::<i32, std::io::Error>(i)
}).collect();
let futures = futures
.then(|r| async { stream::iter(r.into_iter()) })
.flatten();
bar(futures).await;
}
Note: since the type returned by .then() includes the closure and thus can't be named we have to change the type of futures in bar().

How to specify an output type for a Future/async block?

use tokio::runtime::Runtime;
// Create the runtime
let rt = Runtime::new().unwrap();
// Execute the future, blocking the current thread until completion
let s = rt.block_on(async {
println!("hello");
});
is it possible to specify an output type for a future block? On the code above, s: (), but I wanted to be Result<(), Error> so I can return some error from inside the block.
I am not quite familiar with async rust, but as far as I know, the return type of an async fn or async block is impl Future<Output=TheRealReturnTypeOfFnBody>. Once blocked on, as you did rt.block_on(async block), the return type will become TheRealReturnTypeOfFnBody, therefore:
To make s have type Result<(), Error>, you have to implement it in the function body(i.e. make TheRealReturnTypeOfFnBody Result<(), Error>)
use tokio::runtime::Runtime;
fn main() {
// Create the runtime
let rt = Runtime::new().unwrap();
// Execute the future, blocking the current thread until completion
let s: () = rt.block_on(async {
println!("hello");
});
let s_with_error_case: Result<(), &str> = rt.block_on(async {
if false {
Err("run into a trouble")
} else {
println!("erverything is fine");
Ok(())
}
});
if let Err(err_info) = s_with_error_case {
eprintln!("{}", err_info);
}
}

Compilation error reqwest::get(url).status() [duplicate]

I recently started to learn Rust and I'm not sure how I can return future value from a function that should return a Result. When I try to return just the response variable and remove the Result output, I get an error: cannot use the ? operator in a function that returns std::string::String
#[tokio::main]
async fn download() -> Result<(),reqwest::Error> {
let url = "https://query1.finance.yahoo.com/v8/finance/chart/TSLA";
let response = reqwest::get(url)
.await?
.text()
.await?;
Ok(response)
}
What I expect in main() is to get and print the response value:
fn main() {
let response = download();
println!("{:?}", response)
}
I suppose your code should looks something like this
extern crate tokio; // 0.2.13
async fn download() -> Result<String, reqwest::Error> {
let url = "https://query1.finance.yahoo.com/v8/finance/chart/TSLA";
reqwest::get(url).await?.text().await
}
#[tokio::main]
async fn main() {
let response = download().await;
println!("{:?}", response)
}
Here is rust playground link

Calling an async function synchronously with tokio [duplicate]

I am trying to use hyper to grab the content of an HTML page and would like to synchronously return the output of a future. I realized I could have picked a better example since synchronous HTTP requests already exist, but I am more interested in understanding whether we could return a value from an async calculation.
extern crate futures;
extern crate hyper;
extern crate hyper_tls;
extern crate tokio;
use futures::{future, Future, Stream};
use hyper::Client;
use hyper::Uri;
use hyper_tls::HttpsConnector;
use std::str;
fn scrap() -> Result<String, String> {
let scraped_content = future::lazy(|| {
let https = HttpsConnector::new(4).unwrap();
let client = Client::builder().build::<_, hyper::Body>(https);
client
.get("https://hyper.rs".parse::<Uri>().unwrap())
.and_then(|res| {
res.into_body().concat2().and_then(|body| {
let s_body: String = str::from_utf8(&body).unwrap().to_string();
futures::future::ok(s_body)
})
}).map_err(|err| format!("Error scraping web page: {:?}", &err))
});
scraped_content.wait()
}
fn read() {
let scraped_content = future::lazy(|| {
let https = HttpsConnector::new(4).unwrap();
let client = Client::builder().build::<_, hyper::Body>(https);
client
.get("https://hyper.rs".parse::<Uri>().unwrap())
.and_then(|res| {
res.into_body().concat2().and_then(|body| {
let s_body: String = str::from_utf8(&body).unwrap().to_string();
println!("Reading body: {}", s_body);
Ok(())
})
}).map_err(|err| {
println!("Error reading webpage: {:?}", &err);
})
});
tokio::run(scraped_content);
}
fn main() {
read();
let content = scrap();
println!("Content = {:?}", &content);
}
The example compiles and the call to read() succeeds, but the call to scrap() panics with the following error message:
Content = Err("Error scraping web page: Error { kind: Execute, cause: None }")
I understand that I failed to launch the task properly before calling .wait() on the future but I couldn't find how to properly do it, assuming it's even possible.
Standard library futures
Let's use this as our minimal, reproducible example:
async fn example() -> i32 {
42
}
Call executor::block_on:
use futures::executor; // 0.3.1
fn main() {
let v = executor::block_on(example());
println!("{}", v);
}
Tokio
Use the tokio::main attribute on any function (not just main!) to convert it from an asynchronous function to a synchronous one:
use tokio; // 0.3.5
#[tokio::main]
async fn main() {
let v = example().await;
println!("{}", v);
}
tokio::main is a macro that transforms this
#[tokio::main]
async fn main() {}
Into this:
fn main() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async { {} })
}
This uses Runtime::block_on under the hood, so you can also write this as:
use tokio::runtime::Runtime; // 0.3.5
fn main() {
let v = Runtime::new().unwrap().block_on(example());
println!("{}", v);
}
For tests, you can use tokio::test.
async-std
Use the async_std::main attribute on the main function to convert it from an asynchronous function to a synchronous one:
use async_std; // 1.6.5, features = ["attributes"]
#[async_std::main]
async fn main() {
let v = example().await;
println!("{}", v);
}
For tests, you can use async_std::test.
Futures 0.1
Let's use this as our minimal, reproducible example:
use futures::{future, Future}; // 0.1.27
fn example() -> impl Future<Item = i32, Error = ()> {
future::ok(42)
}
For simple cases, you only need to call wait:
fn main() {
let s = example().wait();
println!("{:?}", s);
}
However, this comes with a pretty severe warning:
This method is not appropriate to call on event loops or similar I/O situations because it will prevent the event loop from making progress (this blocks the thread). This method should only be called when it's guaranteed that the blocking work associated with this future will be completed by another thread.
Tokio
If you are using Tokio 0.1, you should use Tokio's Runtime::block_on:
use tokio; // 0.1.21
fn main() {
let mut runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime");
let s = runtime.block_on(example());
println!("{:?}", s);
}
If you peek in the implementation of block_on, it actually sends the future's result down a channel and then calls wait on that channel! This is fine because Tokio guarantees to run the future to completion.
See also:
How can I efficiently extract the first element of a futures::Stream in a blocking manner?
As this is the top result that come up in search engines by the query "How to call async from sync in Rust", I decided to share my solution here. I think it might be useful.
As #Shepmaster mentioned, back in version 0.1 futures crate had beautiful method .wait() that could be used to call an async function from a sync one. This must-have method, however, was removed from later versions of the crate.
Luckily, it's not that hard to re-implement it:
trait Block {
fn wait(self) -> <Self as futures::Future>::Output
where Self: Sized, Self: futures::Future
{
futures::executor::block_on(self)
}
}
impl<F,T> Block for F
where F: futures::Future<Output = T>
{}
After that, you can just do following:
async fn example() -> i32 {
42
}
fn main() {
let s = example().wait();
println!("{:?}", s);
}
Beware that this comes with all the caveats of original .wait() explained in the #Shepmaster's answer.
This works for me using tokio:
tokio::runtime::Runtime::new()?.block_on(fooAsyncFunction())?;

Resources