#![cfg_attr(not(feature = "checked_conversions"), allow(deprecated))]
#![cfg_attr(os_str_bytes_docs_rs, feature(doc_cfg))]
#![cfg_attr(
all(target_vendor = "fortanix", target_env = "sgx"),
feature(sgx_platform)
)]
#![warn(unsafe_op_in_unsafe_fn)]
#![warn(unused_results)]
use std::borrow::Cow;
use std::error::Error;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;
use std::path::Path;
use std::path::PathBuf;
use std::result;
macro_rules! if_checked_conversions {
( $($item:item)+ ) => {
$(
#[cfg(feature = "checked_conversions")]
$item
)+
};
}
#[cfg(not(os_str_bytes_docs_rs))]
if_checked_conversions! {
const _: &str = env!(
"OS_STR_BYTES_CHECKED_CONVERSIONS",
"The 'OS_STR_BYTES_CHECKED_CONVERSIONS' environment variable must be \
defined to use the 'checked_conversions' feature.",
);
}
#[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")
};
}
macro_rules! if_raw_str {
( $($item:item)+ ) => {
$(
#[cfg(feature = "raw_os_str")]
$item
)+
};
}
#[cfg_attr(
all(target_family = "wasm", target_os = "unknown"),
path = "wasm/mod.rs"
)]
#[cfg_attr(windows, path = "windows/mod.rs")]
#[cfg_attr(
not(any(all(target_family = "wasm", target_os = "unknown"), windows)),
path = "common/mod.rs"
)]
mod imp;
#[cfg(any(
all(
feature = "raw_os_str",
target_family = "wasm",
target_os = "unknown",
),
windows,
))]
mod util;
if_raw_str! {
pub mod iter;
mod pattern;
pub use pattern::Pattern;
mod raw_str;
pub use raw_str::RawOsStr;
pub use raw_str::RawOsStrCow;
pub use raw_str::RawOsString;
}
deprecated_checked_conversion! {
"use `OsStrBytes::assert_from_raw_bytes` or \
`OsStringBytes::assert_from_raw_vec` instead, or enable the \
'checked_conversions' feature",
#[derive(Clone, 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]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
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()),
}
}
pub trait OsStrBytes: private::Sealed + ToOwned {
#[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]>>;
deprecated_checked_conversion! {
"use `assert_from_raw_bytes` instead, or enable the \
'checked_conversions' feature",
#[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]>>;
}
#[must_use]
fn to_raw_bytes(&self) -> Cow<'_, [u8]>;
}
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]>>,
{
from_raw_bytes(string).map_err(EncodingError)
}
#[inline]
fn to_raw_bytes(&self) -> Cow<'_, [u8]> {
imp::os_str_to_bytes(self)
}
}
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(cow_os_str_into_path)
}
#[inline]
fn to_raw_bytes(&self) -> Cow<'_, [u8]> {
self.as_os_str().to_raw_bytes()
}
}
pub trait OsStringBytes: private::Sealed + Sized {
#[must_use = "method should not be used for validation"]
#[track_caller]
fn assert_from_raw_vec(string: Vec<u8>) -> Self;
deprecated_checked_conversion! {
"use `assert_from_raw_vec` instead, or enable the \
'checked_conversions' feature",
#[cfg_attr(
os_str_bytes_docs_rs,
doc(cfg(feature = "checked_conversions"))
)]
fn from_raw_vec(string: Vec<u8>) -> Result<Self>;
}
#[must_use]
fn into_raw_vec(self) -> Vec<u8>;
}
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)
}
#[inline]
fn into_raw_vec(self) -> Vec<u8> {
imp::os_string_into_vec(self)
}
}
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)
}
#[inline]
fn into_raw_vec(self) -> Vec<u8> {
self.into_os_string().into_raw_vec()
}
}
mod private {
use std::ffi::OsStr;
use std::ffi::OsString;
use std::path::Path;
use std::path::PathBuf;
if_raw_str! {
use std::borrow::Cow;
use super::RawOsStr;
}
pub trait Sealed {}
impl Sealed for char {}
impl Sealed for OsStr {}
impl Sealed for OsString {}
impl Sealed for Path {}
impl Sealed for PathBuf {}
impl Sealed for &str {}
impl Sealed for &String {}
if_raw_str! {
impl Sealed for Cow<'_, RawOsStr> {}
}
}