6
\$\begingroup\$

As a Rust beginner, I would like to know how I could improve the following points considering the function below:

  • Handling Path and PathBuf types correctly;
  • Performance;
  • Rust writing style in general.

Here is the function, decorated with a full working example:

use std::env;
use std::path::{Path, PathBuf};

const RUSV_FILENAME: &str = ".rusv.json";

/**
 * Find a rusv file in the current or parent directories of the given directory.
 */
fn find_rusv_file(starting_directory: &Path) -> Option<PathBuf> {
    let mut directory = starting_directory;
    let rusv_filename = Path::new(&RUSV_FILENAME);

    loop {
        let filepath: PathBuf = [
            directory,
            rusv_filename
        ].iter().collect();

        if filepath.is_file() {
            return Some(filepath);
        }

        match directory.parent() {
            Some(parent) => directory = parent,
            None => return None,
        }
    }
}

fn main() -> std::io::Result<()> {
    let path = env::current_dir()?;

    match find_rusv_file(&path) {
        Some(filepath) => println!("Rusv file was found: {:?}", filepath),
        None => println!("No rusv file was found."),
    };

    Ok(())
}

My question is not about:

  • Creating a more generic function (e.g. by giving the filename as an argument);
  • Anything related to the main() function.
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Handling Path and PathBuf types correctly;

My concern is that you recreate PathBuf every time, I don't see the point to have a buffer if you don't use it.

Performance;

I think it's ok, you search one file in particular the time you take creating the string is cheap compare to system call. So I don't think read_dir is better on your case. This could be benchmarked.

Rust writing style in general.

You are using return, on your case maybe use break to make your function SESE (single entry single exit).

Path::new(&RUSV_FILENAME); the reference is not needed Path::new(RUSV_FILENAME);.

fn find_rusv_file(starting_directory: &Path) -> Option<PathBuf> {
    let mut path: PathBuf = starting_directory.into();
    let file = Path::new(RUSV_FILENAME);

    loop {
        path.push(file);

        if path.is_file() {
            break Some(path);
        }

        if !(path.pop() && path.pop()) { // remove file && remove parent
            break None;
        }
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.