From f60155a377cbd93cfe881050c91486828b5cd22a Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sat, 15 Jan 2022 10:18:40 +0000 Subject: [PATCH 1/4] feat: allow const path creation --- library/std/src/ffi/os_str.rs | 11 +++++++++-- library/std/src/path.rs | 14 +++++++++++++- library/std/src/sys/unix/os_str.rs | 4 ++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 982ad1898788e..7ee7f750c9dce 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -629,8 +629,15 @@ impl OsStr { s.as_ref() } + /// Creates a new `OsStr` from a `str`. #[inline] - fn from_inner(inner: &Slice) -> &OsStr { + #[unstable(feature = "const_path", reason = "TBD", issue = "none")] + pub const fn from_str(s: &str) -> &OsStr { + Self::from_inner(Slice::from_str(s)) + } + + #[inline] + 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) } @@ -1249,7 +1256,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/path.rs b/library/std/src/path.rs index 7d401cff591c1..d7ae53929d07a 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1948,7 +1948,19 @@ 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 is a cost-free conversion. + /// + /// You should probably use the [`Path::new`] method instead, + /// however, this method supports const expressions + #[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/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()) } From 2f0c05ee941b9c46581096d00720d0ec3475c5f0 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sat, 15 Jan 2022 11:07:40 +0000 Subject: [PATCH 2/4] test: added tests for const-ness --- library/std/src/ffi/os_str.rs | 13 ++++++++++++- library/std/src/ffi/os_str/tests.rs | 7 +++++++ library/std/src/path.rs | 15 +++++++++++---- library/std/src/path/tests.rs | 7 +++++++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 7ee7f750c9dce..c426ff3ab3c2f 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -629,7 +629,18 @@ impl OsStr { s.as_ref() } - /// Creates a new `OsStr` from a `str`. + /// 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 + /// + /// ``` + /// 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 { 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 d7ae53929d07a..36b9af218a309 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1951,12 +1951,19 @@ impl Path { Self::from_os_str(s.as_ref()) } - /// Creates a new `Path` from an `OsStr`. + /// Creates a new [`Path`] from an [`OsStr`]. /// - /// This is a cost-free conversion. + /// This method supports const expressions. However, if you don't need const, + /// you should probably use the [`Path::new`] method instead. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// use std::path::Path; /// - /// You should probably use the [`Path::new`] method instead, - /// however, this method supports const expressions + /// 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 { diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 2bf499e1ab823..86803c43fb681 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1665,6 +1665,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)); +} + #[bench] fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { let prefix = "my/home"; From 7b4bdc0ba22a19cd5b73d801078fec554fa4a619 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sat, 15 Jan 2022 11:28:54 +0000 Subject: [PATCH 3/4] fix: windows --- library/std/src/sys/windows/os_str.rs | 2 +- library/std/src/sys_common/wtf8.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 78e92a3331a1c..10b3ada4f7d90 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -150,7 +150,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 7a6e6246357d1..85a34602774ef 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) } From 5bb397db37e2886d11a45a1e6e794d643c9f21b4 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sat, 15 Jan 2022 12:00:16 +0000 Subject: [PATCH 4/4] fix: doctests --- library/std/src/ffi/os_str.rs | 3 ++- library/std/src/path.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c426ff3ab3c2f..b4f3cb74eb5dc 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -637,9 +637,10 @@ impl OsStr { /// # Examples /// /// ``` + /// #![feature(const_path)] /// use std::ffi::OsStr; /// - /// const OS_STR: OsStr = OsStr::from_str("foo"); + /// const OS_STR: &OsStr = OsStr::from_str("foo"); /// ``` #[inline] #[unstable(feature = "const_path", reason = "TBD", issue = "none")] diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 36b9af218a309..6c74be9a61460 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1959,10 +1959,11 @@ impl Path { /// # Examples /// /// ``` + /// #![feature(const_path)] /// use std::ffi::OsStr; /// use std::path::Path; /// - /// const PATH: Path = Path::from_os_str(OsStr::from_str("/foo/bar")); + /// const PATH: &Path = Path::from_os_str(OsStr::from_str("/foo/bar")); /// ``` #[inline] #[unstable(feature = "const_path", reason = "TBD", issue = "none")]