'How to get a Path variable that implements P: AsRef<Path> + ToString interface in Rust?

I want to use some function provided by a someone on github: https://docs.rs/escposify/latest/escposify/device/struct.File.html#method.from_path But as I read the API documentation, I came accross a problem with this function. It states that it takes something that implements AsRef <Path> and also ToString.

pub fn from_path<P: AsRef<Path> + ToString>(path: P) -> File<File>

Here's my code:

let path = Path::new("//192.168.100.8/Receipt Printer").to_string_lossy();
let file = File::from_path(path);
let mut printer = Printer::new(file, None, None);

it throws an error:

error: the trait bound `Cow<'_, str>: AsRef<Path>` is not satisfied
label: required by a bound introduced by this call

note: required by a bound in `escposify::device::File::<W>::from_path`
label: required by a bound introduced by this call

Here's the implementation from the source code that I could get:

pub fn from_path<P: AsRef<path::Path> + ToString>(path: P) -> File<fs::File> {
    let fobj = fs::OpenOptions::new()
        .write(true)
        .create(true)
        .open(&path)
        .unwrap();
    File { fobj }
}

How should I put my filepath ("//192.168.100.8/Receipt Printer") in this case ?



Solution 1:[1]

You should have simply used Path directly, without to_string_lossy()… at least if it weren’t for the fact that the library’s trait bounds are wrong.

pub fn from_path<P: AsRef<path::Path> + ToString>(path: P) -> File<fs::File> {
    let fobj = fs::OpenOptions::new()
        .write(true)
        .create(true)
        .open(&path)
        .unwrap();
    File { fobj }
}

The only line above that happens to be using path is the .open line, invoking OpenOptions::open, which only requires AsRef<Path>. The ToString trait is not used anywhere in that method, but the fact that it appears in the generic bound precludes passing an actual Path to from_path, since Path does not implement ToString, as it cannot be always losslessly converted to UTF-8.

Path::to_string_lossy should not be used other than to label files in user interfaces for informational purposes. It should never be used for paths which you may actually need to access later.

Fortunately, escposify also offers a more generic File::from trait method, which allows you to open a file yourself and pass it to the library:

let path = Path::new("//192.168.100.8/Receipt Printer");
let fobj = std::fs::OpenOptions::new()
    .write(true)
    .create(true)
    .open(&path)?;
let file = File::from(fobj);
let mut printer = Printer::new(file, None, None);

You can also use the string literal directly, i.e. pass &str like @piojo’s answer suggests; for toy programs that are fine using a hardcoded path, this should be enough.

Solution 2:[2]

&str implements both AsRef<Path> and ToString, so you should be able to let path = "//192.168.100.8/Receipt Printer"; and use that directly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 piojo