#![cfg_attr(os_str_bytes_docs_rs, feature(doc_cfg))]
#![cfg_attr(
all(target_vendor = "fortanix", target_env = "sgx"),
feature(sgx_platform)
)]
#![cfg_attr(target_os = "uefi", feature(uefi_std))]
#![cfg_attr(all(target_os = "wasi", target_env = "p2"), feature(wasip2))]
#![warn(unused_results)]
use std::borrow::Cow;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::path::Path;
use std::path::PathBuf;
macro_rules! if_checked_conversions {
( $($item:item)+ ) => {
$(
#[cfg(feature = "checked_conversions")]
$item
)+
};
}
if_checked_conversions! {
use std::error::Error;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;
use std::result;
}
#[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.",
);
}
#[cfg(all(feature = "memchr", not(feature = "raw_os_str")))]
const _: &str = env!(
"__OS_STR_BYTES_CI",
concat!(
"The 'memchr' feature is useless when 'raw_os_str' is disabled; it \
should be disabled too.",
),
);
macro_rules! if_conversions {
( $($item:item)+ ) => {
$(
#[cfg(feature = "conversions")]
$item
)+
};
}
if_conversions! {
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(any(target_os = "uefi", windows), path = "windows/mod.rs")]
#[cfg_attr(
not(any(
all(target_family = "wasm", target_os = "unknown"),
target_os = "uefi",
windows,
)),
path = "common/mod.rs"
)]
mod imp;
use imp::convert_io;
if_conversions! {
use imp::convert;
}
#[cfg(any(
all(feature = "conversions", any(target_os = "uefi", windows)),
feature = "raw_os_str",
))]
mod util;
if_raw_str! {
mod ext;
pub use ext::NonUnicodeOsStr;
pub use ext::OsStrBytesExt;
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;
}
if_checked_conversions! {
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
os_str_bytes_docs_rs,
doc(cfg(feature = "checked_conversions"))
)]
pub struct EncodingError(convert::EncodingError);
impl Display for EncodingError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Error for EncodingError {}
}
if_checked_conversions! {
type Result<T> = result::Result<T, EncodingError>;
}
if_conversions! {
fn from_raw_bytes<'a, S>(string: S) -> convert::Result<Cow<'a, OsStr>>
where
S: Into<Cow<'a, [u8]>>,
{
match string.into() {
Cow::Borrowed(string) => convert::os_str_from_bytes(string),
Cow::Owned(string) => {
convert::os_string_from_vec(string).map(Cow::Owned)
}
}
}
}
if_conversions! {
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 {
if_conversions! {
#[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
#[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]>>;
}
#[must_use]
fn from_io_bytes(string: &[u8]) -> Option<&Self>;
if_checked_conversions! {
#[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_io_bytes(&self) -> Option<&'_ [u8]>;
#[must_use]
fn to_io_bytes_lossy(&self) -> Cow<'_, [u8]>;
if_conversions! {
#[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
#[must_use]
fn to_raw_bytes(&self) -> Cow<'_, [u8]>;
}
}
impl OsStrBytes for OsStr {
if_conversions! {
#[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_io_bytes(string: &[u8]) -> Option<&Self> {
convert_io::os_str_from_bytes(string)
}
if_checked_conversions! {
#[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_io_bytes(&self) -> Option<&'_ [u8]> {
convert_io::os_str_to_bytes(self)
}
#[inline]
fn to_io_bytes_lossy(&self) -> Cow<'_, [u8]> {
convert_io::os_str_to_bytes_lossy(self)
}
if_conversions! {
#[inline]
fn to_raw_bytes(&self) -> Cow<'_, [u8]> {
convert::os_str_to_bytes(self)
}
}
}
impl OsStrBytes for Path {
if_conversions! {
#[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_io_bytes(string: &[u8]) -> Option<&Self> {
OsStr::from_io_bytes(string).map(Self::new)
}
if_checked_conversions! {
#[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_io_bytes(&self) -> Option<&'_ [u8]> {
self.as_os_str().to_io_bytes()
}
#[inline]
fn to_io_bytes_lossy(&self) -> Cow<'_, [u8]> {
self.as_os_str().to_io_bytes_lossy()
}
if_conversions! {
#[inline]
fn to_raw_bytes(&self) -> Cow<'_, [u8]> {
self.as_os_str().to_raw_bytes()
}
}
}
pub trait OsStringBytes: private::Sealed + Sized {
if_conversions! {
#[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
#[must_use = "method should not be used for validation"]
#[track_caller]
fn assert_from_raw_vec(string: Vec<u8>) -> Self;
}
#[must_use]
fn from_io_vec(string: Vec<u8>) -> Option<Self>;
if_checked_conversions! {
#[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_io_vec(self) -> Option<Vec<u8>>;
#[must_use]
fn into_io_vec_lossy(self) -> Vec<u8>;
if_conversions! {
#[cfg_attr(os_str_bytes_docs_rs, doc(cfg(feature = "conversions")))]
#[must_use]
fn into_raw_vec(self) -> Vec<u8>;
}
}
impl OsStringBytes for OsString {
if_conversions! {
#[inline]
fn assert_from_raw_vec(string: Vec<u8>) -> Self {
expect_encoded!(convert::os_string_from_vec(string))
}
}
if_checked_conversions! {
#[inline]
fn from_raw_vec(string: Vec<u8>) -> Result<Self> {
convert::os_string_from_vec(string).map_err(EncodingError)
}
}
#[inline]
fn from_io_vec(string: Vec<u8>) -> Option<Self> {
convert_io::os_string_from_vec(string)
}
#[inline]
fn into_io_vec(self) -> Option<Vec<u8>> {
convert_io::os_string_into_vec(self)
}
#[inline]
fn into_io_vec_lossy(self) -> Vec<u8> {
convert_io::os_string_into_vec_lossy(self)
}
if_conversions! {
#[inline]
fn into_raw_vec(self) -> Vec<u8> {
convert::os_string_into_vec(self)
}
}
}
impl OsStringBytes for PathBuf {
if_conversions! {
#[inline]
fn assert_from_raw_vec(string: Vec<u8>) -> Self {
OsString::assert_from_raw_vec(string).into()
}
}
if_checked_conversions! {
#[inline]
fn from_raw_vec(string: Vec<u8>) -> Result<Self> {
OsString::from_raw_vec(string).map(Into::into)
}
}
#[inline]
fn from_io_vec(string: Vec<u8>) -> Option<Self> {
OsString::from_io_vec(string).map(Into::into)
}
#[inline]
fn into_io_vec(self) -> Option<Vec<u8>> {
self.into_os_string().into_io_vec()
}
#[inline]
fn into_io_vec_lossy(self) -> Vec<u8> {
self.into_os_string().into_io_vec_lossy()
}
if_conversions! {
#[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> {}
}
}