1use std::borrow::Cow;
2use std::cell::{Ref, RefMut};
3use std::fmt;
4use std::num::{
5 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize,
6 NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
7};
8use std::path::{Path, PathBuf};
9use std::rc::Rc;
10use std::sync::{Arc, MutexGuard, RwLockReadGuard, RwLockWriteGuard};
11
12use super::buffer::Buffer;
13use super::escape;
14
15pub trait Render {
42 fn render(&self, b: &mut Buffer) -> Result<(), RenderError>;
44
45 #[inline]
47 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
48 let mut tmp = Buffer::new();
49 self.render(&mut tmp)?;
50 escape::escape_to_buf(tmp.as_str(), b);
51 Ok(())
52 }
53}
54
55impl Render for String {
79 #[inline]
80 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
81 b.push_str(self);
82 Ok(())
83 }
84
85 #[inline]
86 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
87 escape::escape_to_buf(self, b);
88 Ok(())
89 }
90}
91
92impl Render for str {
93 #[inline]
94 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
95 b.push_str(self);
96 Ok(())
97 }
98
99 #[inline]
100 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
101 escape::escape_to_buf(self, b);
102 Ok(())
103 }
104}
105
106impl Render for char {
107 #[inline]
108 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
109 b.push(*self);
110 Ok(())
111 }
112
113 #[inline]
114 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
115 match *self {
116 '\"' => b.push_str("""),
117 '&' => b.push_str("&"),
118 '<' => b.push_str("<"),
119 '>' => b.push_str(">"),
120 '\'' => b.push_str("'"),
121 _ => b.push(*self),
122 }
123 Ok(())
124 }
125}
126
127impl Render for PathBuf {
128 #[inline]
129 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
130 b.push_str(&self.to_string_lossy());
132 Ok(())
133 }
134
135 #[inline]
136 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
137 escape::escape_to_buf(&self.to_string_lossy(), b);
138 Ok(())
139 }
140}
141
142impl Render for Path {
143 #[inline]
144 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
145 b.push_str(&self.to_string_lossy());
147 Ok(())
148 }
149
150 #[inline]
151 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
152 escape::escape_to_buf(&self.to_string_lossy(), b);
153 Ok(())
154 }
155}
156
157impl Render for bool {
182 #[inline]
183 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
184 let s = if *self { "true" } else { "false" };
185 b.push_str(s);
186 Ok(())
187 }
188
189 #[inline]
190 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
191 self.render(b)
192 }
193}
194
195macro_rules! render_int {
196 ($($int:ty),*) => {
197 $(
198 impl Render for $int {
199 #[cfg_attr(feature = "perf-inline", inline)]
200 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
201 use itoap::Integer;
202
203 unsafe {
206 b.reserve_small(Self::MAX_LEN);
207 let ptr = b.as_mut_ptr().add(b.len());
208
209 let l = itoap::write_to_ptr(ptr, *self);
212 b.advance(l);
213 }
214 debug_assert!(b.len() <= b.capacity());
215 Ok(())
216 }
217
218 #[inline]
219 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
220 self.render(b)
222 }
223 }
224 )*
225 }
226}
227
228render_int!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
229
230impl Render for f32 {
231 #[cfg_attr(feature = "perf-inline", inline)]
232 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
233 if likely!(self.is_finite()) {
234 unsafe {
235 b.reserve_small(16);
236 let ptr = b.as_mut_ptr().add(b.len());
237 let l = ryu::raw::format32(*self, ptr);
238 b.advance(l);
239 debug_assert!(b.len() <= b.capacity());
240 }
241 } else if self.is_nan() {
242 b.push_str("NaN");
243 } else if *self > 0.0 {
244 b.push_str("inf");
245 } else {
246 b.push_str("-inf");
247 }
248
249 Ok(())
250 }
251
252 #[inline]
253 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
254 self.render(b)
256 }
257}
258
259impl Render for f64 {
260 #[cfg_attr(feature = "perf-inline", inline)]
261 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
262 if likely!(self.is_finite()) {
263 unsafe {
264 b.reserve_small(24);
265 let ptr = b.as_mut_ptr().add(b.len());
266 let l = ryu::raw::format64(*self, ptr);
267 b.advance(l);
268 debug_assert!(b.len() <= b.capacity());
269 }
270 } else if self.is_nan() {
271 b.push_str("NaN");
272 } else if *self > 0.0 {
273 b.push_str("inf");
274 } else {
275 b.push_str("-inf");
276 }
277
278 Ok(())
279 }
280
281 #[inline]
282 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
283 self.render(b)
285 }
286}
287
288macro_rules! render_deref {
289 (
290 $(#[doc = $doc:tt])*
291 [$($bounds:tt)+] $($desc:tt)+
292 ) => {
293 $(#[doc = $doc])*
294 impl <$($bounds)+> Render for $($desc)+ {
295 #[inline]
296 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
297 (**self).render(b)
298 }
299
300 #[inline]
301 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
302 (**self).render_escaped(b)
303 }
304 }
305 };
306}
307
308render_deref!(['a, T: Render + ?Sized] &'a T);
309render_deref!(['a, T: Render + ?Sized] &'a mut T);
310render_deref!([T: Render + ?Sized] Box<T>);
311render_deref!([T: Render + ?Sized] Rc<T>);
312render_deref!([T: Render + ?Sized] Arc<T>);
313render_deref!(['a, T: Render + ToOwned + ?Sized] Cow<'a, T>);
314render_deref!(['a, T: Render + ?Sized] Ref<'a, T>);
315render_deref!(['a, T: Render + ?Sized] RefMut<'a, T>);
316render_deref!(['a, T: Render + ?Sized] MutexGuard<'a, T>);
317render_deref!(['a, T: Render + ?Sized] RwLockReadGuard<'a, T>);
318render_deref!(['a, T: Render + ?Sized] RwLockWriteGuard<'a, T>);
319
320macro_rules! render_nonzero {
321 ($($type:ty,)*) => {
322 $(
323 impl Render for $type {
324 #[inline]
325 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
326 self.get().render(b)
327 }
328
329 #[inline]
330 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
331 self.get().render_escaped(b)
332 }
333 }
334 )*
335 }
336}
337
338render_nonzero!(
339 NonZeroI8,
340 NonZeroI16,
341 NonZeroI32,
342 NonZeroI64,
343 NonZeroI128,
344 NonZeroIsize,
345 NonZeroU8,
346 NonZeroU16,
347 NonZeroU32,
348 NonZeroU64,
349 NonZeroU128,
350 NonZeroUsize,
351);
352
353impl<T: Render> Render for Wrapping<T> {
354 #[inline]
355 fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
356 self.0.render(b)
357 }
358
359 #[inline]
360 fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
361 self.0.render_escaped(b)
362 }
363}
364
365#[derive(Clone, Debug)]
367pub enum RenderError {
368 Msg(String),
370 Fmt(fmt::Error),
372 BufSize,
379}
380
381impl RenderError {
382 pub fn new(msg: &str) -> Self {
384 RenderError::Msg(msg.to_owned())
385 }
386}
387
388impl fmt::Display for RenderError {
389 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
390 match self {
391 RenderError::Msg(s) => f.pad(s),
392 RenderError::Fmt(e) => fmt::Display::fmt(e, f),
393 RenderError::BufSize => f.pad("buffer size shrinked while rendering"),
394 }
395 }
396}
397
398impl std::error::Error for RenderError {
399 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
400 match self {
401 RenderError::Msg(_) | RenderError::BufSize => None,
402 RenderError::Fmt(e) => Some(e),
403 }
404 }
405}
406
407impl From<fmt::Error> for RenderError {
408 #[inline]
409 fn from(other: fmt::Error) -> Self {
410 RenderError::Fmt(other)
411 }
412}
413
414pub type RenderResult = Result<String, RenderError>;
416
417#[cfg(test)]
418mod tests {
419 use super::*;
420 use std::error::Error;
421
422 #[test]
423 fn receiver_coercion() {
424 let mut b = Buffer::new();
425 Render::render(&1, &mut b).unwrap();
426 Render::render(&&1, &mut b).unwrap();
427 Render::render(&&&1, &mut b).unwrap();
428 Render::render(&&&&1, &mut b).unwrap();
429 assert_eq!(b.as_str(), "1111");
430 b.clear();
431
432 Render::render(&true, &mut b).unwrap();
433 Render::render(&&false, &mut b).unwrap();
434 Render::render_escaped(&&&true, &mut b).unwrap();
435 Render::render_escaped(&&&&false, &mut b).unwrap();
436 assert_eq!(b.as_str(), "truefalsetruefalse");
437 b.clear();
438
439 let s = "apple";
440 Render::render_escaped(&s, &mut b).unwrap();
441 Render::render_escaped(&s, &mut b).unwrap();
442 Render::render_escaped(&&s, &mut b).unwrap();
443 Render::render_escaped(&&&s, &mut b).unwrap();
444 Render::render_escaped(&&&&s, &mut b).unwrap();
445 assert_eq!(b.as_str(), "appleappleappleappleapple");
446 b.clear();
447
448 Render::render_escaped(&'c', &mut b).unwrap();
449 Render::render_escaped(&&'<', &mut b).unwrap();
450 Render::render_escaped(&&&'&', &mut b).unwrap();
451 Render::render_escaped(&&&&' ', &mut b).unwrap();
452 assert_eq!(b.as_str(), "c<& ");
453 b.clear();
454 }
455
456 #[test]
457 fn deref_coercion() {
458 use std::path::{Path, PathBuf};
459 use std::rc::Rc;
460
461 let mut b = Buffer::new();
462 Render::render(&String::from("a"), &mut b).unwrap();
463 Render::render(&&PathBuf::from("b"), &mut b).unwrap();
464 Render::render_escaped(&Rc::new(4u32), &mut b).unwrap();
465 Render::render_escaped(&Rc::new(2.3f32), &mut b).unwrap();
466 Render::render_escaped(Path::new("<"), &mut b).unwrap();
467 Render::render_escaped(&Path::new("d"), &mut b).unwrap();
468
469 assert_eq!(b.as_str(), "ab42.3<d");
470 }
471
472 #[test]
473 fn float() {
474 let mut b = Buffer::new();
475
476 Render::render_escaped(&0.0f64, &mut b).unwrap();
477 Render::render_escaped(&std::f64::INFINITY, &mut b).unwrap();
478 Render::render_escaped(&std::f64::NEG_INFINITY, &mut b).unwrap();
479 Render::render_escaped(&std::f64::NAN, &mut b).unwrap();
480 assert_eq!(b.as_str(), "0.0inf-infNaN");
481 b.clear();
482
483 Render::render_escaped(&0.0f32, &mut b).unwrap();
484 Render::render_escaped(&std::f32::INFINITY, &mut b).unwrap();
485 Render::render_escaped(&std::f32::NEG_INFINITY, &mut b).unwrap();
486 Render::render_escaped(&std::f32::NAN, &mut b).unwrap();
487 assert_eq!(b.as_str(), "0.0inf-infNaN");
488 }
489
490 #[test]
491 fn test_char() {
492 let mut b = Buffer::new();
493
494 let funcs: Vec<fn(&char, &mut Buffer) -> Result<(), RenderError>> =
495 vec![Render::render, Render::render_escaped];
496
497 for func in funcs {
498 func(&'a', &mut b).unwrap();
499 func(&'b', &mut b).unwrap();
500 func(&'c', &mut b).unwrap();
501 func(&'d', &mut b).unwrap();
502
503 assert_eq!(b.as_str(), "abcd");
504 b.clear();
505
506 func(&'あ', &mut b).unwrap();
507 func(&'い', &mut b).unwrap();
508 func(&'う', &mut b).unwrap();
509 func(&'え', &mut b).unwrap();
510
511 assert_eq!(b.as_str(), "あいうえ");
512 b.clear();
513 }
514 }
515
516 #[test]
517 fn test_nonzero() {
518 let mut b = Buffer::with_capacity(2);
519 Render::render(&NonZeroU8::new(10).unwrap(), &mut b).unwrap();
520 Render::render_escaped(&NonZeroI16::new(-20).unwrap(), &mut b).unwrap();
521 assert_eq!(b.as_str(), "10-20");
522 }
523
524 #[test]
525 fn render_error() {
526 let err = RenderError::new("custom error");
527 assert!(err.source().is_none());
528 assert_eq!(format!("{}", err), "custom error");
529
530 let err = RenderError::from(std::fmt::Error::default());
531 assert!(err.source().is_some());
532 assert_eq!(
533 format!("{}", err),
534 format!("{}", std::fmt::Error::default())
535 );
536
537 let err = RenderError::BufSize;
538 assert!(err.source().is_none());
539
540 assert!(format!("{}", err).is_empty().eq(&false));
541 }
542}