Skip to content

Commit

Permalink
Deprecate missing the "checked_conversions" feature
Browse files Browse the repository at this point in the history
  • Loading branch information
dylni committed Aug 14, 2022
1 parent 5d6c29b commit 7352e35
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 376 deletions.
265 changes: 161 additions & 104 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
//! [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed
//! [print\_bytes]: https://crates.io/crates/print_bytes

#![cfg_attr(not(feature = "checked_conversions"), allow(deprecated))]
// Only require a nightly compiler when building documentation for docs.rs.
// This is a private option that should not be used.
// https://github.com/rust-lang/docs.rs/issues/147#issuecomment-389544407
Expand Down Expand Up @@ -208,6 +209,17 @@ if_checked_conversions! {
);
}

#[rustfmt::skip]
macro_rules! deprecated_checked_conversion {
( $message:expr , $item:item ) => {
#[cfg_attr(
not(feature = "checked_conversions"),
deprecated = $message
)]
$item
};
}

macro_rules! expect_encoded {
( $result:expr ) => {
$result.expect("invalid raw bytes")
Expand Down Expand Up @@ -256,25 +268,34 @@ if_raw_str! {
pub use raw_str::RawOsString;
}

/// The error that occurs when a byte sequence is not representable in the
/// platform encoding.
///
/// [`Result::unwrap`] should almost always be called on results containing
/// this error. It should be known whether or not byte sequences are properly
/// encoded for the platform, since [the module-level documentation][encoding]
/// discourages using encoded bytes in interchange. Results are returned
/// primarily to make panicking behavior explicit.
///
/// On Unix, this error is never returned, but [`OsStrExt`] or [`OsStringExt`]
/// should be used instead if that needs to be guaranteed.
///
/// [encoding]: self#encoding
/// [`OsStrExt`]: ::std::os::unix::ffi::OsStrExt
/// [`OsStringExt`]: ::std::os::unix::ffi::OsStringExt
/// [`Result::unwrap`]: ::std::result::Result::unwrap
#[derive(Debug, Eq, PartialEq)]
#[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "checked_conversions")))]
pub struct EncodingError(imp::EncodingError);
deprecated_checked_conversion! {
"use `OsStrBytes::assert_from_raw_bytes` or \
`OsStringBytes::assert_from_raw_vec` instead, or enable the \
'checked_conversions' feature",
/// The error that occurs when a byte sequence is not representable in the
/// platform encoding.
///
/// [`Result::unwrap`] should almost always be called on results containing
/// this error. It should be known whether or not byte sequences are
/// properly encoded for the platform, since [the module-level
/// documentation][encoding] discourages using encoded bytes in
/// interchange. Results are returned primarily to make panicking behavior
/// explicit.
///
/// On Unix, this error is never returned, but [`OsStrExt`] or
/// [`OsStringExt`] should be used instead if that needs to be guaranteed.
///
/// [encoding]: self#encoding
/// [`OsStrExt`]: ::std::os::unix::ffi::OsStrExt
/// [`OsStringExt`]: ::std::os::unix::ffi::OsStringExt
/// [`Result::unwrap`]: ::std::result::Result::unwrap
#[derive(Debug, Eq, PartialEq)]
#[cfg_attr(
os_str_bytes_docs_rs,
doc(cfg(feature = "checked_conversions"))
)]
pub struct EncodingError(imp::EncodingError);
}

impl Display for EncodingError {
#[inline]
Expand All @@ -287,6 +308,25 @@ impl Error for EncodingError {}

type Result<T> = result::Result<T, EncodingError>;

fn from_raw_bytes<'a, S>(
string: S,
) -> result::Result<Cow<'a, OsStr>, imp::EncodingError>
where
S: Into<Cow<'a, [u8]>>,
{
match string.into() {
Cow::Borrowed(string) => imp::os_str_from_bytes(string),
Cow::Owned(string) => imp::os_string_from_vec(string).map(Cow::Owned),
}
}

fn cow_os_str_into_path(string: Cow<'_, OsStr>) -> Cow<'_, Path> {
match string {
Cow::Borrowed(string) => Cow::Borrowed(Path::new(string)),
Cow::Owned(string) => Cow::Owned(string.into()),
}
}

/// A platform agnostic variant of [`OsStrExt`].
///
/// For more information, see [the module-level documentation][module].
Expand Down Expand Up @@ -318,50 +358,50 @@ pub trait OsStrBytes: private::Sealed + ToOwned {
/// ```
///
/// [unspecified encoding]: self#encoding
#[inline]
#[must_use = "method should not be used for validation"]
#[track_caller]
fn assert_from_raw_bytes<'a, S>(string: S) -> Cow<'a, Self>
where
S: Into<Cow<'a, [u8]>>,
{
expect_encoded!(Self::from_raw_bytes(string))
}

/// Converts a byte string into an equivalent platform-native string.
///
/// [`assert_from_raw_bytes`] should almost always be used instead. For
/// more information, see [`EncodingError`].
///
/// # Errors
///
/// See documentation for [`EncodingError`].
///
/// # Examples
///
/// ```
/// use std::env;
/// use std::ffi::OsStr;
/// # use std::io;
///
/// use os_str_bytes::OsStrBytes;
///
/// let os_string = env::current_exe()?;
/// let os_bytes = os_string.to_raw_bytes();
/// assert_eq!(os_string, OsStr::from_raw_bytes(os_bytes).unwrap());
/// #
/// # Ok::<_, io::Error>(())
/// ```
///
/// [`assert_from_raw_bytes`]: Self::assert_from_raw_bytes
#[cfg_attr(
os_str_bytes_docs_rs,
doc(cfg(feature = "checked_conversions"))
)]
fn from_raw_bytes<'a, S>(string: S) -> Result<Cow<'a, Self>>
where
S: Into<Cow<'a, [u8]>>;

deprecated_checked_conversion! {
"use `assert_from_raw_bytes` instead, or enable the \
'checked_conversions' feature",
/// Converts a byte string into an equivalent platform-native string.
///
/// [`assert_from_raw_bytes`] should almost always be used instead. For
/// more information, see [`EncodingError`].
///
/// # Errors
///
/// See documentation for [`EncodingError`].
///
/// # Examples
///
/// ```
/// use std::env;
/// use std::ffi::OsStr;
/// # use std::io;
///
/// use os_str_bytes::OsStrBytes;
///
/// let os_string = env::current_exe()?;
/// let os_bytes = os_string.to_raw_bytes();
/// assert_eq!(os_string, OsStr::from_raw_bytes(os_bytes).unwrap());
/// #
/// # Ok::<_, io::Error>(())
/// ```
///
/// [`assert_from_raw_bytes`]: Self::assert_from_raw_bytes
#[cfg_attr(
os_str_bytes_docs_rs,
doc(cfg(feature = "checked_conversions"))
)]
fn from_raw_bytes<'a, S>(string: S) -> Result<Cow<'a, Self>>
where
S: Into<Cow<'a, [u8]>>;
}

/// Converts a platform-native string into an equivalent byte string.
///
/// The returned string will use an [unspecified encoding].
Expand All @@ -384,19 +424,20 @@ pub trait OsStrBytes: private::Sealed + ToOwned {
}

impl OsStrBytes for OsStr {
#[inline]
fn assert_from_raw_bytes<'a, S>(string: S) -> Cow<'a, Self>
where
S: Into<Cow<'a, [u8]>>,
{
expect_encoded!(from_raw_bytes(string))
}

#[inline]
fn from_raw_bytes<'a, S>(string: S) -> Result<Cow<'a, Self>>
where
S: Into<Cow<'a, [u8]>>,
{
match string.into() {
Cow::Borrowed(string) => {
imp::os_str_from_bytes(string).map_err(EncodingError)
}
Cow::Owned(string) => {
OsStringBytes::from_raw_vec(string).map(Cow::Owned)
}
}
from_raw_bytes(string).map_err(EncodingError)
}

#[inline]
Expand All @@ -406,15 +447,20 @@ impl OsStrBytes for OsStr {
}

impl OsStrBytes for Path {
#[inline]
fn assert_from_raw_bytes<'a, S>(string: S) -> Cow<'a, Self>
where
S: Into<Cow<'a, [u8]>>,
{
cow_os_str_into_path(OsStr::assert_from_raw_bytes(string))
}

#[inline]
fn from_raw_bytes<'a, S>(string: S) -> Result<Cow<'a, Self>>
where
S: Into<Cow<'a, [u8]>>,
{
OsStr::from_raw_bytes(string).map(|os_string| match os_string {
Cow::Borrowed(os_string) => Cow::Borrowed(Self::new(os_string)),
Cow::Owned(os_string) => Cow::Owned(os_string.into()),
})
OsStr::from_raw_bytes(string).map(cow_os_str_into_path)
}

#[inline]
Expand Down Expand Up @@ -454,45 +500,46 @@ pub trait OsStringBytes: private::Sealed + Sized {
/// ```
///
/// [unspecified encoding]: self#encoding
#[inline]
#[must_use = "method should not be used for validation"]
#[track_caller]
fn assert_from_raw_vec(string: Vec<u8>) -> Self {
expect_encoded!(Self::from_raw_vec(string))
fn assert_from_raw_vec(string: Vec<u8>) -> Self;

deprecated_checked_conversion! {
"use `assert_from_raw_vec` instead, or enable the \
'checked_conversions' feature",
/// Converts a byte string into an equivalent platform-native string.
///
/// [`assert_from_raw_vec`] should almost always be used instead. For
/// more information, see [`EncodingError`].
///
/// # Errors
///
/// See documentation for [`EncodingError`].
///
/// # Examples
///
/// ```
/// use std::env;
/// use std::ffi::OsString;
/// # use std::io;
///
/// use os_str_bytes::OsStringBytes;
///
/// let os_string = env::current_exe()?;
/// let os_bytes = os_string.clone().into_raw_vec();
/// assert_eq!(os_string, OsString::from_raw_vec(os_bytes).unwrap());
/// #
/// # Ok::<_, io::Error>(())
/// ```
///
/// [`assert_from_raw_vec`]: Self::assert_from_raw_vec
#[cfg_attr(
os_str_bytes_docs_rs,
doc(cfg(feature = "checked_conversions"))
)]
fn from_raw_vec(string: Vec<u8>) -> Result<Self>;
}

/// Converts a byte string into an equivalent platform-native string.
///
/// [`assert_from_raw_vec`] should almost always be used instead. For more
/// information, see [`EncodingError`].
///
/// # Errors
///
/// See documentation for [`EncodingError`].
///
/// # Examples
///
/// ```
/// use std::env;
/// use std::ffi::OsString;
/// # use std::io;
///
/// use os_str_bytes::OsStringBytes;
///
/// let os_string = env::current_exe()?;
/// let os_bytes = os_string.clone().into_raw_vec();
/// assert_eq!(os_string, OsString::from_raw_vec(os_bytes).unwrap());
/// #
/// # Ok::<_, io::Error>(())
/// ```
///
/// [`assert_from_raw_vec`]: Self::assert_from_raw_vec
#[cfg_attr(
os_str_bytes_docs_rs,
doc(cfg(feature = "checked_conversions"))
)]
fn from_raw_vec(string: Vec<u8>) -> Result<Self>;

/// Converts a platform-native string into an equivalent byte string.
///
/// The returned string will use an [unspecified encoding].
Expand All @@ -515,6 +562,11 @@ pub trait OsStringBytes: private::Sealed + Sized {
}

impl OsStringBytes for OsString {
#[inline]
fn assert_from_raw_vec(string: Vec<u8>) -> Self {
expect_encoded!(imp::os_string_from_vec(string))
}

#[inline]
fn from_raw_vec(string: Vec<u8>) -> Result<Self> {
imp::os_string_from_vec(string).map_err(EncodingError)
Expand All @@ -527,6 +579,11 @@ impl OsStringBytes for OsString {
}

impl OsStringBytes for PathBuf {
#[inline]
fn assert_from_raw_vec(string: Vec<u8>) -> Self {
OsString::assert_from_raw_vec(string).into()
}

#[inline]
fn from_raw_vec(string: Vec<u8>) -> Result<Self> {
OsString::from_raw_vec(string).map(Into::into)
Expand Down
Loading

0 comments on commit 7352e35

Please sign in to comment.