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