use core::ffi::CStr;
use core::fmt;
use core::fmt::Write as _;
#[cfg(feature = "os_str_bytes")]
use os_str_bytes::OsUnit;
use super::Error;
use super::Formatter;
use super::Result;
use super::QUOTE;
#[derive(Debug)]
pub struct Display<T>(T);
impl<T> fmt::Display for Display<&T>
where
T: Quote + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char(QUOTE)?;
self.0.escape(Formatter::new(f)).map_err(|x| x.0)?;
f.write_char(QUOTE)
}
}
pub trait Quote {
fn escape(&self, f: &mut Formatter<'_>) -> Result;
#[inline]
#[must_use]
fn quote(&self) -> Display<&Self> {
Display(self)
}
}
macro_rules! r#impl {
( $($(#[ $attr:meta ])* $type:ty ,)+ ) => {
$(
$(#[$attr])*
impl Quote for $type {
#[inline]
fn escape(&self, f: &mut Formatter<'_>) -> $crate::Result {
use super::escape::Escape;
Escape::escape(self, &mut f.0).map_err(Error)
}
}
)+
};
}
r#impl!(
char,
#[cfg(feature = "os_str_bytes")]
OsUnit,
str,
[u8],
);
impl<const N: usize> Quote for [u8; N] {
#[inline]
fn escape(&self, f: &mut Formatter<'_>) -> Result {
self[..].escape(f)
}
}
macro_rules! defer_impl {
( $type:ty , $convert_method:ident ) => {
impl $crate::Quote for $type {
#[inline]
fn escape(&self, f: &mut $crate::Formatter<'_>) -> $crate::Result {
self.$convert_method().escape(f)
}
}
};
}
defer_impl!(CStr, to_bytes);
#[cfg(feature = "alloc")]
mod alloc {
use alloc::ffi::CString;
use alloc::string::String;
use alloc::vec::Vec;
defer_impl!(CString, as_c_str);
defer_impl!(String, as_str);
defer_impl!(Vec<u8>, as_slice);
}
#[cfg(feature = "os_str_bytes")]
#[cfg_attr(uniquote_docs_rs, doc(cfg(feature = "os_str_bytes")))]
mod os_str {
use core::ops::Deref;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::path::Path;
use std::path::PathBuf;
use os_str_bytes::NonUnicodeOsStr;
use os_str_bytes::OsStrBytesExt;
use os_str_bytes::RawOsStr;
use os_str_bytes::RawOsString;
use crate::Formatter;
use crate::Result;
use super::Quote;
impl Quote for OsStr {
#[inline]
fn escape(&self, f: &mut Formatter<'_>) -> Result {
for (invalid, valid) in self.utf8_chunks() {
for unit in invalid.os_units() {
unit.escape(f)?;
}
valid.escape(f)?;
}
Ok(())
}
}
defer_impl!(NonUnicodeOsStr, as_os_str);
defer_impl!(OsString, as_os_str);
defer_impl!(Path, as_os_str);
defer_impl!(PathBuf, as_path);
defer_impl!(RawOsStr, as_os_str);
defer_impl!(RawOsString, deref);
}