@@ -85,7 +85,7 @@ use crate::str::FromStr;
8585use crate :: sync:: Arc ;
8686
8787use crate :: ffi:: { OsStr , OsString } ;
88-
88+ use crate :: sys ;
8989use crate :: sys:: path:: { is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR } ;
9090
9191////////////////////////////////////////////////////////////////////////////////
@@ -3172,3 +3172,79 @@ impl Error for StripPrefixError {
31723172 "prefix not found"
31733173 }
31743174}
3175+
3176+ /// Makes the path absolute without accessing the filesystem.
3177+ ///
3178+ /// If the path is relative, the current directory is used as the base directory.
3179+ /// All intermediate components will be resolved according to platforms-specific
3180+ /// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not
3181+ /// resolve symlinks and may succeed even if the path does not exist.
3182+ ///
3183+ /// If the `path` is empty or getting the
3184+ /// [current directory][crate::env::current_dir] fails then an error will be
3185+ /// returned.
3186+ ///
3187+ /// # Examples
3188+ ///
3189+ /// ## Posix paths
3190+ ///
3191+ /// ```
3192+ /// #![feature(absolute_path)]
3193+ /// # #[cfg(unix)]
3194+ /// fn main() -> std::io::Result<()> {
3195+ /// use std::path::{self, Path};
3196+ ///
3197+ /// // Relative to absolute
3198+ /// let absolute = path::absolute("foo/./bar")?;
3199+ /// assert!(absolute.ends_with("foo/bar"));
3200+ ///
3201+ /// // Absolute to absolute
3202+ /// let absolute = path::absolute("/foo//test/.././bar.rs")?;
3203+ /// assert_eq!(absolute, Path::new("/foo/test/../bar.rs"));
3204+ /// Ok(())
3205+ /// }
3206+ /// # #[cfg(not(unix))]
3207+ /// # fn main() {}
3208+ /// ```
3209+ ///
3210+ /// The path is resolved using [POSIX semantics][posix-semantics] except that
3211+ /// it stops short of resolving symlinks. This means it will keep `..`
3212+ /// components and trailing slashes.
3213+ ///
3214+ /// ## Windows paths
3215+ ///
3216+ /// ```
3217+ /// #![feature(absolute_path)]
3218+ /// # #[cfg(windows)]
3219+ /// fn main() -> std::io::Result<()> {
3220+ /// use std::path::{self, Path};
3221+ ///
3222+ /// // Relative to absolute
3223+ /// let absolute = path::absolute("foo/./bar")?;
3224+ /// assert!(absolute.ends_with(r"foo\bar"));
3225+ ///
3226+ /// // Absolute to absolute
3227+ /// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?;
3228+ ///
3229+ /// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs"));
3230+ /// Ok(())
3231+ /// }
3232+ /// # #[cfg(not(windows))]
3233+ /// # fn main() {}
3234+ /// ```
3235+ ///
3236+ /// For verbatim paths this will simply return the path as given. For other
3237+ /// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
3238+ /// This may change in the future.
3239+ ///
3240+ /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
3241+ /// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
3242+ #[ unstable( feature = "absolute_path" , issue = "92750" ) ]
3243+ pub fn absolute < P : AsRef < Path > > ( path : P ) -> io:: Result < PathBuf > {
3244+ let path = path. as_ref ( ) ;
3245+ if path. as_os_str ( ) . is_empty ( ) {
3246+ Err ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "cannot make an empty path absolute" , ) )
3247+ } else {
3248+ sys:: path:: absolute ( path)
3249+ }
3250+ }
0 commit comments