Skip to content

Commit

Permalink
more AsRef and TryFrom impls
Browse files Browse the repository at this point in the history
  • Loading branch information
sunshowers committed Mar 11, 2021
1 parent 4dd0cc7 commit 6fc9c1a
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 1 deletion.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- `TryFrom<PathBuf> for Utf8PathBuf` and `TryFrom<&Path> for &Utf8Path`, both of which return new error types ([#6]).
- `AsRef<Utf8Path>`, `AsRef<Path>`, `AsRef<str>` and `AsRef<OsStr>` impls for `Utf8Components`, `Utf8Component` and
`Iter`.

[#6]: https://github.com/withoutboats/camino/issues/6

## [1.0.2] - 2021-03-02

### Added
Expand Down
193 changes: 192 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
use std::{
borrow::{Borrow, Cow},
cmp::Ordering,
convert::Infallible,
convert::{Infallible, TryFrom},
error,
ffi::{OsStr, OsString},
fmt, fs,
hash::{Hash, Hasher},
Expand Down Expand Up @@ -123,6 +124,9 @@ impl Utf8PathBuf {
///
/// Errors with the original `PathBuf` if it is not valid UTF-8.
///
/// For a version that returns a type that implements [`std::error::Error`], use the
/// `TryFrom<PathBuf>` impl.
///
/// # Examples
///
/// ```
Expand Down Expand Up @@ -1310,6 +1314,30 @@ impl<'a> fmt::Debug for Utf8Components<'a> {
}
}

impl AsRef<Utf8Path> for Utf8Components<'_> {
fn as_ref(&self) -> &Utf8Path {
self.as_path()
}
}

impl AsRef<Path> for Utf8Components<'_> {
fn as_ref(&self) -> &Path {
self.as_path().as_ref()
}
}

impl AsRef<str> for Utf8Components<'_> {
fn as_ref(&self) -> &str {
self.as_path().as_ref()
}
}

impl AsRef<OsStr> for Utf8Components<'_> {
fn as_ref(&self) -> &OsStr {
self.as_path().as_os_str()
}
}

/// An iterator over the [`Utf8Component`]s of a [`Utf8Path`], as [`str`] slices.
///
/// This `struct` is created by the [`iter`] method on [`Utf8Path`].
Expand Down Expand Up @@ -1368,6 +1396,12 @@ impl AsRef<Path> for Iter<'_> {
}
}

impl AsRef<str> for Iter<'_> {
fn as_ref(&self) -> &str {
self.as_path().as_ref()
}
}

impl AsRef<OsStr> for Iter<'_> {
fn as_ref(&self) -> &OsStr {
self.as_path().as_os_str()
Expand Down Expand Up @@ -1502,6 +1536,30 @@ impl<'a> fmt::Display for Utf8Component<'a> {
}
}

impl AsRef<Utf8Path> for Utf8Component<'_> {
fn as_ref(&self) -> &Utf8Path {
self.as_str().as_ref()
}
}

impl AsRef<Path> for Utf8Component<'_> {
fn as_ref(&self) -> &Path {
self.as_os_str().as_ref()
}
}

impl AsRef<str> for Utf8Component<'_> {
fn as_ref(&self) -> &str {
self.as_str()
}
}

impl AsRef<OsStr> for Utf8Component<'_> {
fn as_ref(&self) -> &OsStr {
self.as_os_str()
}
}

/// Windows path prefixes, e.g., `C:` or `\\server\share`.
///
/// Windows uses a variety of path prefix styles, including references to drive
Expand Down Expand Up @@ -1876,6 +1934,139 @@ impl<'a> From<Utf8PathBuf> for Cow<'a, Path> {
}
}

// ---
// TryFrom impls
// ---

impl TryFrom<PathBuf> for Utf8PathBuf {
type Error = FromPathBufError;

fn try_from(path: PathBuf) -> Result<Utf8PathBuf, Self::Error> {
Utf8PathBuf::from_path_buf(path).map_err(|path| FromPathBufError {
path,
error: FromPathError(()),
})
}
}

impl<'a> TryFrom<&'a Path> for &'a Utf8Path {
type Error = FromPathError;

fn try_from(path: &'a Path) -> Result<&'a Utf8Path, Self::Error> {
Utf8Path::from_path(path).ok_or(FromPathError(()))
}
}

/// A possible error value while converting a [`PathBuf`] to a [`Utf8PathBuf`].
///
/// Produced by the `TryFrom<PathBuf>` implementation for [`Utf8PathBuf`].
///
/// # Examples
///
/// ```
/// use camino::{Utf8PathBuf, FromPathBufError};
/// use std::convert::{TryFrom, TryInto};
/// use std::ffi::OsStr;
/// # #[cfg(unix)]
/// use std::os::unix::ffi::OsStrExt;
/// use std::path::PathBuf;
///
/// let unicode_path = PathBuf::from("/valid/unicode");
/// let utf8_path_buf: Utf8PathBuf = unicode_path.try_into().expect("valid Unicode path succeeded");
///
/// // Paths on Unix can be non-UTF-8.
/// # #[cfg(unix)]
/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
/// # #[cfg(unix)]
/// let non_unicode_path = PathBuf::from(non_unicode_str);
/// # #[cfg(unix)]
/// let err: FromPathBufError = Utf8PathBuf::try_from(non_unicode_path.clone())
/// .expect_err("non-Unicode path failed");
/// # #[cfg(unix)]
/// assert_eq!(err.as_path(), &non_unicode_path);
/// # #[cfg(unix)]
/// assert_eq!(err.into_path_buf(), non_unicode_path);
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FromPathBufError {
path: PathBuf,
error: FromPathError,
}

impl FromPathBufError {
/// Returns the [`Path`] slice that was attempted to be converted to [`Utf8PathBuf`].
pub fn as_path(&self) -> &Path {
&self.path
}

/// Returns the [`PathBuf`] that was attempted to be converted to [`Utf8PathBuf`].
pub fn into_path_buf(self) -> PathBuf {
self.path
}

/// Fetch a [`FromPathError`] for more about the conversion failure.
///
/// At the moment this struct does not contain any additional information, but is provided for
/// completeness.
pub fn from_path_error(&self) -> FromPathError {
self.error
}
}

impl fmt::Display for FromPathBufError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PathBuf contains invalid UTF-8: {}", self.path.display())
}
}

impl error::Error for FromPathBufError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(&self.error)
}
}

/// A possible error value while converting a [`Path`] to a [`Utf8Path`].
///
/// Produced by the `TryFrom<&Path>` implementation for [`&Utf8Path`](Utf8Path).
///
///
/// # Examples
///
/// ```
/// use camino::{Utf8Path, FromPathError};
/// use std::convert::{TryFrom, TryInto};
/// use std::ffi::OsStr;
/// # #[cfg(unix)]
/// use std::os::unix::ffi::OsStrExt;
/// use std::path::Path;
///
/// let unicode_path = Path::new("/valid/unicode");
/// let utf8_path: &Utf8Path = unicode_path.try_into().expect("valid Unicode path succeeded");
///
/// // Paths on Unix can be non-UTF-8.
/// # #[cfg(unix)]
/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
/// # #[cfg(unix)]
/// let non_unicode_path = Path::new(non_unicode_str);
/// # #[cfg(unix)]
/// let err: FromPathError = <&Utf8Path>::try_from(non_unicode_path)
/// .expect_err("non-Unicode path failed");
/// ```
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FromPathError(());

impl fmt::Display for FromPathError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Path contains invalid UTF-8")
}
}

impl error::Error for FromPathError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}

// ---
// AsRef impls
// ---
Expand Down

0 comments on commit 6fc9c1a

Please sign in to comment.