I was working with a library's function which accepts any values with a Display trait this is a problem because PathBuf wasn't implemented with Display trait.
This is my code:
//library: inquire
fn recurse_file(path: impl AsRef<Path>) -> std::io::Result<Vec<PathBuf>> {
let mut buf = vec![];
let entries = read_dir(path)?;
for entry in entries {
let entry = entry?;
buf.push(entry.path())
}
Ok(buf)
}
pub fn read_arg() -> String {
let option = recurse_file("./");
let answer: Result<String, InquireError> = Select::new("Select a folder or file", option).prompt();
match answer {
Ok(dir) => dir,
Err(_) => {
exit(1);
}
}
}
The compiler suggests using {:?} or .display() and to_string_lossy() which both didn't work. I tried to implement Display for PathBuf but the compiler said that PathBuf is not defined in the current crate
impl Display for PathBuf {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}", self.0)
}
}
EDIT: I tried to use struct to wrap Vec so I could implement Display for Vec. Interestingly, this method worked but return more errors at read_arg but I think this answered my question so I can close it.
code:
struct CustomPathBuf {
path: Vec<PathBuf>
}
impl Display for CustomPathBuf {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{:?}", self.path)
}
}
As the comments have pointed out, if you want to format a Path
, you generally want to use Path::display
. This also applies to PathBuf
as it can be implicitly converted to &Path
via Deref
.
let path = PathBuf::from("foo/bar.txt");
println!("{}", path.display());
When you want to implement Debug
or Display
on a type defined by different module, the general recommended approach is to create a wrapper type.
For example, lets say I wanted to implement Display
for Vec<PathBuf>
. I could do this by creating a wrapper like this.
// I use Vec<PathBuf> here to make this a bit easier to read/understand,
// but it is generally better to use a slice instead.
pub struct NumberedPathList<'a>(pub &'a Vec<PathBuf>);
impl Display for NumberedPathList<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for (index, path) in self.0.iter().enumerate() {
writeln!(f, "{}: {}", index, path.display())?;
}
Ok(())
}
}
To make it easier to use our wrapper type, I recommend also creating a trait to allow for easy conversion.
pub trait ToNumberedList {
fn display_numbered(&self) -> NumberedPathList<'_>;
}
impl ToNumberedList for Vec<PathBuf> {
fn display_numbered(&self) -> NumberedPathList<'_> {
NumberedPathList(self)
}
}
// Somewhere else in your code
let foo = vec![
PathBuf::from("/a/b/c/d.txt"),
PathBuf::from("/a/b/c/f.rs"),
PathBuf::from("/a/b/g.txt"),
];
println!("{}", foo.display_numbered());
// Output:
// 0: /a/b/c/d.txt
// 1: /a/b/c/f.rs
// 2: /a/b/g.txt