I have this function with two generic parameters and I will have to add more of them.
Is there a cleaner way to do this?
fn handle_connection<Reqparser: traits::Reqparser<Stream = Stream>, Responder: traits::Responder>(mut stream: Stream) {...}
You can use a where clause when an inline generic parameter list gets unwieldy:
fn handle_connection<Reqparser, Responder>(mut stream: Stream)
where
Reqparser: traits::Reqparser<Stream = Stream>,
Responder: traits::Responder,
{
...
}
Related
I'm learning concurrency in rust and can't find a simple example how to return and resolve a Future.
How can I implement this javascript code in rust? It seems like I have to implement the Future trait on some struct and return it (right?), but I want a straightforward example. Instead of setTimeout it can be anything, just keep it simple.
function someAsyncTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("result")
}, 1_000)
})
}
The most straight forward fn() -> impl Future you can create is to simply use a async function:
use std::time::Duration;
use tokio::time;
async fn some_async_task() -> &'static str {
time::sleep(Duration::from_millis(1_000)).await;
"result"
}
If you 'remove' one layer of syntax sugar this becomes the following fn returning an async block.
use std::time::Duration;
use std::future::Future;
use tokio::time;
fn some_async_task() -> impl Future<Output = &'static str> {
async {
time::sleep(Duration::from_millis(1_000)).await;
"result"
}
}
The closest analogue in Rust futures to JavaScript's Promise constructor is the oneshot channel, as seen in futures and tokio. The “sender” of the channel is analogous to the resolve function, and the “receiver” of the channel is a Future that works like the Promise does. There is no separate reject operation; if you wish to communicate errors, you can do that by passing Result in the channel.
Translating your code:
use futures::channel::oneshot;
fn some_async_task() -> oneshot::Receiver<&'static str> {
let (sender, receiver) = oneshot::channel();
set_timeout(|| { // not a real Rust function, but if it were...
sender.send("result").unwrap()
}, 1_000);
receiver
}
Note that just like you only need new Promise in JS if you are translating something callback-like into the promise world, you only need to do this in Rust if you need to cause a future to complete from an outside event. Both should be fairly rare.
I have a function like this
fn get_html(address: &str) -> String {
let mut response = reqwest::blocking::get(
address,
);
response = response.unwrap_or_else(|_e| {String::from("")});
response = response.text().unwrap_or_else(|_e| {String::from("")});
return response
}
Where I'm checking for html content. I would like to return an empty String if any kind of an error occurs somewhere in this function.
I'm not sure how to deal with this because unwrap_or_else expecting Result not String.
The reqwest::blocking::get() function is returning a Result<Response>.
To obtain the html, you have to unwrap this result and call .text() method.
That will return a Result<String>, that you have to unwrap again.
In your code you assign a String::from("") when you unwrap the Result<Response>, and that is not right, because you have a Response when it is Ok and a String when it is an Err.
Instead you should match the result and return the String from the function:
fn get_html(address: &str) -> String {
let mut response = reqwest::blocking::get(
address,
);
match response {
Ok(response) => response.text().unwrap_or_else(|_e| String::from("")),
Err(_) => String::from(""),
}
}
In this code, you use unwrap_or_else() just on the .text() result.
While if you have an error on the response itself, you return a String from the function.
An idiomatic way to solve your issue would be to refactor slightly your code: because code in get_html could fail, it's natural that its signature reflects this, so instead of returning a String, it could return an Option<String>, leaving the caller decide on what to do in this case:
fn get_html(address: &str) -> Option<String> {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()
}
See the playground.
This makes the code much more straightforward. However, you may really want the signature of the function to be -> String, not -> Option<String>. In this case, there are two solutions.
The first solution would be to use the experimental try block. I mention this solution, not because it's currently the most adequate, but because it will be one day (most likely).
fn get_html(address: &str) -> String {
let result: Option<_> = try {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()?
};
result.unwrap_or_default()
}
See the playground.
Note that, as is, Rust is not able to figure out types on its own for the try block, so we have to help it, which makes this more verbose. This aspect will probably improve over time, when try blocks are stabilized.
Also note that, since the Default::default constructor of String produces an empty string, we can directly use .unwrap_or_default() instead of .unwrap_or(String::new()) or .unwrap_or_else(|| String::new()) (since an empty string is not allocated, the first option is also acceptable).
The second solution would simply be to add an other function with the wanted signature, and make it use the first function
fn get_html_failable(address: &str) -> Option<String> {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()
}
fn get_html(address: &str) -> String {
get_html_failable(address).unwrap_or_default()
}
This may seem unconvenient, but lots of libraries in Rust have internal error propagation using types that represent failure (such as Result or Option), because it's really convenient to write such functions and to compose them (both reqwest::blocking::get and .text() return a Result, and see how easy it is to use them in a function that returns an Option), and have wrapper function that expose the wanted signature (most libraries will still expose fail types, but if you are writing an application it's not necessarily the best choice).
A variable of both preceding workarounds is to "simulate" a try block in stable Rust, without relying on an additional toplevel function.
fn get_html(address: &str) -> String {
(|| reqwest::blocking::get(address).ok()?.text().ok())()
.unwrap_or_default()
}
See the playground.
Note that, in this case, countrary to the try version, Rust is able to figure out the right types on its own.
This is probably the least readable solution, so I wouldn't recommend it (use try blocks instead). But it works.
Depending on configuration I need to select either stdout or sink once, and pass the results as an output destination for subsequent output call.s
My Java and C++ experience tell me that abstracting away from the concrete type is wise and makes room for future design changes. This code however won't compile:
let out = if std::env::var("LOG").is_ok() {
std::io::stdout()
} else {
std::io::sink()
};
Stating...
`if` and `else` have incompatible types
What is the Rust-o-matic way of solving this?
Dynamic dispatch using trait objects is probably what you need:
use std::io::{self, Write};
use std::env;
fn get_output() -> Box<dyn Write> {
if env::var("LOG").is_ok() {
Box::new(io::stdout())
} else {
Box::new(io::sink())
}
}
let out = get_output();
The approach from Peter's answer is probably what you need, but it does require an extra allocation. (Which probably doesn't matter in the least in this case, but could matter in other scenarios.) If you are only passing out downward, i.e. as argument to functions, you can avoid the allocation by using two variables to store the different outputs:
let (mut stdout, mut sink);
let out: &mut dyn Write = if std::env::var("LOG").is_ok() {
stdout = std::io::stdout();
&mut stdout
} else {
sink = std::io::sink();
&mut sink
};
// ...proceed to use out...
Here is an example of it in action:
let msg = stream.next().await.context("expected a message")??;
Is it just ? being done twice? If so why does it need to be done in this case?
Yes, it's just ? being done twice; there is no ?? operator.
stream is a WsStream. WsStream is a type defined in the same module. WsStream implements Stream.
stream.next() invokes StreamExt::next, which returns a future that yields Option<Self::Item>. Self::Item is defined to be tungstenite::Result<Message> (= Result<Message, tungstenite::Error>) for WsStream. This means that the result of stream.next().await is of type Option<Result<Message, tungstenite::Error>>.
Then, context is applied on the value. Context is implemented for Option<T> and for Result<T, E>, but the output is always a Result. However, context doesn't flatten anything, so we end up with Result<Result<Message, tungstenite::Error>, anyhow::Error>. The two uses of ? therefore serve to handle the two levels of Results.
Yes, it's just the ? operator done twice. A quick example:
fn result_of_result() -> Result<Result<i32, String>, String> {
Ok(Ok(42))
}
fn f() -> Result<(), String> {
println!("{:?}", result_of_result());
println!("{:?}", result_of_result()?);
println!("{:?}", result_of_result()??);
Ok(())
}
fn main() {f();}
Outputs:
Ok(Ok(42))
Ok(42)
42
It's approximately an operator for unwrap() or try!, so this could be expanded to something like:
let msg = try!(stream.next().await.context("expected a message")).unwrap();
With async code you're going to see await? quite often, but await?? does seem odd.
I'd like to make use of this function:
u8::from_str(src: &str) -> Result<u8, ParseIntError>
I can't seem to figure out the syntax to use it. This is what I am currently trying
use std::u8;
match u8::from_str("89") {
// Stuff...
}
I receive the following error:
error: unresolved name `u8::from_str`
What is the proper way to use functions that are defined in primitive modules?
Thanks in advance for any help!
The trick here is that from_str is actually part of the trait FromStr. You need to use that trait, then specify which implementation you want to use:
use std::str::FromStr;
fn main() {
match <u8 as FromStr>::from_str("89") {
// Stuff...
}
}
However, this particular concept has a more ergonomic option: parse:
fn main() {
match "89".parse::<u8>() {
// Stuff...
}
}
And you might be able to remove the ::<u8> if something else constrains the type enough for it to be inferred.