1use std::fmt::{self, Write};
19use std::ops::Deref;
20
21pub trait StrExt {
23 fn quoted(&self) -> QuotedStr;
50 fn escaped(&self) -> EscapedStr;
62}
63
64impl StrExt for str {
65 fn quoted(&self) -> QuotedStr {
66 QuotedStr(self)
67 }
68 fn escaped(&self) -> EscapedStr {
69 EscapedStr(self)
70 }
71}
72
73#[derive(Debug)]
78pub struct QuotedStr<'a>(&'a str);
79
80impl<'a> fmt::Display for QuotedStr<'a> {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 f.write_char('"')?;
83 for c in self.chars() {
84 match c {
85 '"' => f.write_str("\\\"")?,
86 _ => f.write_char(c)?,
87 }
88 }
89 f.write_char('"')
90 }
91}
92
93impl<'a> Deref for QuotedStr<'a> {
94 type Target = str;
95
96 fn deref(&self) -> &str {
97 self.0
98 }
99}
100
101#[derive(Debug)]
105pub struct EscapedStr<'a>(&'a str);
106
107impl<'a> fmt::Display for EscapedStr<'a> {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 f.write_char('"')?;
110 for c in self.chars() {
111 match c {
113 '"' => f.write_str("\\\"")?,
114 '\n' => f.write_str("\\n")?,
115 '\r' => f.write_str("\\r")?,
116 '\t' => f.write_str("\\t")?,
117 _ => f.write_char(c)?,
118 }
119 }
120 f.write_char('"')
121 }
122}
123
124impl<'a> Deref for EscapedStr<'a> {
125 type Target = str;
126
127 fn deref(&self) -> &str {
128 self.0
129 }
130}
131
132pub fn bracketed<'a, D>(open: &'a str, close: &'a str, contents: D) -> impl fmt::Display + 'a
135where
136 D: fmt::Display + 'a,
137{
138 struct Bracketed<'a, D> {
139 open: &'a str,
140 close: &'a str,
141 contents: D,
142 }
143
144 impl<'a, D> fmt::Display for Bracketed<'a, D>
145 where
146 D: fmt::Display,
147 {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 write!(f, "{}{}{}", self.open, self.contents, self.close)
150 }
151 }
152
153 Bracketed {
154 open,
155 close,
156 contents,
157 }
158}
159
160pub fn closure_to_display<F>(fun: F) -> impl fmt::Display
162where
163 F: Fn(&mut fmt::Formatter) -> fmt::Result,
164{
165 struct Mapped<F> {
166 fun: F,
167 }
168
169 impl<F> fmt::Display for Mapped<F>
170 where
171 F: Fn(&mut fmt::Formatter) -> fmt::Result,
172 {
173 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
174 (self.fun)(formatter)
175 }
176 }
177
178 Mapped { fun }
179}
180
181pub fn separated<'a, I>(separator: &'a str, iter: I) -> impl fmt::Display + 'a
184where
185 I: IntoIterator,
186 I::IntoIter: Clone + 'a,
187 I::Item: fmt::Display + 'a,
188{
189 struct Separated<'a, I> {
190 separator: &'a str,
191 iter: I,
192 }
193
194 impl<'a, I> fmt::Display for Separated<'a, I>
195 where
196 I: Iterator + Clone,
197 I::Item: fmt::Display,
198 {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 for (i, item) in self.iter.clone().enumerate() {
201 if i != 0 {
202 write!(f, "{}", self.separator)?;
203 }
204 write!(f, "{}", item)?;
205 }
206 Ok(())
207 }
208 }
209
210 Separated {
211 separator,
212 iter: iter.into_iter(),
213 }
214}
215
216#[derive(Debug, Clone)]
221pub struct Indent {
222 unit: String,
223 buff: String,
224 mark: Vec<usize>,
225}
226
227impl AsMut<Indent> for Indent {
228 fn as_mut(&mut self) -> &mut Indent {
229 self
230 }
231}
232
233impl Indent {
234 pub fn new(unit: char, step: usize) -> Indent {
237 Indent {
238 unit: std::iter::repeat(unit).take(step).collect::<String>(),
239 buff: String::with_capacity(unit.len_utf8()),
240 mark: vec![],
241 }
242 }
243
244 fn inc(&mut self, rhs: usize) {
245 for _ in 0..rhs {
246 self.buff += &self.unit;
247 }
248 }
249
250 fn dec(&mut self, rhs: usize) {
251 let tail = rhs.saturating_mul(self.unit.len());
252 let head = self.buff.len().saturating_sub(tail);
253 self.buff.truncate(head);
254 }
255
256 pub fn set(&mut self) {
258 self.mark.push(self.buff.len());
259 }
260
261 pub fn reset(&mut self) {
263 if let Some(len) = self.mark.pop() {
264 while self.buff.len() < len {
265 self.buff += &self.unit;
266 }
267 self.buff.truncate(len);
268 }
269 }
270}
271
272pub trait IndentLike {
276 fn indented<F>(&mut self, f: F) -> fmt::Result
279 where
280 F: FnMut(&mut Self) -> fmt::Result;
281
282 fn indented_if<F>(&mut self, guard: bool, f: F) -> fmt::Result
285 where
286 F: FnMut(&mut Self) -> fmt::Result;
287}
288
289impl<T: AsMut<Indent>> IndentLike for T {
290 fn indented<F>(&mut self, mut f: F) -> fmt::Result
291 where
292 F: FnMut(&mut Self) -> fmt::Result,
293 {
294 *self.as_mut() += 1;
295 let result = f(self);
296 *self.as_mut() -= 1;
297 result
298 }
299
300 fn indented_if<F>(&mut self, guard: bool, mut f: F) -> fmt::Result
301 where
302 F: FnMut(&mut Self) -> fmt::Result,
303 {
304 if guard {
305 *self.as_mut() += 1;
306 }
307 let result = f(self);
308
309 if guard {
310 *self.as_mut() -= 1;
311 }
312 result
313 }
314}
315
316impl Default for Indent {
317 fn default() -> Self {
318 Indent::new(' ', 2)
319 }
320}
321
322impl std::ops::AddAssign<usize> for Indent {
323 fn add_assign(&mut self, rhs: usize) {
324 self.inc(rhs)
325 }
326}
327
328impl std::ops::SubAssign<usize> for Indent {
329 fn sub_assign(&mut self, rhs: usize) {
330 self.dec(rhs)
331 }
332}
333
334impl fmt::Display for Indent {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 f.write_str(&self.buff)
337 }
338}
339
340#[derive(Debug, Clone, PartialEq)]
343pub struct MaxLenString<const MAX: usize>(String);
344
345impl<const MAX: usize> MaxLenString<MAX> {
346 pub fn new(s: String) -> Result<Self, String> {
365 if s.len() > MAX {
366 return Err(s);
367 }
368
369 Ok(MaxLenString(s))
370 }
371
372 pub fn into_inner(self) -> String {
374 self.0
375 }
376
377 pub fn as_str(&self) -> &str {
379 self
380 }
381}
382
383impl<const MAX: usize> Deref for MaxLenString<MAX> {
384 type Target = str;
385
386 fn deref(&self) -> &Self::Target {
387 &self.0
388 }
389}
390
391impl<const MAX: usize> fmt::Display for MaxLenString<MAX> {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 f.write_str(&self.0)
394 }
395}
396
397impl<const MAX: usize> TryFrom<String> for MaxLenString<MAX> {
398 type Error = String;
399
400 fn try_from(s: String) -> Result<Self, Self::Error> {
401 Self::new(s)
402 }
403}
404
405impl<'a, const MAX: usize> TryFrom<&'a String> for MaxLenString<MAX> {
406 type Error = String;
407
408 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
409 Self::try_from(s.clone())
410 }
411}
412
413impl<'a, const MAX: usize> TryFrom<&'a str> for MaxLenString<MAX> {
414 type Error = String;
415
416 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
417 Self::try_from(String::from(s))
418 }
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424
425 #[crate::test]
426 fn test_indent() {
427 let mut indent = Indent::new('~', 3);
428 indent += 1;
429 assert_eq!(indent.to_string(), "~~~".to_string());
430 indent += 3;
431 assert_eq!(indent.to_string(), "~~~~~~~~~~~~".to_string());
432 indent -= 2;
433 assert_eq!(indent.to_string(), "~~~~~~".to_string());
434 indent -= 4;
435 assert_eq!(indent.to_string(), "".to_string());
436 indent += 1;
437 assert_eq!(indent.to_string(), "~~~".to_string());
438 }
439}