1pub use rust_html_macros::rhtml;
2
3pub mod integration;
4
5#[derive(Debug, Clone, Eq, PartialEq)]
27pub struct Template {
28 content: TemplateContent,
29}
30
31#[derive(Debug, Clone, Eq, PartialEq)]
36pub struct TemplateGroup(pub Vec<Template>);
37
38#[derive(Debug, Clone)]
55pub struct Unescaped(pub String);
56
57pub trait Render {
63 fn render(&self) -> Template;
64}
65
66#[derive(Debug, Clone, Eq, PartialEq)]
67enum TemplateContent {
68 RawString(String),
69 WithParameters {
70 template_parts: Vec<(&'static str, Template)>,
71 template_end: &'static str,
72 },
73}
74
75impl Template {
76 pub fn build_internal(
84 template_parts: Vec<(&'static str, Template)>,
85 template_end: &'static str,
86 ) -> Self {
87 Template {
88 content: TemplateContent::WithParameters {
89 template_parts,
90 template_end,
91 },
92 }
93 }
94 fn build(&self) -> String {
96 match &self.content {
97 TemplateContent::RawString(value) => value.to_owned(),
98 TemplateContent::WithParameters {
99 template_parts,
100 template_end,
101 } => {
102 if template_parts.is_empty() {
103 return template_end.to_string();
104 }
105 let mut output: Vec<String> = Vec::with_capacity(template_parts.len() * 2 + 1);
106 for (html_part, param_part) in template_parts.iter() {
107 output.push(html_part.to_string());
108 output.push(param_part.build());
109 }
110 output.push(template_end.to_string());
111 output.join("")
112 }
113 }
114 }
115}
116
117impl Render for Template {
118 fn render(&self) -> Template {
119 self.clone()
120 }
121}
122
123impl Render for Unescaped {
124 fn render(&self) -> Template {
125 Template {
126 content: TemplateContent::RawString(self.0.to_owned()),
127 }
128 }
129}
130
131impl Render for TemplateGroup {
132 fn render(&self) -> Template {
133 let string: String = self
134 .0
135 .iter()
136 .map(|template| template.build())
137 .collect::<Vec<_>>()
138 .join("");
139 Template {
140 content: TemplateContent::RawString(string),
141 }
142 }
143}
144
145impl<I> From<I> for TemplateGroup
146where
147 I: IntoIterator<Item = Template>,
148{
149 fn from(value: I) -> Self {
150 TemplateGroup(value.into_iter().collect())
151 }
152}
153
154impl std::iter::FromIterator<Template> for TemplateGroup {
155 fn from_iter<T: IntoIterator<Item = Template>>(iter: T) -> Self {
156 TemplateGroup(iter.into_iter().collect())
157 }
158}
159
160impl<T> Render for T
161where
162 T: std::fmt::Display,
163{
164 fn render(&self) -> Template {
165 let string = self.to_string();
166 let escaped_value = html_escape::encode_safe(&string);
167 Template {
168 content: TemplateContent::RawString(escaped_value.into()),
169 }
170 }
171}
172
173impl From<Template> for String {
174 fn from(value: Template) -> Self {
175 value.build()
176 }
177}
178
179impl<T> From<T> for Template
180where
181 T: std::fmt::Display,
182{
183 fn from(value: T) -> Self {
184 Render::render(&value)
185 }
186}