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