1#[cfg(feature = "termcolor")]
145pub extern crate termcolor;
146extern crate typed_arena;
147
148use std::borrow::Cow;
149use std::fmt;
150use std::io;
151use std::ops::Deref;
152#[cfg(feature = "termcolor")]
153use termcolor::{ColorSpec, WriteColor};
154
155mod render;
156
157#[cfg(feature = "termcolor")]
158pub use self::render::TermColored;
159pub use self::render::{FmtWrite, IoWrite, Render, RenderAnnotated};
160
161#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
167pub enum Doc<'a, T, A = ()> {
168 Nil,
169 Append(T, T),
170 Group(T),
171 Nest(usize, T),
172 Space,
173 Newline,
174 Text(Cow<'a, str>),
175 Annotated(A, T),
176}
177
178impl<'a, T, A> Doc<'a, T, A> {
179 #[inline]
181 pub fn nil() -> Doc<'a, T, A> {
182 Doc::Nil
183 }
184
185 #[inline]
189 pub fn as_string<U: ToString>(data: U) -> Doc<'a, T, A> {
190 Doc::text(data.to_string())
191 }
192
193 #[inline]
195 pub fn newline() -> Doc<'a, T, A> {
196 Doc::Newline
197 }
198
199 #[inline]
201 pub fn text<U: Into<Cow<'a, str>>>(data: U) -> Doc<'a, T, A> {
202 Doc::Text(data.into())
203 }
204
205 #[inline]
207 pub fn space() -> Doc<'a, T, A> {
208 Doc::Space
209 }
210}
211
212impl<'a, A> Doc<'a, BoxDoc<'a, A>, A> {
213 #[inline]
215 pub fn append<D>(self, that: D) -> Doc<'a, BoxDoc<'a, A>, A>
216 where
217 D: Into<Doc<'a, BoxDoc<'a, A>, A>>,
218 {
219 DocBuilder(&BOX_ALLOCATOR, self).append(that).into()
220 }
221
222 #[inline]
224 pub fn concat<I>(docs: I) -> Doc<'a, BoxDoc<'a, A>, A>
225 where
226 I: IntoIterator,
227 I::Item: Into<Doc<'a, BoxDoc<'a, A>, A>>,
228 {
229 docs.into_iter().fold(Doc::nil(), |a, b| a.append(b))
230 }
231
232 #[inline]
237 pub fn intersperse<I, S>(docs: I, separator: S) -> Doc<'a, BoxDoc<'a, A>, A>
238 where
239 I: IntoIterator,
240 I::Item: Into<Doc<'a, BoxDoc<'a, A>, A>>,
241 S: Into<Doc<'a, BoxDoc<'a, A>, A>> + Clone,
242 A: Clone,
243 {
244 let mut result = Doc::nil();
245 let mut iter = docs.into_iter();
246
247 if let Some(first) = iter.next() {
248 result = result.append(first);
249
250 for doc in iter {
251 result = result.append(separator.clone());
252 result = result.append(doc);
253 }
254 }
255
256 result
257 }
258
259 #[inline]
266 pub fn group(self) -> Doc<'a, BoxDoc<'a, A>, A> {
267 DocBuilder(&BOX_ALLOCATOR, self).group().into()
268 }
269
270 #[inline]
272 pub fn nest(self, offset: usize) -> Doc<'a, BoxDoc<'a, A>, A> {
273 DocBuilder(&BOX_ALLOCATOR, self).nest(offset).into()
274 }
275
276 #[inline]
277 pub fn annotate(self, ann: A) -> Doc<'a, BoxDoc<'a, A>, A> {
278 DocBuilder(&BOX_ALLOCATOR, self).annotate(ann).into()
279 }
280}
281
282impl<'a, T, A, S> From<S> for Doc<'a, T, A>
283where
284 S: Into<Cow<'a, str>>,
285{
286 fn from(s: S) -> Doc<'a, T, A> {
287 Doc::Text(s.into())
288 }
289}
290
291pub struct Pretty<'a, T, A>
292where
293 A: 'a,
294 T: 'a,
295{
296 doc: &'a Doc<'a, T, A>,
297 width: usize,
298}
299
300impl<'a, T, A> fmt::Display for Pretty<'a, T, A>
301where
302 T: Deref<Target = Doc<'a, T, A>>,
303{
304 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305 self.doc.render_fmt(self.width, f)
306 }
307}
308
309impl<'a, T, A> Doc<'a, T, A> {
310 #[inline]
312 pub fn render<'b, W>(&'b self, width: usize, out: &mut W) -> io::Result<()>
313 where
314 T: Deref<Target = Doc<'b, T, A>>,
315 W: ?Sized + io::Write,
316 {
317 self.render_raw(width, &mut IoWrite::new(out))
318 }
319
320 #[inline]
322 pub fn render_fmt<'b, W>(&'b self, width: usize, out: &mut W) -> fmt::Result
323 where
324 T: Deref<Target = Doc<'b, T, A>>,
325 W: ?Sized + fmt::Write,
326 {
327 self.render_raw(width, &mut FmtWrite::new(out))
328 }
329
330 #[inline]
332 pub fn render_raw<'b, W>(&'b self, width: usize, out: &mut W) -> Result<(), W::Error>
333 where
334 T: Deref<Target = Doc<'b, T, A>>,
335 W: ?Sized + render::RenderAnnotated<A>,
336 {
337 render::best(self, width, out)
338 }
339
340 #[inline]
350 pub fn pretty<'b>(&'b self, width: usize) -> Pretty<'b, T, A>
351 where
352 T: Deref<Target = Doc<'b, T, A>>,
353 {
354 Pretty { doc: self, width }
355 }
356}
357
358#[cfg(feature = "termcolor")]
359impl<'a, T> Doc<'a, T, ColorSpec> {
360 #[inline]
361 pub fn render_colored<'b, W>(&'b self, width: usize, out: W) -> io::Result<()>
362 where
363 T: Deref<Target = Doc<'b, T, ColorSpec>>,
364 W: WriteColor,
365 {
366 render::best(self, width, &mut TermColored::new(out))
367 }
368}
369
370#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
371pub struct BoxDoc<'a, A>(Box<Doc<'a, BoxDoc<'a, A>, A>>);
372
373impl<'a, A> fmt::Debug for BoxDoc<'a, A>
374where
375 A: fmt::Debug,
376{
377 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
378 self.0.fmt(f)
379 }
380}
381
382impl<'a, A> BoxDoc<'a, A> {
383 fn new(doc: Doc<'a, BoxDoc<'a, A>, A>) -> BoxDoc<'a, A> {
384 BoxDoc(Box::new(doc))
385 }
386}
387
388impl<'a, A> Deref for BoxDoc<'a, A> {
389 type Target = Doc<'a, BoxDoc<'a, A>, A>;
390
391 fn deref(&self) -> &Self::Target {
392 &self.0
393 }
394}
395
396#[derive(Eq, Ord, PartialEq, PartialOrd)]
399pub struct DocBuilder<'a, D, A = ()>(pub &'a D, pub Doc<'a, D::Doc, A>)
400where
401 D: ?Sized + DocAllocator<'a, A> + 'a;
402
403impl<'a, A, D> Clone for DocBuilder<'a, D, A>
404where
405 A: Clone,
406 D: DocAllocator<'a, A> + 'a,
407 D::Doc: Clone,
408{
409 fn clone(&self) -> Self {
410 DocBuilder(self.0, self.1.clone())
411 }
412}
413
414impl<'a, D, A> Into<Doc<'a, D::Doc, A>> for DocBuilder<'a, D, A>
415where
416 D: ?Sized + DocAllocator<'a, A>,
417{
418 fn into(self) -> Doc<'a, D::Doc, A> {
419 self.1
420 }
421}
422
423pub trait DocAllocator<'a, A = ()> {
425 type Doc: Deref<Target = Doc<'a, Self::Doc, A>>;
426
427 fn alloc(&'a self, Doc<'a, Self::Doc, A>) -> Self::Doc;
428
429 #[inline]
431 fn nil(&'a self) -> DocBuilder<'a, Self, A> {
432 DocBuilder(self, Doc::Nil)
433 }
434
435 #[inline]
437 fn newline(&'a self) -> DocBuilder<'a, Self, A> {
438 DocBuilder(self, Doc::Newline)
439 }
440
441 #[inline]
443 fn space(&'a self) -> DocBuilder<'a, Self, A> {
444 DocBuilder(self, Doc::Space)
445 }
446
447 #[inline]
451 fn as_string<U: ToString>(&'a self, data: U) -> DocBuilder<'a, Self, A> {
452 self.text(data.to_string())
453 }
454
455 #[inline]
459 fn text<U: Into<Cow<'a, str>>>(&'a self, data: U) -> DocBuilder<'a, Self, A> {
460 DocBuilder(self, Doc::Text(data.into()))
461 }
462
463 #[inline]
465 fn concat<I>(&'a self, docs: I) -> DocBuilder<'a, Self, A>
466 where
467 I: IntoIterator,
468 I::Item: Into<Doc<'a, Self::Doc, A>>,
469 {
470 docs.into_iter().fold(self.nil(), |a, b| a.append(b))
471 }
472
473 #[inline]
478 fn intersperse<I, S>(&'a self, docs: I, separator: S) -> DocBuilder<'a, Self, A>
479 where
480 I: IntoIterator,
481 I::Item: Into<Doc<'a, Self::Doc, A>>,
482 S: Into<Doc<'a, Self::Doc, A>> + Clone,
483 {
484 let mut result = self.nil();
485 let mut iter = docs.into_iter();
486
487 if let Some(first) = iter.next() {
488 result = result.append(first);
489
490 for doc in iter {
491 result = result.append(separator.clone());
492 result = result.append(doc);
493 }
494 }
495
496 result
497 }
498}
499
500impl<'a, 's, D, A> DocBuilder<'a, D, A>
501where
502 D: ?Sized + DocAllocator<'a, A>,
503{
504 #[inline]
506 pub fn append<E>(self, that: E) -> DocBuilder<'a, D, A>
507 where
508 E: Into<Doc<'a, D::Doc, A>>,
509 {
510 let DocBuilder(allocator, this) = self;
511 let that = that.into();
512 let doc = match (this, that) {
513 (Doc::Nil, that) => that,
514 (this, Doc::Nil) => this,
515 (this, that) => Doc::Append(allocator.alloc(this), allocator.alloc(that)),
516 };
517 DocBuilder(allocator, doc)
518 }
519
520 #[inline]
527 pub fn group(self) -> DocBuilder<'a, D, A> {
528 let DocBuilder(allocator, this) = self;
529 DocBuilder(allocator, Doc::Group(allocator.alloc(this)))
530 }
531
532 #[inline]
534 pub fn nest(self, offset: usize) -> DocBuilder<'a, D, A> {
535 if offset == 0 {
536 return self;
537 }
538 let DocBuilder(allocator, this) = self;
539 DocBuilder(allocator, Doc::Nest(offset, allocator.alloc(this)))
540 }
541
542 #[inline]
543 pub fn annotate(self, ann: A) -> DocBuilder<'a, D, A> {
544 let DocBuilder(allocator, this) = self;
545 DocBuilder(allocator, Doc::Annotated(ann, allocator.alloc(this)))
546 }
547}
548
549#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
551pub struct RefDoc<'a, A: 'a>(&'a Doc<'a, RefDoc<'a, A>, A>);
552
553impl<'a, A> fmt::Debug for RefDoc<'a, A>
554where
555 A: fmt::Debug,
556{
557 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558 self.0.fmt(f)
559 }
560}
561
562impl<'a, A> Deref for RefDoc<'a, A> {
563 type Target = Doc<'a, RefDoc<'a, A>, A>;
564
565 fn deref(&self) -> &Self::Target {
566 &self.0
567 }
568}
569
570pub type Arena<'a, A = ()> = typed_arena::Arena<Doc<'a, RefDoc<'a, A>, A>>;
572
573impl<'a, D, A> DocAllocator<'a, A> for &'a D
574where
575 D: ?Sized + DocAllocator<'a, A>,
576{
577 type Doc = D::Doc;
578
579 #[inline]
580 fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc {
581 (**self).alloc(doc)
582 }
583}
584
585impl<'a, A> DocAllocator<'a, A> for Arena<'a, A> {
586 type Doc = RefDoc<'a, A>;
587
588 #[inline]
589 fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc {
590 RefDoc(match doc {
591 Doc::Nil => &Doc::Nil,
594 Doc::Space => &Doc::Space,
595 Doc::Newline => &Doc::Newline,
596 _ => Arena::alloc(self, doc),
597 })
598 }
599}
600
601pub struct BoxAllocator;
602
603static BOX_ALLOCATOR: BoxAllocator = BoxAllocator;
604
605impl<'a, A> DocAllocator<'a, A> for BoxAllocator {
606 type Doc = BoxDoc<'a, A>;
607
608 #[inline]
609 fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc {
610 BoxDoc::new(doc)
611 }
612}
613
614#[cfg(test)]
615mod tests {
616 use super::*;
617
618 macro_rules! test {
619 ($size:expr, $actual:expr, $expected:expr) => {
620 let mut s = String::new();
621 $actual.render_fmt($size, &mut s).unwrap();
622 assert_eq!(s, $expected);
623 };
624 ($actual:expr, $expected:expr) => {
625 test!(70, $actual, $expected)
626 };
627 }
628
629 #[test]
630 fn box_doc_inference() {
631 let doc = Doc::<_>::group(
632 Doc::text("test")
633 .append(Doc::space())
634 .append(Doc::text("test")),
635 );
636
637 test!(doc, "test test");
638 }
639
640 #[test]
641 fn newline_in_text() {
642 let doc = Doc::<_>::group(
643 Doc::text("test").append(
644 Doc::space()
645 .append(Doc::text("\"test\n test\""))
646 .nest(4),
647 ),
648 );
649
650 test!(5, doc, "test\n \"test\n test\"");
651 }
652
653 #[test]
654 fn forced_newline() {
655 let doc = Doc::<_>::group(
656 Doc::text("test")
657 .append(Doc::newline())
658 .append(Doc::text("test")),
659 );
660
661 test!(doc, "test\ntest");
662 }
663
664 #[test]
665 fn space_do_not_reset_pos() {
666 let doc = Doc::<_>::group(Doc::text("test").append(Doc::space()))
667 .append(Doc::text("test"))
668 .append(Doc::group(Doc::space()).append(Doc::text("test")));
669
670 test!(9, doc, "test test\ntest");
671 }
672
673 #[test]
676 fn newline_does_not_cause_next_line_to_be_to_long() {
677 let doc = Doc::<_>::group(
678 Doc::text("test").append(Doc::newline()).append(
679 Doc::text("test")
680 .append(Doc::space())
681 .append(Doc::text("test")),
682 ),
683 );
684
685 test!(6, doc, "test\ntest\ntest");
686 }
687
688 #[test]
689 fn block() {
690 let doc = Doc::<_>::group(
691 Doc::text("{")
692 .append(
693 Doc::space()
694 .append(Doc::text("test"))
695 .append(Doc::space())
696 .append(Doc::text("test"))
697 .nest(2),
698 )
699 .append(Doc::space())
700 .append(Doc::text("}")),
701 );
702
703 test!(5, doc, "{\n test\n test\n}");
704 }
705
706 #[test]
707 fn annotation_no_panic() {
708 let doc = Doc::group(
709 Doc::text("test")
710 .annotate(())
711 .append(Doc::newline())
712 .annotate(())
713 .append(Doc::text("test")),
714 );
715
716 test!(doc, "test\ntest");
717 }
718}