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();
Related
I had been to this question earlier because the question and the answer(s) were very useful. Yet, my case seems to be somewhat different. Hence, this post:
Because this example (and the accompanying solution/explanation) are very similar to my case, I thought of adding it here (instead of asking a new question).
I am simply trying to read the entries of a directory (Ubuntu Linux 22.10, ext4 filesystem):
let mut all_chosenfiles: Vec<&str> = Vec::new();
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
let chosen_file = next_file.unwrap().path();
all_chosenfiles.push(chosen_file.to_owned().to_str().unwrap());
}
}
}
}
Not very idiomatic, I agree, but it serves the purpose at hand.
The compiler is not happy though:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:31:46
|
31 | all_chosenfiles.push(chosen_file.to_owned().to_str().unwrap());
| ---------------------^^^^^^^^^^^^^^^^^^^^^^-------------------- temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
I understand what is she complaining about. I have tried to pacify her, by using let as has been prescribed here:
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
let chosen_path = next_file.unwrap().path();
let chosen_file = &chosen_path.to_owned().to_str().unwrap();
all_chosenfiles.push(chosen_file);
}
}
}
}
She is stubborn:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:31:44
|
31 | let chosen_file = &chosen_path.to_owned().to_str().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
32 | all_chosenfiles.push(chosen_file);
| ----------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
I am scratching my head. I am missing some idiom, I am sure.
Is a derefencing using '*' operator (viz., *chosent_file) the only way out?
I have gotten around, for the time being, by:
let mut all_chosenfiles: Vec<String> = Vec::new(); // of String, and not of &str
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
// Using as_ref() before unwrapping
let chosen_path: PathBuf = next_file.as_ref().unwrap().path();
// Doc says that, to_str()
// "Yields a &str slice if the Path is valid unicode"
let chosen_file: Option<&str> = chosen_path.to_str();
// Explicitly owning a String, made out of &str, below!
all_chosenfiles.push(chosen_file.unwrap().to_owned());
}
}
}
}
Honestly, I am not really sure why it is working. By calling next_file.as_ref(), I ensure that a reference to that memory is held. But, how does that solve the problem of temporary which is freed etc. issue? Moreover, cloning the pathstrings by using to_str() seems to be wasteful to me.
Help me fill in, the gaps in my understanding!
i am trying to make a simple tauri Program where i have a Filetree of all Files and sub files of a chosen directory.
I have not got many experience in Rust and ran into a problem with Ownerships.
Code
use std::fs;
use std::path::PathBuf;
use trees::Tree;
//FileTree
//https://docs.rs/crate/file_tree/0.1.1
fn main() {
let path = PathBuf::from("MyPath...");
let tree = Tree::new(path);
build_tree(tree);
}
fn build_tree( mut tree:Tree<PathBuf>){
let path = tree.front().unwrap().data();
for entry in fs::read_dir(path).unwrap() {
let entry = entry.unwrap();
let subpath = entry.path();
if subpath.is_dir() {
let subtree = Tree::new(subpath);
build_tree(subtree);
tree.push_back(subtree);
} else {
tree.push_back(Tree::new(subpath));
}
}
tree;
}
This is what i figured out so far but in the line:
tree.push_back(subtree);
I got following Error
error[E0382]: use of moved value: subtree
--> src\main.rs:23:28
|
21 | let subtree = Tree::new(subpath);
| ------- move occurs because `subtree` has type `trees::Tree<PathBuf>`, which does not implement the `Copy` trait
22 | build_tree(subtree);
| ------- value moved here
23 | tree.push_back(subtree);
| ^^^^^^^ value used here after move
What i tried
I tried to make subtree mutable but it didn't work either because it says mut is not necessary
Also i already tried to use the Filetree crate of Rust but it was not exectely what i was looking for.
Someone got other Ideas how to Implement a Filetree in Rust or Tauri?
You are trying to mutate a tree in your build_tree function, but since the function is taking ownership of whatever you pass in, you get the value used here after move error afterwards. To allow a function to mutate a variable and the variable still exist afterwards, you should instead pass in a mutable reference to the tree:
use std::fs;
use std::path::PathBuf;
use trees::Tree;
fn main() {
let path = PathBuf::from("MyPath...");
let mut tree = Tree::new(path);
build_tree(&mut tree);
}
fn build_tree(tree: &mut Tree<PathBuf>) {
let path = tree.front().unwrap().data();
for entry in fs::read_dir(path).unwrap() {
let entry = entry.unwrap();
let subpath = entry.path();
if subpath.is_dir() {
let mut subtree = Tree::new(subpath);
build_tree(&mut subtree);
tree.push_back(subtree);
} else {
tree.push_back(Tree::new(subpath));
}
}
}
Notice also that you need to change some variable declarations to use let mut so that the compiler allows a mutable reference (&mut) to that variable to be used.
This can also be done by taking ownership and returning a new value, but this method looks a little closer to what you had originally.
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();
I'm making a scraper and want to download the HTML source of a website so that it can be parsed. I'm using fantoccini with WebDriver to log in to the site. I have an asynchronous funct
Now that I'm logged in, what do I need to do to extract the HTML source?
What I have so far is this:
let htmlsrc = client.source();
let mut file = File::create("htmlsrc.html").unwrap();
fs::write("htmlsrc.txt", htmlsrc).await?;
However this gives me this error:
error[E0277]: the trait bound `impl Future: AsRef<[u8]>` is not satisfied
--> src/main.rs:44:30
|
44 | fs::write("htmlsrc.txt", htmlsrc).await?;
| --------- ^^^^^^^ the trait `AsRef<[u8]>` is not implemented for `impl Future`
I'm new to Rust, so I'm not very sure of what I'm doing.
Any help would be appreciated!
The full code is this:
use fantoccini::{ClientBuilder, Locator, Client};
use std::time::Duration;
use tokio::time::sleep;
use std::fs::File;
use tokio::fs;
// let's set up the sequence of steps we want the browser to take
#[tokio::main]
async fn main() -> Result<(), fantoccini::error::CmdError> {
let s_email = "email";
let password = "pass;
// Connecting using "native" TLS (with feature `native-tls`; on by default)
let mut c = ClientBuilder::native()
.connect("http://localhost:4444").await
.expect("failed to connect to WebDriver");
// first, go to the Managebac login page
c.goto("https://bavarianis.managebac.com/login").await?;
// define email field with css selector
let mut email_field = c.wait().for_element(Locator::Css("#session_login")).await?;
// type in email
email_field.send_keys(s_email).await?;
// define email field with css selector
let mut pass_field = c.wait().for_element(Locator::Css("#session_password")).await?;
// type in email
pass_field.send_keys(password).await?;
// define sign in button with xpath
let signin_button = "/html/body/main/div/div/form/div[2]/input";
let signin_button = c.wait().for_element(Locator::XPath(signin_button)).await?;
// click sign in
signin_button.click().await?;
let htmlsrc = c.source();
let mut file = File::create("htmlsrc.html").unwrap();
fs::write("htmlsrc.txt", htmlsrc).await?;
//temp to observe
sleep(Duration::from_millis(6000)).await;
//c.close().await?;
Ok(())
}
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.