nbindgen/bindgen/
writer.rs1use std::cmp;
6use std::io;
7use std::io::Write;
8
9use crate::bindgen::config::Config;
10use crate::bindgen::Bindings;
11
12pub enum ListType<'a> {
14 Join(&'a str),
16 Cap(&'a str),
18}
19
20pub struct NullFile;
23impl Write for NullFile {
24 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
25 Ok(buf.len())
26 }
27 fn flush(&mut self) -> io::Result<()> {
28 Ok(())
29 }
30}
31
32struct InnerWriter<'a, 'b: 'a, F: 'a + Write>(&'a mut SourceWriter<'b, F>);
34
35impl<'a, 'b, F: Write> Write for InnerWriter<'a, 'b, F> {
36 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
37 let writer = &mut self.0;
38
39 if !writer.line_started {
40 for _ in 0..writer.spaces() {
41 write!(writer.out, " ").unwrap();
42 }
43 writer.line_started = true;
44 writer.line_length += writer.spaces();
45 }
46
47 let written = writer.out.write(buf)?;
48 writer.line_length += written;
49 writer.max_line_length = cmp::max(writer.max_line_length, writer.line_length);
50 Ok(written)
51 }
52
53 fn flush(&mut self) -> io::Result<()> {
54 self.0.out.flush()
55 }
56}
57
58pub struct SourceWriter<'a, F: Write> {
60 out: F,
61 bindings: &'a Bindings,
62 spaces: Vec<usize>,
63 line_started: bool,
64 line_length: usize,
65 line_number: usize,
66 max_line_length: usize,
67}
68pub type MeasureWriter<'a> = SourceWriter<'a, NullFile>;
69
70impl<'a, F: Write> SourceWriter<'a, F> {
71 pub fn new(out: F, bindings: &'a Bindings) -> Self {
72 SourceWriter {
73 out,
74 bindings,
75 spaces: vec![0],
76 line_started: false,
77 line_length: 0,
78 line_number: 1,
79 max_line_length: 0,
80 }
81 }
82
83 pub fn bindings(&self) -> &Bindings {
84 &self.bindings
85 }
86
87 pub fn measure<T>(&self, func: T) -> usize
90 where
91 T: Fn(&mut MeasureWriter),
92 {
93 let mut measurer = SourceWriter {
94 out: NullFile,
95 bindings: self.bindings,
96 spaces: self.spaces.clone(),
97 line_started: self.line_started,
98 line_length: self.line_length,
99 line_number: self.line_number,
100 max_line_length: self.line_length,
101 };
102
103 func(&mut measurer);
104
105 measurer.max_line_length
106 }
107
108 fn spaces(&self) -> usize {
109 *self.spaces.last().unwrap()
110 }
111
112 pub fn push_set_spaces(&mut self, spaces: usize) {
113 self.spaces.push(spaces);
114 }
115
116 pub fn line_length_for_align(&self) -> usize {
117 if self.line_started {
118 self.line_length
119 } else {
120 self.line_length + self.spaces()
121 }
122 }
123
124 pub fn pop_tab(&mut self) {
125 assert!(!self.spaces.is_empty());
126 self.spaces.pop();
127 }
128
129 pub fn new_line(&mut self) {
130 writeln!(self.out).unwrap();
131 self.line_started = false;
132 self.line_length = 0;
133 self.line_number += 1;
134 }
135
136 pub fn new_line_if_not_start(&mut self) {
137 if self.line_number != 1 {
138 self.new_line();
139 }
140 }
141
142 pub fn indent(&mut self) {
143 self.push_set_spaces(self.spaces() + 2);
144 }
145
146 pub fn dedent(&mut self) {
147 self.push_set_spaces(self.spaces() - 2);
148 }
149
150 pub fn write(&mut self, text: &'static str) {
151 write!(self, "{}", text);
152 }
153
154 pub fn write_raw_block(&mut self, block: &str) {
155 self.new_line();
156 self.line_started = true;
157 write!(self, "{}", block);
158 }
159
160 pub fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) {
161 InnerWriter(self).write_fmt(fmt).unwrap();
162 }
163
164 pub fn write_horizontal_source_list<'b, S: Source>(
165 &mut self,
166 items: &[S],
167 list_type: ListType<'b>,
168 ) {
169 for (i, ref item) in items.iter().enumerate() {
170 item.write(&self.bindings.config, self);
171
172 match list_type {
173 ListType::Join(text) => {
174 if i != items.len() - 1 {
175 write!(self, "{}", text);
176 }
177 }
178 ListType::Cap(text) => {
179 write!(self, "{}", text);
180 }
181 }
182 }
183 }
184
185 pub fn write_vertical_source_list<'b, S: Source>(
186 &mut self,
187 items: &[S],
188 list_type: ListType<'b>,
189 ) {
190 let align_length = self.line_length_for_align();
191 self.push_set_spaces(align_length);
192 for (i, ref item) in items.iter().enumerate() {
193 item.write(&self.bindings.config, self);
194
195 match list_type {
196 ListType::Join(text) => {
197 if i != items.len() - 1 {
198 write!(self, "{}", text);
199 }
200 }
201 ListType::Cap(text) => {
202 write!(self, "{}", text);
203 }
204 }
205
206 if i != items.len() - 1 {
207 self.new_line();
208 }
209 }
210 self.pop_tab();
211 }
212}
213
214pub trait Source {
215 fn write<F: Write>(&self, config: &Config, _: &mut SourceWriter<F>);
216}