I'm confused seeing that str implements AsRef<Path>. Following the source code of the cited documentation, the implementation looks like this:
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<Path> for str {
#[inline]
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
Path::new takes an impl AsRef<OsStr> + ?Sized as argument. So apparently str implements AsRef<OsStr>. But isn't OsStr dependent on the operating system? How can I cheaply (and without allocation) convert a UTF-8 string to a UTF-16 string, for example?
Implementation of AsRef<OsStr> for str looks as follows:
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for str {
#[inline]
fn as_ref(&self) -> &OsStr {
OsStr::from_inner(Slice::from_str(self))
}
}
And then I found elsewhere in the source:
#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")]
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
// `OsStr::from_inner` current implementation relies
// on `OsStr` being layout-compatible with `Slice`.
// When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`.
// Anyway, `OsStr` representation and layout are considered implementation details, are
// not documented and must not be relied upon.
pub struct OsStr {
inner: Slice,
}
Does that mean that current OsStr is just a str internally? But what if that changes? Wouldn't then impl AsRef<OsStr> for str (and thus impl AsRef<Path> for str) need to be removed (which isn't possible because of backwards compatibility?).
But likely I'm just missing some understanding on the internal details. Perhaps someone can explain to me how this works.
Under Unix, we have:
#[repr(transparent)]
pub struct Slice {
pub inner: [u8],
}
And under Windows:
pub struct Slice {
pub inner: Wtf8,
}
WTF!?
Also #repr[transparent)] seems to be missing here?
To my current understanding, OsStr isn't UTF-16, but it is (internally) WTF-8 on Windows, allowing to encode unpaired surrogates in addition to the unicode codepoints. Thus, a transformation from UTF-8 to WTF-8 can be done cheaply, right?
However, I still think the #repr[transparent)] is missing, right?
Also, this doesn't concur with OsStr's documentation:
This type represents a borrowed reference to a string in the operating system’s preferred representation.
This isn't (like the documentation suggests) about representation but it's about an OsStr being able to contain data that isn't valid Unicode.
And due to the implementation of AsRef<OsStr> for str, I believe it also can't be made to use arbitrary representation formats in the future. It is "tied" to how str works, even if the operating system "prefers" something else.