1#![cfg_attr(
30 all(
31 feature = "bstr",
32 feature = "bash",
33 feature = "fish",
34 feature = "sh",
35 ),
36 doc = include_str!("../README.md")
37)]
38
39use std::ffi::{OsStr, OsString};
40use std::path::{Path, PathBuf};
41
42mod ascii;
43mod bash;
44mod fish;
45mod sh;
46mod utf8;
47
48#[cfg(feature = "bash")]
49pub use bash::Bash;
50#[cfg(feature = "fish")]
51pub use fish::Fish;
52#[cfg(feature = "sh")]
53pub use sh::Sh;
54
55#[cfg(feature = "sh")]
58pub type Dash = sh::Sh;
59
60#[cfg(feature = "bash")]
63pub type Zsh = bash::Bash;
64
65pub trait QuoteInto<OUT: ?Sized> {
69 fn quote_into<'q, S: Into<Quotable<'q>>>(s: S, out: &mut OUT);
71}
72
73pub trait Quote<OUT: Default>: QuoteInto<OUT> {
75 fn quote<'q, S: Into<Quotable<'q>>>(s: S) -> OUT {
77 let mut out = OUT::default();
78 Self::quote_into(s, &mut out);
79 out
80 }
81}
82
83impl<T: QuoteInto<OUT>, OUT: Default> Quote<OUT> for T {}
85
86pub trait QuoteExt {
92 fn push_quoted<'q, Q, S>(&mut self, _q: Q, s: S)
93 where
94 Q: QuoteInto<Self>,
95 S: Into<Quotable<'q>>;
96}
97
98impl<T: ?Sized> QuoteExt for T {
99 fn push_quoted<'q, Q, S>(&mut self, _q: Q, s: S)
100 where
101 Q: QuoteInto<Self>,
102 S: Into<Quotable<'q>>,
103 {
104 Q::quote_into(s, self);
105 }
106}
107
108pub trait QuoteRefExt<Output: Default> {
115 fn quoted<Q: Quote<Output>>(self, q: Q) -> Output;
116}
117
118impl<'a, S, OUT: Default> QuoteRefExt<OUT> for S
119where
120 S: Into<Quotable<'a>>,
121{
122 fn quoted<Q: Quote<OUT>>(self, _q: Q) -> OUT {
123 Q::quote(self)
124 }
125}
126
127pub enum Quotable<'a> {
137 #[cfg_attr(
138 not(any(feature = "bash", feature = "fish", feature = "sh")),
139 allow(unused)
140 )]
141 Bytes(&'a [u8]),
142 #[cfg_attr(
143 not(any(feature = "bash", feature = "fish", feature = "sh")),
144 allow(unused)
145 )]
146 Text(&'a str),
147}
148
149impl<'a> From<&'a [u8]> for Quotable<'a> {
150 fn from(source: &'a [u8]) -> Quotable<'a> {
151 Quotable::Bytes(source)
152 }
153}
154
155impl<'a, const N: usize> From<&'a [u8; N]> for Quotable<'a> {
156 fn from(source: &'a [u8; N]) -> Quotable<'a> {
157 Quotable::Bytes(&source[..])
158 }
159}
160
161impl<'a> From<&'a Vec<u8>> for Quotable<'a> {
162 fn from(source: &'a Vec<u8>) -> Quotable<'a> {
163 Quotable::Bytes(source)
164 }
165}
166
167impl<'a> From<&'a str> for Quotable<'a> {
168 fn from(source: &'a str) -> Quotable<'a> {
169 Quotable::Text(source)
170 }
171}
172
173impl<'a> From<&'a String> for Quotable<'a> {
174 fn from(source: &'a String) -> Quotable<'a> {
175 Quotable::Text(source)
176 }
177}
178
179#[cfg(unix)]
180impl<'a> From<&'a OsStr> for Quotable<'a> {
181 fn from(source: &'a OsStr) -> Quotable<'a> {
182 use std::os::unix::ffi::OsStrExt;
183 source.as_bytes().into()
184 }
185}
186
187#[cfg(unix)]
188impl<'a> From<&'a OsString> for Quotable<'a> {
189 fn from(source: &'a OsString) -> Quotable<'a> {
190 use std::os::unix::ffi::OsStrExt;
191 source.as_bytes().into()
192 }
193}
194
195#[cfg(feature = "bstr")]
196impl<'a> From<&'a bstr::BStr> for Quotable<'a> {
197 fn from(source: &'a bstr::BStr) -> Quotable<'a> {
198 let bytes: &[u8] = source.as_ref();
199 bytes.into()
200 }
201}
202
203#[cfg(feature = "bstr")]
204impl<'a> From<&'a bstr::BString> for Quotable<'a> {
205 fn from(source: &'a bstr::BString) -> Quotable<'a> {
206 let bytes: &[u8] = source.as_ref();
207 bytes.into()
208 }
209}
210
211#[cfg(unix)]
212impl<'a> From<&'a Path> for Quotable<'a> {
213 fn from(source: &'a Path) -> Quotable<'a> {
214 source.as_os_str().into()
215 }
216}
217
218#[cfg(unix)]
219impl<'a> From<&'a PathBuf> for Quotable<'a> {
220 fn from(source: &'a PathBuf) -> Quotable<'a> {
221 source.as_os_str().into()
222 }
223}