1use std::collections::{BTreeMap, VecDeque};
11use std::fmt::{self, Debug, Write};
12use std::rc::Rc;
13
14use crate::targets::RustTarget;
15
16pub mod args;
17pub mod config;
18pub mod context;
19pub mod header;
20pub mod platforms;
21pub mod rules;
22pub mod targets;
23
24pub struct BazelBuildFile {
29 pub header: header::BazelHeader,
30 pub targets: Vec<Box<dyn RustTarget>>,
31}
32
33impl fmt::Display for BazelBuildFile {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 self.header.format(f)?;
36 for target in &self.targets {
37 writeln!(f)?;
38 target.format(f)?;
39 }
40 Ok(())
41 }
42}
43
44pub trait ToBazelDefinition: Debug {
46 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error>;
47
48 fn to_bazel_definition(&self) -> String {
49 let mut buf = String::new();
50 self.format(&mut buf).expect("failed to write into string");
51 buf
52 }
53}
54
55impl<T: ToBazelDefinition> ToBazelDefinition for Option<T> {
56 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
57 match self {
58 Some(val) => val.format(writer),
59 None => Ok(()),
60 }
61 }
62}
63
64impl ToBazelDefinition for bool {
65 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
66 let bazel_str = if *self { "True" } else { "False" };
67 writer.write_str(bazel_str)
68 }
69}
70
71struct AutoIndentingWriter<'w> {
73 level: usize,
74 should_indent: bool,
75 writer: &'w mut dyn fmt::Write,
76}
77
78impl<'w> AutoIndentingWriter<'w> {
79 fn new(writer: &'w mut dyn fmt::Write) -> Self {
80 AutoIndentingWriter {
81 level: 0,
82 should_indent: true,
83 writer,
84 }
85 }
86
87 fn indent(&mut self) -> AutoIndentingWriter<'_> {
88 AutoIndentingWriter {
89 level: self.level + 1,
90 should_indent: self.should_indent,
91 writer: self.writer,
92 }
93 }
94}
95
96impl<'w> fmt::Write for AutoIndentingWriter<'w> {
97 fn write_str(&mut self, s: &str) -> fmt::Result {
98 let lines = s.split_inclusive('\n');
99
100 for line in lines {
101 if self.should_indent {
102 for _ in 0..self.level {
103 self.writer.write_char('\t')?;
104 }
105 }
106
107 self.writer.write_str(line)?;
108 self.should_indent = line.ends_with('\n');
109 }
110
111 Ok(())
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
124pub struct QuotedString(String);
125
126impl QuotedString {
127 pub fn new(s: impl Into<String>) -> Self {
128 QuotedString(s.into())
129 }
130
131 pub fn unquoted(&self) -> &str {
133 &self.0
134 }
135}
136
137impl ToBazelDefinition for QuotedString {
138 fn format(&self, writer: &mut dyn Write) -> Result<(), fmt::Error> {
139 write!(writer, "\"{}\"", self.0)?;
140 Ok(())
141 }
142}
143
144impl<T: ToString> From<T> for QuotedString {
145 fn from(value: T) -> Self {
146 QuotedString(value.to_string())
147 }
148}
149
150#[derive(Debug, Clone)]
162pub struct Field<T> {
163 name: String,
164 value: T,
165}
166
167impl<T> Field<T> {
168 pub fn new(name: impl Into<String>, value: T) -> Self {
169 Field {
170 name: name.into(),
171 value,
172 }
173 }
174
175 pub fn name(&self) -> &str {
176 &self.name
177 }
178}
179
180impl<T: ToBazelDefinition> ToBazelDefinition for Field<T> {
181 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
182 write!(writer, "{} = ", self.name)?;
183 self.value.format(writer)?;
184 writeln!(writer, ",")?;
185
186 Ok(())
187 }
188}
189
190#[derive(Debug, Clone)]
199pub struct List<T> {
200 items: Vec<T>,
201 objects: Vec<Rc<dyn ToBazelDefinition>>,
202}
203
204impl<T> List<T> {
205 pub fn new<E: Into<T>, I: IntoIterator<Item = E>>(items: I) -> Self {
206 List {
207 items: items.into_iter().map(Into::into).collect(),
208 objects: Vec::new(),
209 }
210 }
211
212 pub fn empty() -> Self {
213 List::new(VecDeque::<T>::new())
214 }
215
216 pub fn concat_other(mut self, other: impl ToBazelDefinition + 'static) -> Self {
223 self.objects.push(Rc::new(other));
224 self
225 }
226
227 pub fn push_front<E: Into<T>>(&mut self, val: E) {
229 self.items.insert(0, val.into())
230 }
231
232 pub fn push_back<E: Into<T>>(&mut self, val: E) {
234 self.items.push(val.into())
235 }
236
237 pub fn extend<E: Into<T>, I: IntoIterator<Item = E>>(&mut self, vals: I) {
239 self.items.extend(vals.into_iter().map(Into::into))
240 }
241
242 pub fn iter(&self) -> impl Iterator<Item = &T> {
244 self.items.iter()
245 }
246
247 pub fn is_empty(&self) -> bool {
249 self.items.is_empty() && self.objects.is_empty()
250 }
251}
252
253impl<A, B, T> From<T> for List<A>
254where
255 B: Into<A>,
256 T: IntoIterator<Item = B>,
257{
258 fn from(value: T) -> Self {
259 List::from_iter(value.into_iter().map(|x| x.into()))
260 }
261}
262
263impl<A> FromIterator<A> for List<A> {
264 fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
265 List {
266 items: iter.into_iter().collect(),
267 objects: Vec::new(),
268 }
269 }
270}
271
272impl<T: ToBazelDefinition> ToBazelDefinition for List<T> {
273 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
274 let mut w = AutoIndentingWriter::new(writer);
275
276 match &self.items[..] {
277 [] => write!(w, "[]")?,
278 [one] => write!(w, "[{}]", one.to_bazel_definition())?,
279 multiple => {
280 write!(w, "[")?;
281 for item in multiple {
282 let mut w = w.indent();
283 writeln!(w)?;
284 write!(w, "{},", item.to_bazel_definition())?;
285 }
286 write!(w, "\n]")?;
287 }
288 }
289
290 for o in &self.objects {
291 let def = o.to_bazel_definition();
292 if !def.is_empty() {
293 write!(w, " + {def}")?;
294 }
295 }
296
297 Ok(())
298 }
299}
300
301#[derive(Debug)]
311pub struct Dict<K, V> {
312 items: BTreeMap<K, V>,
313}
314
315impl<K, V> Dict<K, V> {
316 pub fn new<M, N, I>(vals: I) -> Self
317 where
318 M: Into<K>,
319 N: Into<V>,
320 I: IntoIterator<Item = (M, N)>,
321 K: Ord,
322 {
323 Dict {
324 items: vals
325 .into_iter()
326 .map(|(m, n)| (m.into(), n.into()))
327 .collect(),
328 }
329 }
330
331 pub fn empty() -> Self {
332 Dict {
333 items: BTreeMap::default(),
334 }
335 }
336
337 pub fn insert<M, N>(&mut self, key: M, val: N)
338 where
339 M: Into<K>,
340 N: Into<V>,
341 K: Ord,
342 {
343 self.items.insert(key.into(), val.into());
344 }
345
346 pub fn extend<M, N, I>(&mut self, vals: I)
347 where
348 M: Into<K>,
349 N: Into<V>,
350 I: IntoIterator<Item = (M, N)>,
351 K: Ord,
352 {
353 self.items
354 .extend(vals.into_iter().map(|(k, v)| (k.into(), v.into())));
355 }
356}
357
358impl<K: ToBazelDefinition, V: ToBazelDefinition> ToBazelDefinition for Dict<K, V> {
359 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
360 let mut w = AutoIndentingWriter::new(writer);
361
362 match self.items.len() {
363 0 => write!(w, "{{}}")?,
364 1 => {
365 let (key, val) = self.items.iter().next().expect("checked length");
366 write!(
367 w,
368 "{{ {}: {} }}",
369 key.to_bazel_definition(),
370 val.to_bazel_definition()
371 )?;
372 }
373 _ => {
374 write!(w, "{{")?;
375 for (key, val) in &self.items {
376 let mut w = w.indent();
377 writeln!(w)?;
378 write!(
379 w,
380 "{{ {}: {} }}",
381 key.to_bazel_definition(),
382 val.to_bazel_definition()
383 )?;
384 }
385 write!(w, "\n}}")?;
386 }
387 }
388
389 Ok(())
390 }
391}
392
393#[derive(Debug)]
395pub struct FileGroup {
396 name: Field<QuotedString>,
397 files: Field<List<QuotedString>>,
398}
399
400impl FileGroup {
401 pub fn new<S: Into<String>>(
402 name: impl Into<String>,
403 files: impl IntoIterator<Item = S>,
404 ) -> Self {
405 let name = Field::new("name", QuotedString::new(name.into()));
406 let files = Field::new(
407 "srcs",
408 files.into_iter().map(|f| QuotedString::new(f)).collect(),
409 );
410
411 FileGroup { name, files }
412 }
413}
414
415impl ToBazelDefinition for FileGroup {
416 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
417 let mut w = AutoIndentingWriter::new(writer);
418
419 writeln!(w, "filegroup(")?;
420 {
421 let mut w = w.indent();
422 self.name.format(&mut w)?;
423 self.files.format(&mut w)?;
424 }
425 writeln!(w, ")")?;
426
427 Ok(())
428 }
429}
430
431#[derive(Debug)]
433pub struct Alias {
434 name: Field<QuotedString>,
435 actual: Field<QuotedString>,
436}
437
438impl Alias {
439 pub fn new<N: Into<String>, A: Into<String>>(name: N, actual: A) -> Self {
440 let name = Field::new("name", QuotedString::new(name.into()));
441 let actual = Field::new("actual", QuotedString::new(actual.into()));
442
443 Alias { name, actual }
444 }
445}
446
447impl ToBazelDefinition for Alias {
448 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
449 let mut w = AutoIndentingWriter::new(writer);
450
451 writeln!(w, "alias(")?;
452 {
453 let mut w = w.indent();
454 self.name.format(&mut w)?;
455 self.actual.format(&mut w)?;
456 }
457 writeln!(w, ")")?;
458
459 Ok(())
460 }
461}
462
463#[derive(Debug)]
467pub struct Glob {
468 includes: List<QuotedString>,
469}
470
471impl Glob {
472 pub fn new<E, I>(globs: I) -> Glob
473 where
474 E: Into<QuotedString>,
475 I: IntoIterator<Item = E>,
476 {
477 Glob {
478 includes: List::new(globs),
479 }
480 }
481}
482
483impl ToBazelDefinition for Glob {
484 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
485 write!(writer, "glob(")?;
486 self.includes.format(writer)?;
487 write!(writer, ")")?;
488
489 Ok(())
490 }
491}
492
493#[derive(Debug)]
511pub struct Select<T> {
512 entries: BTreeMap<String, T>,
513 default: T,
514}
515
516impl<T> Select<T> {
517 pub fn new<E, I, J>(entires: I, default: E) -> Select<T>
518 where
519 E: Into<T>,
520 J: ToBazelDefinition,
521 I: IntoIterator<Item = (J, E)>,
522 {
523 Select {
524 entries: entires
525 .into_iter()
526 .map(|(variant, entry)| (variant.to_bazel_definition(), entry.into()))
527 .collect(),
528 default: default.into(),
529 }
530 }
531}
532
533impl<T: ToBazelDefinition> ToBazelDefinition for Select<T> {
534 fn format(&self, writer: &mut dyn fmt::Write) -> Result<(), fmt::Error> {
535 let mut w = AutoIndentingWriter::new(writer);
536
537 writeln!(w, "select({{")?;
538 {
539 let mut w = w.indent();
540 for (variant, entry) in &self.entries {
541 write!(w, "{variant}")?;
542 write!(w, ": ")?;
543 entry.format(&mut w)?;
544 writeln!(w, ",")?;
545 }
546
547 write!(w, "\"//conditions:default\": ")?;
548 self.default.format(&mut w)?;
549 writeln!(w, ",")?;
550 }
551 write!(w, "}})")?;
552
553 Ok(())
554 }
555}