My first Rust project: the Ripasso password manager

Here is my first Rust project, http://github.com/cortex/ripasso, a password manager GUI compatible with https://www.passwordstore.org/. I would love to get some feedback on the code, since I feel I am not really sure what I am doing :slight_smile:.

1 Like

Congratulations!

You might want to run rustfmt to get uniform code formatting, and Clippy to nitpick about function naming style, etc.

Overall looks good!

One noob thing I've noticed is a reference to an owned type: &String. While it works, it's unnecessarily restrictive. For read-only strings in function arguments you'd generally use &str (this is analogous to using &[T] rather than &Vec<T>).

This is because String type represents the whole string, and has ability to modify and grow the string. But &String gives only a read-only access to it, so you can't use that ability.

OTOH &str is more universal. It's a read-only view of any string. It can be a view into the whole String, or a part of it, or a string literal.

1 Like

Thanks for the hints abut Strings and str, this was very confusing to me when starting!
Thanks for the tips about the linters! Some of my inconsistent naming is caused by the QML<->Rust interaction, because QML has special mapping rules for names.

I tried using rustfmt but the code looks very strange after I apply it, here is an example.

Before:

let passwords = Arc::new(Mutex::new(vec![]));
let p1 = passwords.clone();
thread::spawn(move || loop {
    match password_rx.recv() {
        Ok(p) => {
            println!("Recieved: {:?}", p.name);
            let mut passwords = p1.lock().unwrap();
            passwords.push(p);
        }
        Err(e) => {
            panic!("password reciever channel failed: {:?}", e);
        },
    }
});

After:

let passwords = Arc::new(Mutex::new(vec![]));
let p1 = passwords.clone();
thread::spawn(move || loop {
                  match password_rx.recv() {
                      Ok(p) => {
        println!("Recieved: {:?}", p.name);
        let mut passwords = p1.lock().unwrap();
        passwords.push(p);
    }
                      Err(e) => {
        panic!("password reciever channel failed: {:?}", e);
    }
                  }
              });

Am I doing something wrong that makes it behave like this?

This does look weird, right. This is how it should look like this:

let passwords = Arc::new(Mutex::new(vec![]));
let p1 = passwords.clone();
thread::spawn(move || loop {
                  match password_rx.recv() {
                      Ok(p) => {
                          println!("Recieved: {:?}", p.name);
                          let mut passwords = p1.lock().unwrap();
                          passwords.push(p);
                      }
                      Err(e) => {
                          panic!("password reciever channel failed: {:?}", e);
                      }
                  }
              });

(the indent may seem a bit weird even here, but this is because it's aligned with move keyword in this case)

Consider using cargo fmt command after installing rustfmt to reformat entire project, as opposed to directly calling rustfmt.