use std::borrow::Cow;
use std::ffi::CStr;
use std::ffi::CString;
use std::ops::Deref;
#[cfg(windows)]
type Bytes<'a> = &'a [u8];
#[cfg(not(windows))]
type Bytes<'a> = Cow<'a, [u8]>;
#[derive(Debug)]
pub(super) enum ByteStrInner<'a> {
Bytes(Bytes<'a>),
#[cfg(windows)]
Str(Cow<'a, str>),
}
#[derive(Debug)]
pub struct ByteStr<'a>(pub(super) ByteStrInner<'a>);
#[cfg(any(doc, windows))]
impl<'a> ByteStr<'a> {
#[cfg_attr(print_bytes_docs_rs, doc(cfg(windows)))]
#[inline]
#[must_use]
pub fn from_utf8_lossy(string: &'a [u8]) -> Self {
Self(ByteStrInner::Str(String::from_utf8_lossy(string)))
}
}
#[cfg(any(doc, windows))]
#[cfg_attr(print_bytes_docs_rs, doc(cfg(windows)))]
#[derive(Debug)]
pub struct WideStr(pub(super) Vec<u16>);
#[cfg(any(doc, windows))]
impl WideStr {
#[inline]
#[must_use]
pub fn new(string: Vec<u16>) -> Self {
Self(string)
}
}
pub trait ToBytes {
#[must_use]
fn to_bytes(&self) -> ByteStr<'_>;
#[cfg(any(doc, windows))]
#[cfg_attr(print_bytes_docs_rs, doc(cfg(windows)))]
#[must_use]
fn to_wide(&self) -> Option<WideStr>;
}
impl ToBytes for [u8] {
#[cfg_attr(windows, allow(clippy::useless_conversion))]
#[inline]
fn to_bytes(&self) -> ByteStr<'_> {
ByteStr(ByteStrInner::Bytes(self.into()))
}
#[cfg(any(doc, windows))]
#[inline]
fn to_wide(&self) -> Option<WideStr> {
None
}
}
macro_rules! defer_methods {
( $convert_method:ident ) => {
#[inline]
fn to_bytes(&self) -> ByteStr<'_> {
ToBytes::to_bytes(self.$convert_method())
}
#[cfg(any(doc, windows))]
#[inline]
fn to_wide(&self) -> Option<WideStr> {
self.$convert_method().to_wide()
}
};
}
impl<const N: usize> ToBytes for [u8; N] {
defer_methods!(as_slice);
}
impl<T> ToBytes for Cow<'_, T>
where
T: ?Sized + ToBytes + ToOwned,
T::Owned: ToBytes,
{
defer_methods!(deref);
}
macro_rules! defer_impl {
( $type:ty , $convert_method:ident ) => {
impl ToBytes for $type {
defer_methods!($convert_method);
}
};
}
defer_impl!(CStr, to_bytes);
defer_impl!(CString, as_c_str);
defer_impl!(Vec<u8>, as_slice);
#[cfg(feature = "os_str_bytes")]
#[cfg_attr(print_bytes_docs_rs, doc(cfg(feature = "os_str_bytes")))]
mod os_str_bytes {
use std::ffi::OsStr;
use std::ffi::OsString;
#[cfg(windows)]
use std::os::windows::ffi::OsStrExt;
use std::path::Path;
use std::path::PathBuf;
#[cfg(not(windows))]
use os_str_bytes::OsStrBytes;
use super::ByteStr;
use super::ByteStrInner;
use super::ToBytes;
#[cfg(any(doc, windows))]
use super::WideStr;
impl ToBytes for OsStr {
#[inline]
fn to_bytes(&self) -> ByteStr<'_> {
#[cfg(windows)]
{
ByteStr(ByteStrInner::Str(self.to_string_lossy()))
}
#[cfg(not(windows))]
ByteStr(ByteStrInner::Bytes(self.to_io_bytes_lossy()))
}
#[cfg(any(doc, windows))]
#[inline]
fn to_wide(&self) -> Option<WideStr> {
Some(WideStr(self.encode_wide().collect()))
}
}
defer_impl!(OsString, as_os_str);
defer_impl!(Path, as_os_str);
defer_impl!(PathBuf, as_path);
}