diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ae13275e4b35d..378a53585af0e 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -631,8 +631,27 @@ impl OsStr { s.as_ref() } + /// Creates a new [`OsStr`] from a [`str`]. + /// + /// This method supports const expressions. However, if you don't need const, + /// you should probably use the [`OsStr::new`] method instead. + /// + /// # Examples + /// + /// ``` + /// #![feature(const_path)] + /// use std::ffi::OsStr; + /// + /// const OS_STR: &OsStr = OsStr::from_str("foo"); + /// ``` + #[inline] + #[unstable(feature = "const_path", reason = "TBD", issue = "none")] + pub const fn from_str(s: &str) -> &OsStr { + Self::from_inner(Slice::from_str(s)) + } + #[inline] - fn from_inner(inner: &Slice) -> &OsStr { + const fn from_inner(inner: &Slice) -> &OsStr { // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } @@ -1263,7 +1282,7 @@ impl AsRef for OsString { impl AsRef for str { #[inline] fn as_ref(&self) -> &OsStr { - OsStr::from_inner(Slice::from_str(self)) + OsStr::from_str(self) } } diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs index 283f2b577e896..6b00ae98a3bb9 100644 --- a/library/std/src/ffi/os_str/tests.rs +++ b/library/std/src/ffi/os_str/tests.rs @@ -163,3 +163,10 @@ fn into_rc() { assert_eq!(&*rc2, os_str); assert_eq!(&*arc2, os_str); } + +#[test] +pub fn test_const() { + const STR: &str = "/foo/bar"; + const OS_STR: &OsStr = OsStr::from_str(STR); + assert_eq!(OS_STR, OsStr::new(STR)); +} diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 36d6469c02d31..9a8fcb8828669 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1973,7 +1973,27 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new + ?Sized>(s: &S) -> &Path { - unsafe { &*(s.as_ref() as *const OsStr as *const Path) } + Self::from_os_str(s.as_ref()) + } + + /// Creates a new [`Path`] from an [`OsStr`]. + /// + /// This method supports const expressions. However, if you don't need const, + /// you should probably use the [`Path::new`] method instead. + /// + /// # Examples + /// + /// ``` + /// #![feature(const_path)] + /// use std::ffi::OsStr; + /// use std::path::Path; + /// + /// const PATH: &Path = Path::from_os_str(OsStr::from_str("/foo/bar")); + /// ``` + #[inline] + #[unstable(feature = "const_path", reason = "TBD", issue = "none")] + pub const fn from_os_str(s: &OsStr) -> &Path { + unsafe { &*(s as *const OsStr as *const Path) } } /// Yields the underlying [`OsStr`] slice. diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 351cf698810f1..5140e0f932fc6 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1701,6 +1701,13 @@ fn test_ord() { ord!(Equal, "foo/bar", "foo/bar//"); } +#[test] +pub fn test_const() { + const STR: &str = "/foo/bar"; + const PATH: &Path = Path::from_os_str(OsStr::from_str(STR)); + assert_eq!(PATH, Path::new(STR)); +} + #[test] #[cfg(unix)] fn test_unix_absolute() { diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs index ccbc182240cf3..b56c53f802108 100644 --- a/library/std/src/sys/unix/os_str.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -186,12 +186,12 @@ impl Buf { impl Slice { #[inline] - fn from_u8_slice(s: &[u8]) -> &Slice { + const fn from_u8_slice(s: &[u8]) -> &Slice { unsafe { mem::transmute(s) } } #[inline] - pub fn from_str(s: &str) -> &Slice { + pub const fn from_str(s: &str) -> &Slice { Slice::from_u8_slice(s.as_bytes()) } diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 11883f15022f6..0f6f63f0bd4de 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -151,7 +151,7 @@ impl Buf { impl Slice { #[inline] - pub fn from_str(s: &str) -> &Slice { + pub const fn from_str(s: &str) -> &Slice { unsafe { mem::transmute(Wtf8::from_str(s)) } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 57fa4989358a4..bd4312063f37b 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -507,7 +507,7 @@ impl Wtf8 { /// /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] - pub fn from_str(value: &str) -> &Wtf8 { + pub const fn from_str(value: &str) -> &Wtf8 { unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } } @@ -516,7 +516,7 @@ impl Wtf8 { /// Since the byte slice is not checked for valid WTF-8, this functions is /// marked unsafe. #[inline] - unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + const unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { mem::transmute(value) }