I have started looking into Rust (and Warp) just a few days ago. I can't get into my head the following:
Given the following endpoints
let hi = warp::path("hi");
let bye = warp::path("bye");
let howdy = warp::path("howdy");
Why is the following ok
let routes = hi.or(bye).or(howdy);
But not the following:
let mut routes = hi.or(bye);
routes = routes.or(howdy);
Which throws the compile error:
error[E0308]: mismatched types
--> src/lib.rs:64:14
|
63 | let mut routes = hi.or(bye);
| -------------------- expected due to this value
64 | routes = routes.or(howdy);
| ^^^^^^^^^^^^^^^^ expected struct `warp::filter::and_then::AndThen`, found struct `warp::filter::or::Or`
or() wraps in a new type. You can use shadowing:
let routes = hi.or(bye);
let routes = routes.or(howdy);
If you really need them to have the same type (e.g. for usage in a loop), you can use the boxed() method to create a trait object:
let mut routes = hi.or(bye).unify().boxed();
routes = routes.or(howdy).unify().boxed();
Related
I am trying to write a section of code that does a web request every few seconds and updates a struct in rust. I have so far tried using a thread to accomplish this task however I am having some real trouble moving variables into the thread and assigning the results of the web request to a struct once it completes.
I have provided a small code sample below that doesn't include a web request but does demonstrate the problem I am having moving variables around.
Code:
use std::thread;
#[derive(Debug, Clone)]
struct input_holder {
i : String,
}
fn main() {
// pass this string into the thread loop.
let input = String::from("This is a string");
let input_loop = input.clone();
//assign the output of the method to this struct.
let ih = input_holder {
i : input
};
thread::spawn(|| {
let runtime = tokio::runtime::Runtime::new().unwrap();
loop {
let _ = runtime.block_on(runtime.spawn(async move {
let _new_input = match update_string(input_loop.clone(), ih.clone()){
Some(ni) => ni,
None => String::from("None")
};
}));
}
});
}
//This is where I would do the web request. I can test this method outside of the thread and it works as expected.
pub fn update_string(_input: String, mut ih: input_holder) -> Option<String> {
ih.i = String::from("This is an updated string");
Some(String::from("This is an updated string"))
}
Below is the error message I am running into:
error[E0382]: use of moved value: `ih`
--> src/main.rs:64:63
|
64 | let _ = runtime.block_on(runtime.spawn(async move {
| _______________________________________________________________^
65 | | let _new_input = match update_string(input_loop.clone(), ih.clone()){
| | -- use occurs due to use in generator
66 | | Some(ni) => ni,
67 | | None => String::from("None")
68 | | };
69 | | }));
| |_____________^ value moved here, in previous iteration of loop
|
= note: move occurs because `ih` has type `input_holder`, which does not implement the `Copy` trait
There doesn't seem to be anyway for me to pass ih that I am aware of, I don't know what use occurs due to use in generator means and Google does not seem to have much on this error (there are a bunch of options for move occurs due to use in generator but nothing for this error).
I have tried cloning and not cloning, borrowing, removing the move from the loop (I should note here I can't implement the copy trait on the struct). How are you supposed to get variables in and out of a thread loop like this?
I think I might not be understanding something about how you are supposed to move variables around in rust because in general I find myself needing to make lots and lots of copies of any value I plan to pass between methods.
I simply tried to create a recoverable signature using the k256 crate documentation as a reference as follows, but for some reason I get a compile error regarding the sign method to create the signature.
use k256::ecdsa::{recoverable, signature::Signer, SigningKey};
use rand_core::OsRng;
fn main() {
let signing_key = SigningKey::random(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
let signature: recoverable::Signature = signing_key.sign(message);
}
error[E0277]: the trait bound `k256::ecdsa::recoverable::Signature: PrehashSignature` is not satisfied
--> src/main.rs:9:57
|
9 | let signature: recoverable::Signature = signing_key.sign(message);
| ^^^^ the trait `PrehashSignature` is not implemented for `k256::ecdsa::recoverable::Signature`
|
= help: the following other types implement trait `PrehashSignature`:
ecdsa::Signature<C>
ecdsa::der::Signature<C>
k256::schnorr::Signature
= note: required because of the requirements on the impl of `Signer<k256::ecdsa::recoverable::Signature>` for `k256::ecdsa::SigningKey`
I have enabled the "ecdsa" features as follows:
k256 = { version = "0.11.3", features = ["ecdsa"] }
Is there any other setting I need to do?
As #isaactfa mentioned at the comment, I need to enable BOTH "ecdsa" and "keccak256" features:
k256 = { version = "0.11.3", features = ["ecdsa", "keccak256"] }
This is part of my code, the error in rest move |event: Event|
pub struct FileStream{
el : HtmlInputElement,
}
impl FileStream {
pub fn new(el : HtmlInputElement) -> FileStream {
FileStream {el}
}
pub fn get_file(&self){
let file = self.el.files().unwrap().get(0).unwrap();
let file_reader = FileReader::new().unwrap();
file_reader.read_as_data_url(&file).unwrap();
let onloadend = Closure::wrap(Box::new(move |event: Event| {
let file_reader = file_reader.unchecked_into::<web_sys::FileReader>();
let data_url = file_reader.result().unwrap();
let data_url = data_url.unchecked_into::<JsValue>();
let data_url = data_url.as_string().unwrap();
let audio_el = self.el.unchecked_into::<HtmlAudioElement>();
audio_el.set_src(&data_url);
}) as Box<dyn FnMut(_)>);
file_reader.set_onloadend(Some(onloadend.as_ref().unchecked_ref()));
}
}
I don't know how to fix this error...
error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
--> src/lib.rs:29:48
|
29 | let onloadend = Closure::wrap(Box::new(move |event: Event| {
| - ^^^^^^^^^^^^^^^^^^^ this closure implements `FnOnce`, not `FnMut`
| _______________________________________|
| |
30 | | let file_reader = file_reader.unchecked_into::<web_sys::FileReader>();
| | ----------- closure is `FnOnce` because it moves the variable `file_reader` out of its environment
31 | | let data_url = file_reader.result().unwrap();
32 | | let data_url = data_url.unchecked_into::<JsValue>();
... |
35 | | audio_el.set_src(&data_url);
36 | | }) as Box<dyn FnMut(_)>);
| |__________- the requirement to implement `FnMut` derives from here
For more information about this error, try `rustc --explain E0525`.
When the closure is created, it moves file_reader into itself (because it is declared as a move || closure). Then, when the closure is called, it consumes file_reader via calling unchecked_into(). Therefore, if the closure were to be called a second time, it would no longer have a file_reader to use. That's why the compiler decides the closure is only a “FnOnce”.
On the other hand, the set_onloadend callback mechanism wants a function that can be called more than once, in case the underlying event somehow happens more than once.
The general solution to this problem is to adjust your function so that it can be called more than once — as far as the compiler is concerned. You can do this by putting the value that must be moved in an Option outside the closure, then using Option::take() inside the closure to get it back out — thus leaving the Option value to be None if the function ever gets called again.
However, in this case, it would be simpler to just remove the entire unchecked_into() line. As far as I can see, there is no need for it, because the object is already typed as a FileReader. (But I haven't tried compiling your code to see if it works without, so maybe I missed something.)
I have been writing a client in Rust which makes a request to a server with a client certificate (Pkcs12). Although this has been answered How to make a request with client certificate in Rust, the code doesn't compile as it is. If I make some modifications like replacing '?' by call to unwrap() function,
Code:
let tls_conn = TlsConnector::builder().unwrap()
.identity(cert).unwrap()
.build().unwrap();
Error:
let tls_conn = TlsConnector::builder().unwrap()
| ____________________^
18 | | .identity(cert).unwrap()
| |________________________________^ cannot move out of borrowed content.
I rewrote the above line of code and broke it down into multiple lines for debugging:
let ref mut init_tls_conn_builder = TlsConnector::builder().unwrap();
let ref mut tls_conn_builder = init_tls_conn_builder.identity(cert).unwrap();
let tls_conn = tls_conn_builder.build().unwrap();
I get the error as follows:
let tls_conn = tls_conn_builder.build().unwrap();
| ^^^^^^^^^^^^^^^^ cannot move out of borrowed content.
I am new to Rust and seeking help on this, can anyone please share an example code which compiles?
You don't need any mut references here. The builder pattern is create smth mutable (TlsConnector::builder().unwrap()), mutate it (tls_conn_builder.identity(cert)) and then get the result (build). Try this code
let mut tls_conn_builder = TlsConnector::builder().unwrap();
tls_conn_builder.identity(cert);
let tls_conn = tls_conn_builder.build().unwrap();
Here's the code:
extern crate tempdir;
use std::env;
use tempdir::*;
#[test]
fn it_installs_component() {
let current_dir = env::current_dir().unwrap();
let home_dir = env::home_dir().unwrap();
let tmp_dir = env::temp_dir();
println!("The current directory is: {}", current_dir.display());
println!("The home directory is: {}", home_dir.display());
println!("The temporary directory is: {}", tmp_dir.display());
let stage_dir = TempDir::new_in(tmp_dir.as_path(), "Components-Test");
let components_dir = TempDir::new_in(stage_dir.unwrap().path(), "Components");
// This is "offending line"
// let components_make_dir = TempDir::new_in(stage_dir.unwrap().path(), "Components.make");
println!("---- {:?}", components_dir.unwrap().path());
//println!("---- {:?}", components_make_dir.unwrap().path());
}
If the offending line is commented out the code compiles fine. If I uncomment it, I start getting an error:
error[E0382]: use of moved value: `stage_dir`
--> src/main.rs:21:51
|
18 | let components_dir = TempDir::new_in(stage_dir.unwrap().path(), "Components");
| --------- value moved here
...
21 | let components_make_dir = TempDir::new_in(stage_dir.unwrap().path(), "Components.make");
| ^^^^^^^^^ value used here after move
|
= note: move occurs because `stage_dir` has type `std::result::Result<tempdir::TempDir, std::io::Error>`, which does not implement the `Copy` trait
I understand the problem is that I move stage_dir when I use it the first time, but I can't see how to share stage_dir between those two sub-folders as I will need to access them both in my test.
I tried playing with &stage_dir but that produced some other warnings even more obscure to me.
TempDir::new gives you back a Result<TempDir>. You're trying to unwrap it each time, rather than unwrap it once to get a TempDir, and then share that.
So change
let stage_dir = TempDir::new_in(tmp_dir.as_path(), "Components-Test");
to
let stage_dir = TempDir::new_in(tmp_dir.as_path(), "Components-Test").unwrap();
instead.