rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.85k stars 12.66k forks source link

`PrefixComponent` cannot be constructed in any way #83578

Open Boscop opened 3 years ago

Boscop commented 3 years ago

I need to pass a canonicalized path to cl.exe: https://github.com/google/autocxx/blob/78965991ba04e6c9383920e9c4275deaa808a7a5/demo/build.rs#L19

Path::canonicalize returns \\?\C:\foo\bar instead of C:\foo\bar, which cl.exe doesn't interpret correctly (it's as if I hadn't passed that include path). So I need to strip the prefix. It seems the way to do it, is like this:

let path = PathBuf::from("src")
    .canonicalize()
    .unwrap()
    .components()
    .map(|c| match c {
        Component::Prefix(p) => Component::Prefix(match p.kind() {
            Prefix::VerbatimDisk(p) => Prefix::Disk(p),
            Prefix::VerbatimUNC(a, b) => Prefix::UNC(a, b),
            p => p,
        }),
        c => c,
    })
    .collect::<PathBuf>();

But I need to map a PrefixComponent to a PrefixComponent, and there is no public constructor for it! https://doc.rust-lang.org/stable/std/path/struct.PrefixComponent.html

So this code doesn't work: image

Can you please add a constructor for it? And maybe also a method to canonicalize a Path without adding such a prefix?

dylni commented 3 years ago

I've worked a little with these structs, so I might be able to answer why they're designed this way.

But I need to map a PrefixComponent to a PrefixComponent, and there is no public constructor for it!

The issue is that libstd doesn't have any way to convert Prefix to Path. If you give Prefix::Disk, it doesn't know what path you want to use for that prefix. For example, Prefix::Disk always has a lowercase disk letter when you extract it from PrefixComponent. However, converting PrefixComponent to Path will always use the original case.

And maybe also a method to canonicalize a Path without adding such a prefix?

Removing \\?\ can be difficult for some paths on Windows, so the issue you're looking for is probably #59117. Although no solution exists in libstd, I created normpath, which was mentioned on that issue and might help.