How to insert into HashMap dereferenced iterator of LinkedList? - rust

How to fix issue on a screenshot? I already tried to make it mutable, but that is not the point. What can it be, how to get rid of it? I will be thankful for the changes in the code.
screenshot:
(source: i.ibb.co)
let mut buf = vec![0 as u8; 4096];
for stream in listener.incoming() {
match stream {
Ok(mut stream) => {
match stream.read(&mut buf) {
Ok(size) => {
//Get List of names
let names: LinkedList<String> = serde_json::from_slice(&buf[..size])?;
for name in names.iter() {
if (*data).available.contains_key(&*name) {
//If file already exist just update Vec of IP
(*data)
.available
.get_mut(&*name)
.unwrap()
.push(stream.peer_addr().unwrap());
} else {
//In another case - adding file with first IP that share it
let mut v: Vec<SocketAddr> = Vec::new();
v.push(stream.peer_addr().unwrap());
(*data).available.insert(*name, v);
}
}
}
Err(_) => {
println!("An error occurred, {}", stream.peer_addr().unwrap());
}
}
}
Err(e) => {
println!("Error: {}", e);
}
}
}

Are you sure you want a LinkedList and not a Vec as output from your JSON parser? From the LinkedList docs:
It is almost always better to use Vec or VecDeque because array-based containers are generally faster, more memory efficient, and make better use of CPU cache.
To solve your problem, you should loop over names instead of names.iter(). This will make the list unusable after the for loop.
You will then have to remove the dereferences in your code, i.e. write &name instead of "&*name" and name instead of *name. However, you shouldn't have written &*name at all because the & and * in &*name are cancelling each other out.

Related

in Rust how can I dump the result of a panic! returned by join() if it is not a &'static str?

I have a Rust program where I spawn a number of threads and store the JoinHandles. When I later join the threads that panic!ed, I'm not sure how to retrieve the message that was passed to panic!
Recovering from `panic!` in another thread covers a simple case, but when I applied it to my code it turns out it doesn't work, so I have updated my example:
If I run the following program
fn main() {
let handle = std::thread::spawn(||panic!(format!("demo {}",1)));
match handle.join() {
Ok(_) => println!("OK"),
Err(b) => println!("Err {:?}", b.downcast_ref::<&'static str>())
}
}
(rust playground)
It prints Err None . I want to access the "demo" message.
Based on the comments, I was able to come up with a working solution (rust playground):
fn main() {
let handle = std::thread::spawn(|| {
panic!("malfunction {}", 7);
if true {
Err(14)
} else {
Ok("bacon".to_string())
}
});
match handle.join() {
Ok(msg) => println!("OK {:?}", msg),
Err(b) => {
let msg = if let Some(msg) = b.downcast_ref::<&'static str>() {
msg.to_string()
} else if let Some(msg) = b.downcast_ref::<String>() {
msg.clone()
} else {
format!("?{:?}", b)
};
println!("{}", msg);
}
}
}
which prints malfunction 7 like I want. While this toy example doesn't need all the branches, a more complex piece of code might have some panic!s that give &'static str and others that give String.

Filesystem watch in Rust

I'm trying to implement a filesystem watcher in Rust. I can receive events when filesystem objects have changed but determining what change was made has me stumped. I found code on the latest released version of the Notify package here that takes me almost the whole way there.
How can I extract the path and type out of the event? The event is an enumerated type, yet somehow when it's printed, I see all the info I want.
I am obviously missing something very fundamental.
use notify::{watcher, RecursiveMode, Watcher};
use std::sync::mpsc::channel;
use std::time::Duration;
fn main() {
let (tx, rx) = channel();
let mut watcher = watcher(tx, Duration::from_secs(10)).unwrap();
watcher
.watch("/tmp/path", RecursiveMode::Recursive)
.unwrap();
loop {
match rx.recv() {
Ok(event) => {
// **>> event.filename? event.type? how?
println!("{:?}", event);
}
Err(e) => println!("watch error: {:?}", e),
}
}
}
Using a debounced watcher, the event you get is of type DebouncedEvent. The enum variant specifies the type, and its contents is the path(s). To get it out of the event, you should match on the event for the desired event types:
match &event {
Read(path) => {
// do thing
}
Rename(src, dest) => {
// do other thing
}
_ => () // don't care about other types
}

What is the idiomatic way of using an if-let binding when matching a `Result` and still being able to capture the error?

fn lines_from_file<F>(filename: F) -> Result<io::Lines<BufReader<File>>, io::Error>
where
F: std::convert::AsRef<std::path::Path>,
{
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn main() {
let filename: &str = "input.pdl";
// This works fine
match lines_from_file(filename) {
Ok(lines) => {
for line in lines {
println!("{:?}", line);
},
}
Err(e) => println!("Error {:?}", e),
}
}
I'd like to use this instead:
if let lines = Ok(lines_from_file(filename)) {
for line in lines {
println!("{:?}", line);
}
} else {
println!("Error {:?}" /*what goes here?*/,)
}
But that gives an error:
| if let lines = Ok(lines_from_file(filename)) {
| ^^ cannot infer type for `E`
What is the idiomatic way of using an if-let binding when matching a Result and still being able to capture the error?
[...] using an if-let binding when matching a Result and still being able to capture the error?
This is fundamentally impossible with one if let. The if let construct's only purpose is to make life easier in the case where you only want to destructure one pattern. If you want to destructure both cases of a Result, you have to use match (or multiple if let or unwrap(), but this is not a good solution). Why you don't want to use match in the first place?
Regarding your compiler error: you added the Ok() on the wrong side:
if let Ok(lines) = lines_from_file(filename) { ... }
This is the correct way of using if let: the destructuring pattern to the left, the expression producing a value to the right.

Recovering from `panic!` in another thread

I know that in Rust there is no try/catch, and you can't throw a rolling save from the thread that is currently panicking.
I know you should not create and handle errors like this. This is just for example's sake.
However, I am wondering what the best way to recover from a panic is. This is what I have now:
use std::thread;
fn main() {
println!("Hello, world!");
let h = thread::spawn(|| {
thread::sleep_ms(1000);
panic!("boom");
});
let r = h.join();
match r {
Ok(r) => println!("All is well! {:?}", r),
Err(e) => println!("Got an error! {:?}", e)
}
println!("Exiting main!");
}
Is there a better way to handle errors from other threads? Is there a way to capture the message of the panic? This seems to only tell me that the error is of type Any. Thanks!
Putting aside "you should be using Result where possible," yes, this is basically how you catch a panic in Rust. Keep in mind that "recover" is perhaps not the best way of phrasing this in Rust. You don't really recover from panics in Rust, you isolate them, then detect them. There is no On Error Resume Next :P.
That said, there are two things to add to your example. First is how to get at the panic message. The key observation is that Any, in order to be used, must be explicitly downcast to the exact, concrete type it contains. In this case, since the panic message is a &'static str, you need to downcast to that.
The second thing is that there is a new API in nightly called catch_panic that lets you isolate a panic without having to start a thread. That said, it comes with the same restrictions as spawning a new thread: you cannot pass a non-'static reference across the isolation boundary. Note that this is an unstable addition; there are no guarantees about stability yet, and you'll need a nightly compiler to access it.
Here is an example which shows both of those. You can also run this on the Rust Playpen.
#![feature(catch_panic)]
use std::thread;
fn main() {
println!("Hello, world!");
let h = thread::spawn(|| {
thread::sleep_ms(500);
panic!("boom");
});
let r = h.join();
handle(r);
let r = thread::catch_panic(|| {
thread::sleep_ms(500);
panic!(String::from("boom again!"));
});
handle(r);
println!("Exiting main!");
}
fn handle(r: thread::Result<()>) {
match r {
Ok(r) => println!("All is well! {:?}", r),
Err(e) => {
if let Some(e) = e.downcast_ref::<&'static str>() {
println!("Got an error: {}", e);
} else {
println!("Got an unknown error: {:?}", e);
}
}
}
}

Dealing with a mutable counter variable in closure

I have written a program to visit directories which is based
on the example on this page.
When I compile it, the compile displays the following 'note':
previous borrow of file_counter occurs here due to use in closure;
How can I display file_counter's value?
Is there a better (ie, more functional-like) way to count displayed files, in this program,
perhaps a non-mutable variable and/or recursion?
Many thanks.
fn main() {
let mut file_counter = 0i;
let display_path_closure = |path: &Path| {
file_counter += 1;
println!("{}) path = {}", file_counter, path.display());
};
let path = Path::new("z:/abc");
let _ = match visit_dirs(&path, display_path_closure) {
Err(e) => println!("error: {}", e),
Ok(_) => println!("Counter: {}", file_counter)
};
}
fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> {
if dir.is_dir() {
let contents = try!(fs::readdir(dir));
for entry in contents.iter() {
if entry.is_dir() {
try!(visit_dirs(entry, |p| cb(p)));
} else {
cb(entry);
}
}
Ok(())
} else {
Err(io::standard_error(io::InvalidInput))
}
}
You can get around this by slight restructuring, putting the closure into an inner block:
fn main() {
let path = Path::new("z:/abc");
let mut file_counter = 0i;
let result = {
let display_path_closure = |path: &Path| {
file_counter += 1;
println!("{}) path = {}", file_counter, path.display());
};
visit_dirs(&path, display_path_closure)
};
let _ = match result {
Err(e) => println!("error: {}", e),
Ok(_) => println!("Counter: {}", file_counter)
};
}
As for why it happens, it is because closure captures all its environment by unique reference (mutable in your case), as if it is declared like this (pretending for a moment that closures capture their environment by value; in fact that's how unboxed closures work):
let mut file_counter = 0i;
let file_counter_ref = &mut file_counter;
// file_counter_ref is a plain pointer so it is copied into the closure,
// not taken by reference itself
let display_path_closure = |path: &Path| {
*file_counter_ref += 1;
println!("{}) path = {}", *file_counter_ref, path.display());
};
So file_counter_ref reference lasts to the end of the block in which closure is defined. In your case it is the whole main function starting from the closure declaration. I agree, this may be surprising and I certainly would also think that closure environment borrows die with the closure (e.g. when the closure is moved into the function and this function returns), but that's how things are now.
The situation with closures in Rust is currently unstable: unboxed closures have just been added to the language, so old boxed closures (like the one in this example) will soon go away; moreover, borrow checker is also being improved. These features may interact in complex ways, so maybe your original example will become possible soon :) (just a speculation, of course)

Resources