Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement absolute_utf8 #95

Merged
merged 1 commit into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading