1use std::fmt::{self, Write};
2
3use crate::bound::Bound;
4
5use crate::r#type::Type;
6
7const DEFAULT_INDENT: usize = 4;
8
9#[derive(Debug)]
11pub struct Formatter<'a> {
12 dst: &'a mut String,
14
15 spaces: usize,
17
18 indent: usize,
20}
21
22impl<'a> Formatter<'a> {
23 pub fn new(dst: &'a mut String) -> Self {
25 Formatter {
26 dst,
27 spaces: 0,
28 indent: DEFAULT_INDENT,
29 }
30 }
31
32 pub fn block<F>(&mut self, f: F) -> fmt::Result
34 where
35 F: FnOnce(&mut Self) -> fmt::Result,
36 {
37 if !self.is_start_of_line() {
38 write!(self, " ")?;
39 }
40
41 write!(self, "{{\n")?;
42 self.indent(f)?;
43 write!(self, "}}\n")?;
44 Ok(())
45 }
46
47 pub fn indent<F, R>(&mut self, f: F) -> R
49 where
50 F: FnOnce(&mut Self) -> R,
51 {
52 self.spaces += self.indent;
53 let ret = f(self);
54 self.spaces -= self.indent;
55 ret
56 }
57
58 pub fn is_start_of_line(&self) -> bool {
60 self.dst.is_empty() || self.dst.as_bytes().last() == Some(&b'\n')
61 }
62
63 fn push_spaces(&mut self) {
64 for _ in 0..self.spaces {
65 self.dst.push_str(" ");
66 }
67 }
68}
69
70impl<'a> fmt::Write for Formatter<'a> {
71 fn write_str(&mut self, s: &str) -> fmt::Result {
72 let mut first = true;
73 let mut should_indent = self.is_start_of_line();
74
75 for line in s.lines() {
76 if !first {
77 self.dst.push_str("\n");
78 }
79
80 first = false;
81
82 let do_indent = should_indent && !line.is_empty() && line.as_bytes()[0] != b'\n';
83
84 if do_indent {
85 self.push_spaces();
86 }
87
88 should_indent = true;
90
91 self.dst.push_str(line);
92 }
93
94 if s.as_bytes().last() == Some(&b'\n') {
95 self.dst.push_str("\n");
96 }
97
98 Ok(())
99 }
100}
101
102pub fn fmt_generics(generics: &[String], fmt: &mut Formatter<'_>) -> fmt::Result {
104 if !generics.is_empty() {
105 write!(fmt, "<")?;
106
107 for (i, ty) in generics.iter().enumerate() {
108 if i != 0 {
109 write!(fmt, ", ")?
110 }
111 write!(fmt, "{}", ty)?;
112 }
113
114 write!(fmt, ">")?;
115 }
116
117 Ok(())
118}
119
120pub fn fmt_bounds(bounds: &[Bound], fmt: &mut Formatter<'_>) -> fmt::Result {
122 if !bounds.is_empty() {
123 write!(fmt, "\n")?;
124
125 write!(fmt, "where {}: ", bounds[0].name)?;
127 fmt_bound_rhs(&bounds[0].bound, fmt)?;
128 write!(fmt, ",\n")?;
129
130 for bound in &bounds[1..] {
131 write!(fmt, " {}: ", bound.name)?;
132 fmt_bound_rhs(&bound.bound, fmt)?;
133 write!(fmt, ",\n")?;
134 }
135 }
136
137 Ok(())
138}
139
140pub fn fmt_bound_rhs(tys: &[Type], fmt: &mut Formatter<'_>) -> fmt::Result {
142 for (i, ty) in tys.iter().enumerate() {
143 if i != 0 {
144 write!(fmt, " + ")?
145 }
146 ty.fmt(fmt)?;
147 }
148
149 Ok(())
150}