Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::{borrow::Borrow, io, path::PathBuf};
/// A representation of a path as a wide character sequence that can
/// contain unpaired surrogates.
///
/// A [`WidePathBuf`] can be created from an [`nsstring::nsAString`],
/// and copied into an `[nsstring::nsString]`, without re-encoding.
/// Unlike `ns{A}String`, [`WidePathBuf`] implements the built-in
/// comparison and hashing traits, so it can be used as a key in
/// a `HashMap` or a `BTreeMap`.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
pub struct WidePathBuf(Vec<u16>);
impl WidePathBuf {
/// Creates a [`WidePathBuf`] from a wide character sequence.
pub fn new(wide: impl AsRef<[u16]>) -> Self {
Self(wide.as_ref().into())
}
/// Returns the wide character sequence in this [`WidePathBuf`].
pub fn as_wide(&self) -> &[u16] {
&self.0
}
/// Returns the canonical, absolute form of a path, normalizing
/// `/./` and `/../` components, symbolic links, and
/// {drive, directory}-relative paths.
///
/// ### Notes
///
/// This function calls [`std::fs::canonicalize`] on Windows, and
/// reimplements [`std::fs::canonicalize`] on Unix platforms
/// to work around an [allocator crash][1].
///
pub fn canonicalize(&self) -> io::Result<PathBuf> {
#[cfg(windows)]
{
use std::{ffi::OsString, os::windows::prelude::*};
std::fs::canonicalize(OsString::from_wide(&*self.0))
}
#[cfg(unix)]
{
use std::{
ffi::{CStr, CString, OsString},
os::unix::prelude::*,
};
let path = CString::new(String::from_utf16(&*self.0).map_err(io::Error::other)?)?;
let mut bytes = [0 as libc::c_char; libc::PATH_MAX as usize];
let ptr = unsafe { libc::realpath(path.as_ptr(), bytes[..].as_mut_ptr()) };
if ptr.is_null() {
return Err(io::Error::last_os_error());
}
Ok(OsString::from_vec(unsafe { CStr::from_ptr(ptr) }.to_bytes().into()).into())
}
#[cfg(all(not(unix), not(windows)))]
compile_error!("`WidePathBuf::canonicalize` requires Windows or Unix")
}
}
// Convenience implementation for comparing a [`WidePathBuf`] to a Rust
// `String` or `str`.
impl<T> PartialEq<T> for WidePathBuf
where
T: Borrow<str>,
{
fn eq(&self, other: &T) -> bool {
other
.borrow()
.encode_utf16()
.eq(self.as_wide().iter().copied())
}
}