diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9026606987e16..0b2b5f7e58f46 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -93,7 +93,7 @@ use crate::ops::{self, Deref}; use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; -use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; +use crate::sys::path::{HAS_PREFIXES, is_sep_byte, is_verbatim_sep, parse_prefix}; use crate::{cmp, fmt, fs, io, sys}; //////////////////////////////////////////////////////////////////////////////// @@ -266,22 +266,33 @@ impl<'a> Prefix<'a> { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub fn is_separator(c: char) -> bool { +#[rustc_const_unstable(feature = "const_path_separators", issue = "153106")] +pub const fn is_separator(c: char) -> bool { c.is_ascii() && is_sep_byte(c as u8) } -/// The primary separator of path components for the current platform. -/// -/// For example, `/` on Unix and `\` on Windows. +/// All path separators recognized on the current platform, represented as [`char`]s; for example, +/// this is `&['/'][..]` on Unix and `&['\\', '/'][..]` on Windows. The [primary +/// separator](MAIN_SEPARATOR) is always element 0 of the slice. +#[unstable(feature = "const_path_separators", issue = "153106")] +pub const SEPARATORS: &[char] = crate::sys::path::SEPARATORS; + +/// All path separators recognized on the current platform, represented as [`&str`]s; for example, +/// this is `&["/"][..]` on Unix and `&["\\", "/"][..]` on Windows. The [primary +/// separator](MAIN_SEPARATOR_STR) is always element 0 of the slice. +#[unstable(feature = "const_path_separators", issue = "153106")] +pub const SEPARATORS_STR: &[&str] = crate::sys::path::SEPARATORS_STR; + +/// The primary separator of path components for the current platform, represented as a [`char`]; +/// for example, this is `'/'` on Unix and `'\\'` on Windows. #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "path_main_separator")] -pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP; +pub const MAIN_SEPARATOR: char = SEPARATORS[0]; -/// The primary separator of path components for the current platform. -/// -/// For example, `/` on Unix and `\` on Windows. +/// The primary separator of path components for the current platform, represented as a [`&str`]; +/// for example, this is `"/"` on Unix and `"\\"` on Windows. #[stable(feature = "main_separator_str", since = "1.68.0")] -pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR; +pub const MAIN_SEPARATOR_STR: &str = SEPARATORS_STR[0]; //////////////////////////////////////////////////////////////////////////////// // Misc helpers @@ -562,7 +573,7 @@ impl<'a> Component<'a> { pub fn as_os_str(self) -> &'a OsStr { match self { Component::Prefix(p) => p.as_os_str(), - Component::RootDir => OsStr::new(MAIN_SEP_STR), + Component::RootDir => OsStr::new(MAIN_SEPARATOR_STR), Component::CurDir => OsStr::new("."), Component::ParentDir => OsStr::new(".."), Component::Normal(path) => path, @@ -1379,7 +1390,7 @@ impl PathBuf { for c in buf { if need_sep && c != Component::RootDir { - res.push(MAIN_SEP_STR); + res.push(MAIN_SEPARATOR_STR); } res.push(c.as_os_str()); @@ -1402,7 +1413,7 @@ impl PathBuf { // `path` is a pure relative path } else if need_sep { - self.inner.push(MAIN_SEP_STR); + self.inner.push(MAIN_SEPARATOR_STR); } self.inner.push(path); diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs index 75f0de6beaeb5..494dd91f23140 100644 --- a/library/std/src/sys/path/cygwin.rs +++ b/library/std/src/sys/path/cygwin.rs @@ -5,25 +5,20 @@ use crate::sys::cvt; use crate::sys::helpers::run_path_with_cstr; use crate::{io, ptr}; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' -} +path_separator_bytes!(b'/', b'\\'); /// Cygwin always prefers `/` over `\`, and it always converts all `/` to `\` /// internally when calling Win32 APIs. Therefore, the server component of path /// `\\?\UNC\localhost/share` is `localhost/share` on Win32, but `localhost` /// on Cygwin. #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' || b == b'\\' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub use super::windows_prefix::parse_prefix; pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; unsafe extern "C" { // Doc: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs index 254683bc83f91..bbb7577e186ae 100644 --- a/library/std/src/sys/path/mod.rs +++ b/library/std/src/sys/path/mod.rs @@ -1,3 +1,22 @@ +// There's a lot of necessary redundancy in separator definition. Consolidated into a macro to +// prevent transcription errors. +macro_rules! path_separator_bytes { + ($($sep:literal),+) => ( + pub const SEPARATORS: &[char] = &[$($sep as char,)+]; + pub const SEPARATORS_STR: &[&str] = &[$( + match str::from_utf8(&[$sep]) { + Ok(s) => s, + Err(_) => panic!("path_separator_bytes must be ASCII bytes"), + } + ),+]; + + #[inline] + pub const fn is_sep_byte(b: u8) -> bool { + $(b == $sep) ||+ + } + ) +} + cfg_select! { target_os = "windows" => { mod windows; diff --git a/library/std/src/sys/path/sgx.rs b/library/std/src/sys/path/sgx.rs index dca61f3ea145d..9b7ab30a9c652 100644 --- a/library/std/src/sys/path/sgx.rs +++ b/library/std/src/sys/path/sgx.rs @@ -3,14 +3,11 @@ use crate::io; use crate::path::{Path, PathBuf, Prefix}; use crate::sys::unsupported; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} +path_separator_bytes!(b'/'); #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub fn parse_prefix(_: &OsStr) -> Option> { @@ -18,8 +15,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = false; -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; pub(crate) fn absolute(_path: &Path) -> io::Result { unsupported() diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs index 84d634af93cf1..8c911ee5f9c53 100644 --- a/library/std/src/sys/path/uefi.rs +++ b/library/std/src/sys/path/uefi.rs @@ -5,17 +5,14 @@ use crate::path::{Path, PathBuf, Prefix}; use crate::sys::pal::helpers; use crate::sys::unsupported_err; +path_separator_bytes!(b'\\'); + const FORWARD_SLASH: u8 = b'/'; const COLON: u8 = b':'; #[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'\\' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub fn parse_prefix(_: &OsStr) -> Option> { @@ -23,8 +20,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; /// UEFI paths can be of 4 types: /// diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs index 611d250db4050..b49c39a9253fa 100644 --- a/library/std/src/sys/path/unix.rs +++ b/library/std/src/sys/path/unix.rs @@ -2,14 +2,11 @@ use crate::ffi::OsStr; use crate::path::{Path, PathBuf, Prefix}; use crate::{env, io}; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} +path_separator_bytes!(b'/'); #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } #[inline] @@ -18,8 +15,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = false; -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; /// Make a POSIX path absolute without changing its semantics. pub(crate) fn absolute(path: &Path) -> io::Result { diff --git a/library/std/src/sys/path/unsupported_backslash.rs b/library/std/src/sys/path/unsupported_backslash.rs index 8ed1fdc36e23f..ce1851e938395 100644 --- a/library/std/src/sys/path/unsupported_backslash.rs +++ b/library/std/src/sys/path/unsupported_backslash.rs @@ -4,14 +4,11 @@ use crate::io; use crate::path::{Path, PathBuf, Prefix}; use crate::sys::unsupported; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'\\' -} +path_separator_bytes!(b'\\'); #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub fn parse_prefix(_: &OsStr) -> Option> { @@ -19,8 +16,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; pub(crate) fn absolute(_path: &Path) -> io::Result { unsupported() diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 509b13b6ae812..1c7bf50d1907f 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -9,9 +9,9 @@ mod tests; pub use super::windows_prefix::parse_prefix; +path_separator_bytes!(b'\\', b'/'); + pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; /// A null terminated wide string. #[repr(transparent)] @@ -48,12 +48,7 @@ pub fn with_native_path(path: &Path, f: &dyn Fn(&WCStr) -> io::Result) -> } #[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { +pub const fn is_verbatim_sep(b: u8) -> bool { b == b'\\' }