1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
use std::fmt::Display; pub use markup_proc_macro::define; pub trait Render { fn render(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result; fn is_none(&self) -> bool { false } } impl<'a, T: Render + ?Sized> Render for &'a T { fn render(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { (*self).render(f) } } impl<T: Render> Render for Option<T> { fn render(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Some(t) => t.render(f), None => Ok(()), } } fn is_none(&self) -> bool { self.is_none() } } impl Render for str { fn render(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let mut last = 0; for (index, byte) in self.bytes().enumerate() { match byte { b'&' | b'<' | b'>' | b'"' => { f.write_str(&self[last..index])?; f.write_str(match byte { b'&' => "&", b'<' => "<", b'>' => ">", _ => """, })?; last = index + 1; } _ => {} } } f.write_str(&self[last..]) } } impl Render for String { fn render(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.as_str().render(f) } } struct Raw<T: Display>(pub T); impl<T: Display> Render for Raw<T> { fn render(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.0.fmt(f) } } pub fn raw<T: Display>(t: T) -> impl Render { Raw(t) } macro_rules! raw_display { ($($ty:ty)*) => { $( impl Render for $ty { fn render(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.fmt(f) } } )* }; } raw_display! { bool char u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64 } pub fn doctype() -> impl Render { raw("<!DOCTYPE html>") }