1#![no_std]
2
3extern crate alloc;
4#[cfg(feature = "std")]
5extern crate std;
6
7mod buffer;
8pub mod either;
9pub mod escape;
10mod helpers;
11
12use alloc::string::String;
13
14pub use self::buffer::Buffer;
15use self::escape::escape_into;
16
17pub trait IntoHtml {
19 fn into_html(self) -> impl IntoHtml;
93
94 #[inline]
96 fn escape_and_write(self, buf: &mut Buffer)
97 where
98 Self: Sized,
99 {
100 self.into_html().escape_and_write(buf);
101 }
102
103 #[inline]
104 fn size_hint(&self) -> usize {
105 0
106 }
107
108 fn into_string(self) -> String
110 where
111 Self: Sized,
112 {
113 let html = self.into_html();
114 let size = html.size_hint();
115 let mut buf = Buffer::with_capacity(size + (size / 10));
116 html.escape_and_write(&mut buf);
117 buf.into_string()
118 }
119}
120
121impl IntoHtml for &str {
122 #[inline]
123 fn into_html(self) -> impl IntoHtml {
124 self
125 }
126
127 #[inline]
128 fn escape_and_write(self, buf: &mut Buffer) {
129 escape_into(buf, self)
130 }
131
132 #[inline]
133 fn size_hint(&self) -> usize {
134 self.len()
135 }
136}
137
138impl IntoHtml for char {
139 #[inline]
140 fn into_html(self) -> impl IntoHtml {
141 self
142 }
143
144 #[inline]
145 fn escape_and_write(self, buf: &mut Buffer) {
146 escape_into(buf, self.encode_utf8(&mut [0; 4]));
147 }
148
149 #[inline]
150 fn size_hint(&self) -> usize {
151 self.len_utf8()
152 }
153}
154
155impl IntoHtml for String {
156 #[inline]
157 fn into_html(self) -> impl IntoHtml {
158 self
159 }
160
161 #[inline]
162 fn escape_and_write(self, buf: &mut Buffer) {
163 escape_into(buf, &self)
164 }
165
166 #[inline]
167 fn size_hint(&self) -> usize {
168 self.len()
169 }
170}
171
172impl IntoHtml for &String {
173 #[inline]
174 fn into_html(self) -> impl IntoHtml {
175 self.as_str()
176 }
177
178 #[inline]
179 fn size_hint(&self) -> usize {
180 self.len()
181 }
182}
183
184impl IntoHtml for bool {
185 #[inline]
186 fn into_html(self) -> impl IntoHtml {
187 if self {
188 "true"
189 } else {
190 "false"
191 }
192 }
193
194 #[inline]
195 fn size_hint(&self) -> usize {
196 5
197 }
198}
199
200impl<T: IntoHtml> IntoHtml for Option<T> {
201 #[inline]
202 fn into_html(self) -> impl IntoHtml {
203 self
204 }
205
206 #[inline]
207 fn escape_and_write(self, buf: &mut Buffer) {
208 if let Some(x) = self {
209 x.escape_and_write(buf)
210 }
211 }
212
213 #[inline]
214 fn size_hint(&self) -> usize {
215 if let Some(x) = self {
216 x.size_hint()
217 } else {
218 0
219 }
220 }
221}
222
223impl IntoHtml for () {
224 #[inline]
225 fn into_html(self) -> impl IntoHtml {
226 self
227 }
228
229 #[inline]
230 fn escape_and_write(self, _: &mut Buffer) {}
231}
232
233impl<F: FnOnce(&mut Buffer)> IntoHtml for F {
234 #[inline]
235 fn into_html(self) -> impl IntoHtml {
236 self
237 }
238
239 #[inline]
240 fn escape_and_write(self, buf: &mut Buffer) {
241 (self)(buf)
242 }
243}
244
245impl<B: IntoHtml, I: ExactSizeIterator, F> IntoHtml for core::iter::Map<I, F>
246where
247 F: FnMut(I::Item) -> B,
248{
249 #[inline]
250 fn into_html(self) -> impl IntoHtml {
251 self
252 }
253
254 #[inline]
255 fn escape_and_write(self, buf: &mut Buffer) {
256 let len = self.len();
257 for (i, x) in self.enumerate() {
258 if i == 0 {
259 buf.reserve(len * x.size_hint());
260 }
261 x.escape_and_write(buf);
262 }
263 }
264}
265
266impl<T: IntoHtml> IntoHtml for alloc::vec::Vec<T> {
267 #[inline]
268 fn into_html(self) -> impl IntoHtml {
269 self
270 }
271
272 #[inline]
273 fn escape_and_write(self, buf: &mut Buffer) {
274 for x in self {
275 x.escape_and_write(buf);
276 }
277 }
278
279 #[inline]
280 fn size_hint(&self) -> usize {
281 let mut n = 0;
282 for x in self {
283 n += x.size_hint();
284 }
285 n
286 }
287}
288
289impl<T: IntoHtml, const N: usize> IntoHtml for [T; N] {
290 #[inline]
291 fn into_html(self) -> impl IntoHtml {
292 self
293 }
294
295 #[inline]
296 fn escape_and_write(self, buf: &mut Buffer) {
297 for x in self {
298 x.escape_and_write(buf);
299 }
300 }
301
302 #[inline]
303 fn size_hint(&self) -> usize {
304 let mut n = 0;
305 for x in self {
306 n += x.size_hint();
307 }
308 n
309 }
310}