Skip to content

Commit

Permalink
implement absolute_utf8 (#95)
Browse files Browse the repository at this point in the history
Note that we take `AsRef<Path>`, not `AsRef<Utf8Path>`, for the reason
mentioned in the comment.

Closes #94.
  • Loading branch information
sunshowers authored Aug 18, 2024
1 parent 49c1ef6 commit 10491be
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 1 deletion.
8 changes: 7 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ fn main() {
println!("cargo:rustc-check-cfg=cfg(shrink_to)");
println!("cargo:rustc-check-cfg=cfg(try_reserve_2)");
println!("cargo:rustc-check-cfg=cfg(os_str_bytes)");
println!("cargo:rustc-check-cfg=cfg(absolute_path)");

let compiler = match rustc_version() {
Some(compiler) => compiler,
Expand Down Expand Up @@ -50,11 +51,16 @@ fn main() {
{
println!("cargo:rustc-cfg=path_buf_deref_mut");
}
// os_str_bytes was added in a 1.74 stable.
// os_str_bytes was added in 1.74.
if (compiler.minor >= 74 && compiler.channel == ReleaseChannel::Stable) || compiler.minor >= 75
{
println!("cargo:rustc-cfg=os_str_bytes");
}
// absolute_path was added in 1.79.
if (compiler.minor >= 79 && compiler.channel == ReleaseChannel::Stable) || compiler.minor >= 80
{
println!("cargo:rustc-cfg=absolute_path");
}

// Catch situations where the actual features aren't enabled. Currently, they're only shown with
// `-vv` output, but maybe that will be noticed.
Expand Down
85 changes: 85 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3064,6 +3064,91 @@ impl_cmp_os_str!(&'a Utf8Path, Cow<'b, OsStr>);
impl_cmp_os_str!(&'a Utf8Path, OsString);
// NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)

/// Makes the path absolute without accessing the filesystem, converting it to a [`Utf8PathBuf`].
///
/// If the path is relative, the current directory is used as the base directory. All intermediate
/// components will be resolved according to platform-specific rules, but unlike
/// [`canonicalize`][Utf8Path::canonicalize] or [`canonicalize_utf8`](Utf8Path::canonicalize_utf8),
/// this does not resolve symlinks and may succeed even if the path does not exist.
///
/// *Requires Rust 1.79 or newer.*
///
/// # Errors
///
/// Errors if:
///
/// * The path is empty.
/// * The [current directory][std::env::current_dir] cannot be determined.
/// * The path is not valid UTF-8.
///
/// # Examples
///
/// ## POSIX paths
///
/// ```
/// # #[cfg(unix)]
/// fn main() -> std::io::Result<()> {
/// use camino::Utf8Path;
///
/// // Relative to absolute
/// let absolute = camino::absolute_utf8("foo/./bar")?;
/// assert!(absolute.ends_with("foo/bar"));
///
/// // Absolute to absolute
/// let absolute = camino::absolute_utf8("/foo//test/.././bar.rs")?;
/// assert_eq!(absolute, Utf8Path::new("/foo/test/../bar.rs"));
/// Ok(())
/// }
/// # #[cfg(not(unix))]
/// # fn main() {}
/// ```
///
/// The path is resolved using [POSIX semantics][posix-semantics] except that it stops short of
/// resolving symlinks. This means it will keep `..` components and trailing slashes.
///
/// ## Windows paths
///
/// ```
/// # #[cfg(windows)]
/// fn main() -> std::io::Result<()> {
/// use camino::Utf8Path;
///
/// // Relative to absolute
/// let absolute = camino::absolute_utf8("foo/./bar")?;
/// assert!(absolute.ends_with(r"foo\bar"));
///
/// // Absolute to absolute
/// let absolute = camino::absolute_utf8(r"C:\foo//test\..\./bar.rs")?;
///
/// assert_eq!(absolute, Utf8Path::new(r"C:\foo\bar.rs"));
/// Ok(())
/// }
/// # #[cfg(not(windows))]
/// # fn main() {}
/// ```
///
/// For verbatim paths this will simply return the path as given. For other paths this is currently
/// equivalent to calling [`GetFullPathNameW`][windows-path].
///
/// Note that this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
/// [posix-semantics]:
/// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
/// [windows-path]:
/// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
#[cfg(absolute_path)]
pub fn absolute_utf8<P: AsRef<Path>>(path: P) -> io::Result<Utf8PathBuf> {
// Note that even if the passed in path is valid UTF-8, it is not guaranteed that the absolute
// path will be valid UTF-8. For example, the current directory may not be valid UTF-8.
//
// That's why we take `AsRef<Path>` instead of `AsRef<Utf8Path>` here -- we have to pay the cost
// of checking for valid UTF-8 anyway.
let path = path.as_ref();
#[allow(clippy::incompatible_msrv)]
Utf8PathBuf::try_from(std::path::absolute(path)?).map_err(|error| error.into_io_error())
}

// invariant: OsStr must be guaranteed to be utf8 data
#[inline]
unsafe fn str_assume_utf8(string: &OsStr) -> &str {
Expand Down

0 comments on commit 10491be

Please sign in to comment.