Skip to content

Commit

Permalink
Refactor conversions to separate files related to conversions themsel…
Browse files Browse the repository at this point in the history
…ves (#40)

* Remove implementation of AsRef for utf8 native path and pathbuf

Removes the implementation of `AsRef<std::path::Path>` for both `Utf8NativePath` and `Utf8NativePathBuf` to avoid situations where code using native path aliases appears to compile on one platform and fails on another. Also removes associated `TryAsRef` and other implementations that leveraged these at compile-time.

```rust
// Compiles on Unix-like platforms, does not compile on Windows
fn foo(path: &UnixPath) -> _ {
    std::fs::exists(path)
}
```

It is instead recommended to use the new `PlatformPath` to ensure types are respected and work across operating system targets.

* Refactor convert file into the files related to the conversions

Moves all of the convert.rs contents to specific files versus bundling conversion logic into a singular file that becomes a spaghetti of imports and logic.

1. Conversions to/from `WindowsComponent` have been moved to the associated file.
2. Conversions to/from `UnixComponent` have been moved to the associated file.

* Fix linting errors
  • Loading branch information
chipsenkbeil authored Dec 1, 2024
1 parent e1d1443 commit 73e9da6
Show file tree
Hide file tree
Showing 27 changed files with 651 additions and 718 deletions.
5 changes: 5 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ mod errors;
mod non_utf8;
mod utf8;

/// Interface to try to perform a cheap reference-to-reference conversion.
pub trait TryAsRef<T: ?Sized> {
fn try_as_ref(&self) -> Option<&T>;
}

pub use errors::*;
pub use non_utf8::*;
pub use utf8::*;
4 changes: 2 additions & 2 deletions src/common/non_utf8/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ where
where
T: for<'enc> Encoding<'enc>;

impl<'a, T> fmt::Debug for DebugHelper<'a, T>
impl<T> fmt::Debug for DebugHelper<'_, T>
where
T: for<'enc> Encoding<'enc>,
{
Expand Down Expand Up @@ -164,4 +164,4 @@ where
}
}

impl<'a, T> FusedIterator for Ancestors<'a, T> where T: for<'enc> Encoding<'enc> {}
impl<T> FusedIterator for Ancestors<'_, T> where T: for<'enc> Encoding<'enc> {}
8 changes: 5 additions & 3 deletions src/common/non_utf8/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,13 @@ pub fn take(cnt: usize) -> impl FnMut(ParseInput) -> ParseResult<ParseInput> {
}

/// Parse multiple bytes, failing if they do not match `bytes` or there are not enough bytes
pub fn bytes<'a>(bytes: &[u8]) -> impl FnMut(ParseInput<'a>) -> ParseResult<&'a [u8]> + '_ {
move |input: ParseInput<'a>| {
pub fn bytes(bytes: &[u8]) -> impl FnMut(ParseInput) -> ParseResult<&[u8]> + '_ {
move |input: ParseInput| {
if input.is_empty() {
return Err("Empty input");
} else if input.len() < bytes.len() {
}

if input.len() < bytes.len() {
return Err("Not enough bytes");
}

Expand Down
60 changes: 57 additions & 3 deletions src/common/non_utf8/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use core::{cmp, fmt};

pub use display::Display;

use crate::no_std_compat::*;
use crate::{
use crate::common::{
Ancestors, CheckedPathError, Component, Components, Encoding, Iter, PathBuf, StripPrefixError,
};
use crate::no_std_compat::*;

/// A slice of a path (akin to [`str`]).
///
Expand Down Expand Up @@ -1231,7 +1231,7 @@ where
}
}

impl<'a, T> From<PathBuf<T>> for Cow<'a, Path<T>>
impl<T> From<PathBuf<T>> for Cow<'_, Path<T>>
where
T: for<'enc> Encoding<'enc>,
{
Expand Down Expand Up @@ -1489,3 +1489,57 @@ mod helpers {
}
}
}

#[cfg(any(
unix,
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "solid_asp3",
target_os = "hermit",
target_os = "wasi"
))]
#[cfg(feature = "std")]
mod std_conversions {
use std::ffi::{OsStr, OsString};
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
use std::os::fortanix_sgx as os;
#[cfg(target_os = "solid_asp3")]
use std::os::solid as os;
#[cfg(any(target_os = "hermit", unix))]
use std::os::unix as os;
#[cfg(target_os = "wasi")]
use std::os::wasi as os;

use os::ffi::OsStrExt;

use super::*;

impl<T> AsRef<Path<T>> for OsStr
where
T: for<'enc> Encoding<'enc>,
{
#[inline]
fn as_ref(&self) -> &Path<T> {
Path::new(self.as_bytes())
}
}

impl<T> AsRef<Path<T>> for OsString
where
T: for<'enc> Encoding<'enc>,
{
#[inline]
fn as_ref(&self) -> &Path<T> {
Path::new(self.as_bytes())
}
}

impl<T> AsRef<OsStr> for Path<T>
where
T: for<'enc> Encoding<'enc>,
{
#[inline]
fn as_ref(&self) -> &OsStr {
OsStrExt::from_bytes(self.as_bytes())
}
}
}
100 changes: 100 additions & 0 deletions src/common/non_utf8/pathbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,3 +686,103 @@ where
self.components().cmp(other.components())
}
}

#[cfg(feature = "std")]
impl<T> TryFrom<PathBuf<T>> for std::path::PathBuf
where
T: for<'enc> Encoding<'enc>,
{
type Error = PathBuf<T>;

/// Attempts to convert a [`PathBuf`] into a [`std::path::PathBuf`], returning a result
/// containing the new path when successful or the original path when failed
///
/// # Examples
///
/// ```
/// use std::convert::TryFrom;
/// use std::path::PathBuf;
/// use typed_path::UnixPathBuf;
///
/// let unix_path_buf = UnixPathBuf::from("/path/to/file.txt");
/// let std_path_buf: PathBuf = TryFrom::try_from(unix_path_buf).unwrap();
/// ```
fn try_from(path: PathBuf<T>) -> Result<Self, Self::Error> {
match std::str::from_utf8(path.as_bytes()) {
Ok(s) => Ok(std::path::PathBuf::from(s)),
Err(_) => Err(path),
}
}
}

#[cfg(feature = "std")]
impl<T> TryFrom<std::path::PathBuf> for PathBuf<T>
where
T: for<'enc> Encoding<'enc>,
{
type Error = std::path::PathBuf;

/// Attempts to convert a [`std::path::PathBuf`] into a [`PathBuf`], returning a result
/// containing the new path when successful or the original path when failed
///
/// # Examples
///
/// ```
/// use std::convert::TryFrom;
/// use std::path::PathBuf;
/// use typed_path::UnixPathBuf;
///
/// let std_path_buf = PathBuf::from("/path/to/file.txt");
/// let unix_path_buf: UnixPathBuf = TryFrom::try_from(std_path_buf).unwrap();
/// ```
fn try_from(path: std::path::PathBuf) -> Result<Self, Self::Error> {
match path.to_str() {
Some(s) => Ok(PathBuf::from(s)),
None => Err(path),
}
}
}

#[cfg(any(
unix,
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "solid_asp3",
target_os = "hermit",
target_os = "wasi"
))]
#[cfg(feature = "std")]
mod std_conversions {
use std::ffi::{OsStr, OsString};
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
use std::os::fortanix_sgx as os;
#[cfg(target_os = "solid_asp3")]
use std::os::solid as os;
#[cfg(any(target_os = "hermit", unix))]
use std::os::unix as os;
#[cfg(target_os = "wasi")]
use std::os::wasi as os;

use os::ffi::{OsStrExt, OsStringExt};

use super::*;

impl<T> From<PathBuf<T>> for OsString
where
T: for<'enc> Encoding<'enc>,
{
#[inline]
fn from(path_buf: PathBuf<T>) -> Self {
OsStringExt::from_vec(path_buf.into_vec())
}
}

impl<T> AsRef<OsStr> for PathBuf<T>
where
T: for<'enc> Encoding<'enc>,
{
#[inline]
fn as_ref(&self) -> &OsStr {
OsStrExt::from_bytes(self.as_bytes())
}
}
}
4 changes: 2 additions & 2 deletions src/common/utf8/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ where
where
T: for<'enc> Utf8Encoding<'enc>;

impl<'a, T> fmt::Debug for DebugHelper<'a, T>
impl<T> fmt::Debug for DebugHelper<'_, T>
where
T: for<'enc> Utf8Encoding<'enc>,
{
Expand Down Expand Up @@ -174,4 +174,4 @@ where
}
}

impl<'a, T> FusedIterator for Utf8Ancestors<'a, T> where T: for<'enc> Utf8Encoding<'enc> {}
impl<T> FusedIterator for Utf8Ancestors<'_, T> where T: for<'enc> Utf8Encoding<'enc> {}
57 changes: 56 additions & 1 deletion src/common/utf8/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,7 @@ where
}
}

impl<'a, T> From<Utf8PathBuf<T>> for Cow<'a, Utf8Path<T>>
impl<T> From<Utf8PathBuf<T>> for Cow<'_, Utf8Path<T>>
where
T: for<'enc> Utf8Encoding<'enc>,
{
Expand Down Expand Up @@ -1475,3 +1475,58 @@ mod helpers {
}
}
}

#[cfg(any(
unix,
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "solid_asp3",
target_os = "hermit",
target_os = "wasi"
))]
#[cfg(feature = "std")]
mod std_conversions {
use std::ffi::{OsStr, OsString};
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
use std::os::fortanix_sgx as os;
#[cfg(target_os = "solid_asp3")]
use std::os::solid as os;
#[cfg(any(target_os = "hermit", unix))]
use std::os::unix as os;
#[cfg(target_os = "wasi")]
use std::os::wasi as os;

use os::ffi::OsStrExt;

use super::*;
use crate::common::TryAsRef;

impl<T> TryAsRef<Utf8Path<T>> for OsStr
where
T: for<'enc> Utf8Encoding<'enc>,
{
#[inline]
fn try_as_ref(&self) -> Option<&Utf8Path<T>> {
std::str::from_utf8(self.as_bytes()).ok().map(Utf8Path::new)
}
}

impl<T> TryAsRef<Utf8Path<T>> for OsString
where
T: for<'enc> Utf8Encoding<'enc>,
{
#[inline]
fn try_as_ref(&self) -> Option<&Utf8Path<T>> {
std::str::from_utf8(self.as_bytes()).ok().map(Utf8Path::new)
}
}

impl<T> AsRef<OsStr> for Utf8Path<T>
where
T: for<'enc> Utf8Encoding<'enc>,
{
#[inline]
fn as_ref(&self) -> &OsStr {
OsStrExt::from_bytes(self.as_str().as_bytes())
}
}
}
44 changes: 44 additions & 0 deletions src/common/utf8/pathbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,3 +778,47 @@ where
self.components().cmp(other.components())
}
}

#[cfg(any(
unix,
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "solid_asp3",
target_os = "hermit",
target_os = "wasi"
))]
#[cfg(feature = "std")]
mod std_conversions {
use std::ffi::{OsStr, OsString};
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
use std::os::fortanix_sgx as os;
#[cfg(target_os = "solid_asp3")]
use std::os::solid as os;
#[cfg(any(target_os = "hermit", unix))]
use std::os::unix as os;
#[cfg(target_os = "wasi")]
use std::os::wasi as os;

use os::ffi::{OsStrExt, OsStringExt};

use super::*;

impl<T> From<Utf8PathBuf<T>> for OsString
where
T: for<'enc> Utf8Encoding<'enc>,
{
#[inline]
fn from(path_buf: Utf8PathBuf<T>) -> Self {
OsStringExt::from_vec(path_buf.into_string().into_bytes())
}
}

impl<T> AsRef<OsStr> for Utf8PathBuf<T>
where
T: for<'enc> Utf8Encoding<'enc>,
{
#[inline]
fn as_ref(&self) -> &OsStr {
OsStrExt::from_bytes(self.as_str().as_bytes())
}
}
}
Loading

0 comments on commit 73e9da6

Please sign in to comment.