cbindgen/bindgen/
writer.rs1use std::cmp;
6use std::io;
7use std::io::Write;
8
9use crate::bindgen::config::{Braces, Language};
10use crate::bindgen::language_backend::LanguageBackend;
11use crate::bindgen::Bindings;
12
13pub enum ListType<'a> {
15 Join(&'a str),
17 Cap(&'a str),
19}
20
21struct InnerWriter<'a, 'b: 'a, F: 'a + Write>(&'a mut SourceWriter<'b, F>);
23
24impl<F: Write> Write for InnerWriter<'_, '_, F> {
25 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
26 let writer = &mut self.0;
27
28 if !writer.line_started {
29 for _ in 0..writer.spaces() {
30 write!(writer.out, " ").unwrap();
31 }
32 writer.line_started = true;
33 writer.line_length += writer.spaces();
34 }
35
36 let written = writer.out.write(buf)?;
37 writer.line_length += written;
38 writer.max_line_length = cmp::max(writer.max_line_length, writer.line_length);
39 Ok(written)
40 }
41
42 fn flush(&mut self) -> io::Result<()> {
43 self.0.out.flush()
44 }
45}
46
47pub struct SourceWriter<'a, F: Write> {
49 out: F,
50 bindings: &'a Bindings,
51 spaces: Vec<usize>,
52 line_started: bool,
53 line_length: usize,
54 line_number: usize,
55 max_line_length: usize,
56}
57
58pub type MeasureWriter<'a> = SourceWriter<'a, &'a mut Vec<u8>>;
59
60impl<'a, F: Write> SourceWriter<'a, F> {
61 pub fn new(out: F, bindings: &'a Bindings) -> Self {
62 SourceWriter {
63 out,
64 bindings,
65 spaces: vec![0],
66 line_started: false,
67 line_length: 0,
68 line_number: 1,
69 max_line_length: 0,
70 }
71 }
72
73 pub fn bindings(&self) -> &Bindings {
74 self.bindings
75 }
76
77 pub fn try_write<T>(&mut self, func: T, max_line_length: usize) -> bool
80 where
81 T: FnOnce(&mut MeasureWriter),
82 {
83 if self.line_length > max_line_length {
84 return false;
85 }
86
87 let mut buffer = Vec::new();
88 let line_length = {
89 let mut measurer = SourceWriter {
90 out: &mut buffer,
91 bindings: self.bindings,
92 spaces: self.spaces.clone(),
93 line_started: self.line_started,
94 line_length: self.line_length,
95 line_number: self.line_number,
96 max_line_length: self.line_length,
97 };
98
99 func(&mut measurer);
100
101 measurer.max_line_length
102 };
103
104 if line_length > max_line_length {
105 return false;
106 }
107 self.line_started = true;
110 InnerWriter(self).write_all(&buffer).unwrap();
111 true
112 }
113
114 fn spaces(&self) -> usize {
115 *self.spaces.last().unwrap()
116 }
117
118 pub fn push_set_spaces(&mut self, spaces: usize) {
119 self.spaces.push(spaces);
120 }
121
122 pub fn pop_set_spaces(&mut self) {
123 self.pop_tab()
124 }
125
126 pub fn line_length_for_align(&self) -> usize {
127 if self.line_started {
128 self.line_length
129 } else {
130 self.line_length + self.spaces()
131 }
132 }
133
134 pub fn push_tab(&mut self) {
135 let spaces = self.spaces() - (self.spaces() % self.bindings.config.tab_width)
136 + self.bindings.config.tab_width;
137 self.spaces.push(spaces);
138 }
139
140 pub fn pop_tab(&mut self) {
141 assert!(!self.spaces.is_empty());
142 self.spaces.pop();
143 }
144
145 pub fn new_line(&mut self) {
146 self.out
147 .write_all(self.bindings.config.line_endings.as_str().as_bytes())
148 .unwrap();
149 self.line_started = false;
150 self.line_length = 0;
151 self.line_number += 1;
152 }
153
154 pub fn new_line_if_not_start(&mut self) {
155 if self.line_number != 1 {
156 self.new_line();
157 }
158 }
159
160 pub fn open_brace(&mut self) {
161 match self.bindings.config.language {
162 Language::Cxx | Language::C => match self.bindings.config.braces {
163 Braces::SameLine => {
164 self.write(" {");
165 self.push_tab();
166 self.new_line();
167 }
168 Braces::NextLine => {
169 self.new_line();
170 self.write("{");
171 self.push_tab();
172 self.new_line();
173 }
174 },
175 Language::Cython => {
176 self.write(":");
177 self.new_line();
178 self.push_tab();
179 }
180 }
181 }
182
183 pub fn close_brace(&mut self, semicolon: bool) {
184 self.pop_tab();
185 match self.bindings.config.language {
186 Language::Cxx | Language::C => {
187 self.new_line();
188 if semicolon {
189 self.write("};");
190 } else {
191 self.write("}");
192 }
193 }
194 Language::Cython => {}
195 }
196 }
197
198 pub fn write(&mut self, text: &'static str) {
199 write!(self, "{text}");
200 }
201
202 pub fn write_raw_block(&mut self, block: &str) {
203 self.line_started = true;
204 write!(self, "{block}");
205 }
206
207 pub fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) {
208 InnerWriter(self).write_fmt(fmt).unwrap();
209 }
210
211 pub fn write_horizontal_source_list<
212 LB: LanguageBackend,
213 S,
214 WF: Fn(&mut LB, &mut SourceWriter<F>, &S),
215 >(
216 &mut self,
217 language_backend: &mut LB,
218 items: &[S],
219 list_type: ListType<'_>,
220 writer: WF,
221 ) {
222 for (i, item) in items.iter().enumerate() {
223 writer(language_backend, self, item);
224
225 match list_type {
226 ListType::Join(text) => {
227 if i != items.len() - 1 {
228 write!(self, "{text}");
229 }
230 }
231 ListType::Cap(text) => {
232 write!(self, "{text}");
233 }
234 }
235 }
236 }
237
238 pub fn write_vertical_source_list<
239 LB: LanguageBackend,
240 S,
241 WF: Fn(&mut LB, &mut SourceWriter<F>, &S),
242 >(
243 &mut self,
244 language_backend: &mut LB,
245 items: &[S],
246 list_type: ListType<'_>,
247 writer: WF,
248 ) {
249 let align_length = self.line_length_for_align();
250 self.push_set_spaces(align_length);
251 for (i, item) in items.iter().enumerate() {
252 writer(language_backend, self, item);
253
254 match list_type {
255 ListType::Join(text) => {
256 if i != items.len() - 1 {
257 write!(self, "{text}");
258 }
259 }
260 ListType::Cap(text) => {
261 write!(self, "{text}");
262 }
263 }
264
265 if i != items.len() - 1 {
266 self.new_line();
267 }
268 }
269 self.pop_tab();
270 }
271}