-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ACP: PathLike
trait
#62
Comments
This was discussed at a recent libs-api meeting. There was general interest but it was felt like we should have the minimal surface area necessary for experimentation outside of std. To that end I'm thinking we just need a This still requires a trait to replace In summary, this is what I'm proposing: // std::path::NativePath
// An opaque type. Use methods in std::os::ffi::$PLATFORM::NativePathExt to create or unwrap a NativePath.
pub struct NativePath(_);
// std::os::ffi::windows::NativePathExt
// On Windows NativePath wraps a [u16],
pub trait NativePathExt: Sealed {
fn from_wide(wide: &[u16]) -> &NativePath;
fn as_wide(&self) -> &[u16];
}
// std::os::ffi::unix::NativePathExt
// On Unix NativePath wraps a CStr,
pub trait NativePathExt: Sealed {
fn from_cstr(cstr: &CStr) -> &NativePath;
fn as_cstr(&self) -> &CStr;
}
// std::path::AsPath
// Sealed trait that implements no methods itself.
pub trait AsPath: Sealed {}
impl<P: AsRef<Path>> AsPath for P {}
impl AsPath for &NativePath {} |
Public but unstable and unimplementable isn't so bad, users won't be able to use it in bounds so we can still rename it later. |
For sure, I just meant if a name appears publicly in stable |
shouldn't that be |
Hm, is that not already implied by |
no and no, but imho consistency with
ok, then i guess it's just opinion-based rather than a breaking change |
Haven't looked at this in detail, but it might be interesting to see if we can provide something similar to https://docs.rs/rustix/latest/rustix/path/trait.Arg.html or https://docs.rs/nix/latest/nix/trait.NixPath.html. Currently, std always has to either copy the path on the stack or allocate. That's bummed me out when I know I can produce a CStr that can be passed directly to the OS. |
Yes, that's the idea. Originally this was done through a trait the users could implement on their own type. This has now been simplified to a |
Awesome, that would be cool! |
Closing this as this was already discussed in an earlier libs-api meeting. Looking forward to the next steps. Edit: to clarify, what was proposed in this comment seems fine. ^^ |
PR is here: rust-lang/rust#108981 Sorry, it seems I forgot to link back to the ACP. |
Proposal
Problem statement
Currently all filesystem operations that act on paths have to go through
Path
. This then requires a conversion fromPath
to the platform path type before use. This conversion is exasperated when the user already has a native path type and, when calling stdlib filesystem functions, has to convert it toPath
only for it to be immediately converted back to the native form.Another issue Windows has is that
Path
(andOsStr
) are opaque. So if the user wants to do anything not provided by stdlib functions then they have to convert to another type and then back. Either astr
(which incurs a UTF-8 check and is potentially lossy) or by usingencode_wide
(which is more expensive and may require an allocation).Motivation, use-cases
For Windows in particular something like this conversion needs to be done a lot:
There are ways to mitigate the cost (e.g. using the stack for shorter paths instead of allocating) but it still must always be done one way or another.
If you already have a native path (e.g. from a
-sys
crate) then this essentially means round tripping throughPath
to use the standard library. It's roughly the equivalent of doing this, which ends up as a particularly expensive no-op:Solution sketches
I propose allowing users to provide their own path types. To facilitate this we would add a
PathLike
trait that can be used by functions to take anything that can be converted to a native path, without mandating how that happens. There would be a blanket implementation forAsRef<Path>
so that his doesn't break (n.b. would this need a crater run to confirm?).PathLike
would initially be an unstable trait but its name would instantly appear in stable method signatures. Therefore any bikeshedding of the trait name would need to happen before it's merged and the trait itself would need to be documented with that in mind (the pattern trait is in a similar position).I do not think the exact definition of
PathLike
needs to be finalized in this ACP (feel free to disagree!) but my aim would be to work towards something like this:I don't think we need to immediately decide what form
NativePath
should take for each platform. This could, for example, be a type alias incore::ffi
(which already has OS specific type aliases). Or a more complex solution would be to have an opaque struct with extension methods for each platform (perhaps better for documentation but a lot more indirection).Alternatives
I considered having a
ToPlatformStr
(or similar) as a replacement for bothAsRef<OsStr>
andAsRef<Path>
. However, we do currently make a distinction between aPath
and anOsStr
(even though they're really the same thing) so I decided to stick with that for now as I do think it will be useful for custom types. In the future we may also want to make finer distinction for otherOsStr
types. For example, environment variable keys orprocess::Command
application names. But I think I can avoid those questions for now.I also considered
Into<NativePath>
but I think using a dedicated trait is more versatile and also provides a better place to hang documentation on.Links and related work
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
The text was updated successfully, but these errors were encountered: