1#![allow(clippy::wrong_self_convention)]
14
15use itertools::Itertools;
16use std::collections::VecDeque;
17
18#[macro_export]
19macro_rules! docvec {
20 () => {
21 Document::Vec(Vec::new())
22 };
23
24 ($($x:expr),+ $(,)?) => {
25 Document::Vec(vec![$($x.to_doc()),+])
26 };
27}
28
29pub trait Documentable<'a> {
33 fn to_doc(self) -> Document<'a>;
34}
35
36impl<'a> Documentable<'a> for char {
37 fn to_doc(self) -> Document<'a> {
38 Document::String(format!("{self}"))
39 }
40}
41
42impl<'a> Documentable<'a> for &'a str {
43 fn to_doc(self) -> Document<'a> {
44 Document::Str(self)
45 }
46}
47
48impl<'a> Documentable<'a> for isize {
49 fn to_doc(self) -> Document<'a> {
50 Document::String(format!("{self}"))
51 }
52}
53
54impl<'a> Documentable<'a> for i64 {
55 fn to_doc(self) -> Document<'a> {
56 Document::String(format!("{self}"))
57 }
58}
59
60impl<'a> Documentable<'a> for usize {
61 fn to_doc(self) -> Document<'a> {
62 Document::String(format!("{self}"))
63 }
64}
65
66impl<'a> Documentable<'a> for f64 {
67 fn to_doc(self) -> Document<'a> {
68 Document::String(format!("{self:?}"))
69 }
70}
71
72impl<'a> Documentable<'a> for u64 {
73 fn to_doc(self) -> Document<'a> {
74 Document::String(format!("{self:?}"))
75 }
76}
77
78impl<'a> Documentable<'a> for u32 {
79 fn to_doc(self) -> Document<'a> {
80 Document::String(format!("{self}"))
81 }
82}
83
84impl<'a> Documentable<'a> for u16 {
85 fn to_doc(self) -> Document<'a> {
86 Document::String(format!("{self}"))
87 }
88}
89
90impl<'a> Documentable<'a> for u8 {
91 fn to_doc(self) -> Document<'a> {
92 Document::String(format!("{self}"))
93 }
94}
95
96impl<'a> Documentable<'a> for Document<'a> {
97 fn to_doc(self) -> Document<'a> {
98 self
99 }
100}
101
102impl<'a> Documentable<'a> for Vec<Document<'a>> {
103 fn to_doc(self) -> Document<'a> {
104 Document::Vec(self)
105 }
106}
107
108impl<'a, D: Documentable<'a>> Documentable<'a> for Option<D> {
109 fn to_doc(self) -> Document<'a> {
110 self.map(Documentable::to_doc).unwrap_or_else(nil)
111 }
112}
113
114pub fn concat<'a>(docs: impl IntoIterator<Item = Document<'a>>) -> Document<'a> {
115 Document::Vec(docs.into_iter().collect())
116}
117
118pub fn join<'a>(
119 docs: impl IntoIterator<Item = Document<'a>>,
120 separator: Document<'a>,
121) -> Document<'a> {
122 concat(Itertools::intersperse(docs.into_iter(), separator))
123}
124
125#[derive(Debug, Clone, PartialEq, Eq)]
126pub enum Document<'a> {
127 Line(usize),
129
130 ForceBroken(Box<Self>),
132
133 ForceUnbroken(Box<Self>),
135
136 Break {
138 broken: &'a str,
139 unbroken: &'a str,
140 break_first: bool,
141 kind: BreakKind,
142 },
143
144 Vec(Vec<Self>),
146
147 Nest(isize, Box<Self>),
149
150 Group(Box<Self>),
152
153 String(String),
155
156 Str(&'a str),
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161enum Mode {
162 Broken,
163 Unbroken,
164
165 ForcedBroken,
171 ForcedUnbroken,
172}
173
174impl Mode {
175 fn is_forced(&self) -> bool {
176 matches!(self, Mode::ForcedBroken | Mode::ForcedUnbroken)
177 }
178}
179
180fn fits(
181 mut limit: isize,
182 mut current_width: isize,
183 mut docs: VecDeque<(isize, Mode, &Document<'_>)>,
184) -> bool {
185 loop {
186 if current_width > limit {
187 return false;
188 };
189
190 let (indent, mode, document) = match docs.pop_front() {
191 Some(x) => x,
192 None => return true,
193 };
194
195 match document {
196 Document::ForceBroken(_) => {
197 return false;
198 }
199
200 Document::Line(_) => return true,
201
202 Document::Nest(i, doc) => docs.push_front((i + indent, mode, doc)),
203
204 Document::ForceUnbroken(doc) => docs.push_front((indent, mode, doc)),
205
206 Document::Group(doc) if mode.is_forced() => docs.push_front((indent, mode, doc)),
207
208 Document::Group(doc) => docs.push_front((indent, Mode::Unbroken, doc)),
209
210 Document::Str(s) => limit -= s.len() as isize,
211
212 Document::String(s) => limit -= s.len() as isize,
213
214 Document::Break { unbroken, .. } => match mode {
215 Mode::Broken | Mode::ForcedBroken => return true,
216 Mode::Unbroken | Mode::ForcedUnbroken => current_width += unbroken.len() as isize,
217 },
218
219 Document::Vec(vec) => {
220 for doc in vec.iter().rev() {
221 docs.push_front((indent, mode, doc));
222 }
223 }
224 }
225 }
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub enum BreakKind {
230 Flex,
231 Strict,
232}
233
234fn format(
235 writer: &mut String,
236 limit: isize,
237 mut width: isize,
238 mut docs: VecDeque<(isize, Mode, &Document<'_>)>,
239) {
240 while let Some((indent, mode, document)) = docs.pop_front() {
241 match document {
242 Document::Line(i) => {
243 for _ in 0..*i {
244 writer.push('\n');
245 }
246
247 for _ in 0..indent {
248 writer.push(' ');
249 }
250
251 width = indent;
252 }
253
254 Document::Break {
256 broken,
257 unbroken,
258 break_first,
259 kind: BreakKind::Flex,
260 } => {
261 if mode == Mode::ForcedUnbroken {
262 writer.push_str(unbroken);
263 width += unbroken.len() as isize
264 } else {
265 let unbroken_width = width + unbroken.len() as isize;
266
267 if fits(limit, unbroken_width, docs.clone()) {
268 writer.push_str(unbroken);
269 width = unbroken_width;
270 continue;
271 }
272
273 if *break_first {
274 writer.push('\n');
275 for _ in 0..indent {
276 writer.push(' ');
277 }
278 writer.push_str(broken);
279 } else {
280 writer.push_str(broken);
281 writer.push('\n');
282 for _ in 0..indent {
283 writer.push(' ');
284 }
285 }
286
287 width = indent;
288 }
289 }
290
291 Document::Break {
293 broken,
294 unbroken,
295 break_first,
296 kind: BreakKind::Strict,
297 } => {
298 width = match mode {
299 Mode::Unbroken | Mode::ForcedUnbroken => {
300 writer.push_str(unbroken);
301
302 width + unbroken.len() as isize
303 }
304
305 Mode::Broken | Mode::ForcedBroken if *break_first => {
306 writer.push('\n');
307
308 for _ in 0..indent {
309 writer.push(' ');
310 }
311
312 writer.push_str(broken);
313
314 indent
315 }
316
317 Mode::Broken | Mode::ForcedBroken => {
318 writer.push_str(broken);
319
320 writer.push('\n');
321
322 for _ in 0..indent {
323 writer.push(' ');
324 }
325
326 indent
327 }
328 };
329 }
330
331 Document::String(s) => {
332 width += s.len() as isize;
333
334 writer.push_str(s);
335 }
336
337 Document::Str(s) => {
338 width += s.len() as isize;
339
340 writer.push_str(s);
341 }
342
343 Document::Vec(vec) => {
344 for doc in vec.iter().rev() {
345 docs.push_front((indent, mode, doc));
346 }
347 }
348
349 Document::Nest(i, doc) => {
350 docs.push_front((indent + i, mode, doc));
351 }
352
353 Document::Group(doc) => {
354 let mut group_docs = VecDeque::new();
355
356 let inner_mode = if mode == Mode::ForcedUnbroken {
357 Mode::ForcedUnbroken
358 } else {
359 Mode::Unbroken
360 };
361
362 group_docs.push_front((indent, inner_mode, doc.as_ref()));
363
364 if fits(limit, width, group_docs) {
365 docs.push_front((indent, inner_mode, doc));
366 } else {
367 docs.push_front((indent, Mode::Broken, doc));
368 }
369 }
370
371 Document::ForceBroken(document) => {
372 docs.push_front((indent, Mode::ForcedBroken, document));
373 }
374
375 Document::ForceUnbroken(document) => {
376 docs.push_front((indent, Mode::ForcedUnbroken, document));
377 }
378 }
379 }
380}
381
382pub fn nil<'a>() -> Document<'a> {
383 Document::Vec(vec![])
384}
385
386pub fn line<'a>() -> Document<'a> {
387 Document::Line(1)
388}
389
390pub fn lines<'a>(i: usize) -> Document<'a> {
391 Document::Line(i)
392}
393
394pub fn break_<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> {
395 Document::Break {
396 broken,
397 unbroken,
398 kind: BreakKind::Strict,
399 break_first: false,
400 }
401}
402
403pub fn prebreak<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> {
404 Document::Break {
405 broken,
406 unbroken,
407 kind: BreakKind::Strict,
408 break_first: true,
409 }
410}
411
412pub fn flex_break<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> {
413 Document::Break {
414 broken,
415 unbroken,
416 kind: BreakKind::Flex,
417 break_first: false,
418 }
419}
420
421pub fn flex_prebreak<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> {
422 Document::Break {
423 broken,
424 unbroken,
425 kind: BreakKind::Flex,
426 break_first: true,
427 }
428}
429
430impl<'a> Document<'a> {
431 pub fn fits(&self, target: isize) -> bool {
432 let mut docs = VecDeque::new();
433 docs.push_front((0, Mode::Unbroken, self));
434 fits(target, 0, docs)
435 }
436
437 pub fn group(self) -> Self {
438 Self::Group(Box::new(self))
439 }
440
441 pub fn nest(self, indent: isize) -> Self {
442 Self::Nest(indent, Box::new(self))
443 }
444
445 pub fn force_break(self) -> Self {
446 Self::ForceBroken(Box::new(self))
447 }
448
449 pub fn force_unbroken(self) -> Self {
450 Self::ForceUnbroken(Box::new(self))
451 }
452
453 pub fn append(self, second: impl Documentable<'a>) -> Self {
454 match self {
455 Self::Vec(mut vec) => {
456 vec.push(second.to_doc());
457 Self::Vec(vec)
458 }
459 first => Self::Vec(vec![first, second.to_doc()]),
460 }
461 }
462
463 pub fn to_pretty_string(self, limit: isize) -> String {
464 let mut buffer = String::new();
465
466 self.pretty_print(limit, &mut buffer);
467
468 buffer
469 }
470
471 pub fn surround(self, open: impl Documentable<'a>, closed: impl Documentable<'a>) -> Self {
472 open.to_doc().append(self).append(closed)
473 }
474
475 pub fn pretty_print(&self, limit: isize, writer: &mut String) {
476 let mut docs = VecDeque::new();
477
478 docs.push_front((0, Mode::Unbroken, self));
479
480 format(writer, limit, 0, docs);
481 }
482
483 pub fn is_empty(&self) -> bool {
486 use Document::*;
487 match self {
488 Line(n) => *n == 0,
489 String(s) => s.is_empty(),
490 Str(s) => s.is_empty(),
491 Break { broken, .. } => broken.is_empty(),
493 ForceUnbroken(d) | ForceBroken(d) | Nest(_, d) | Group(d) => d.is_empty(),
494 Vec(docs) => docs.iter().all(|d| d.is_empty()),
495 }
496 }
497}