1use super::context::{BindgenContext, ItemId};
4use super::traversal::Trace;
5use std::fs::File;
6use std::io::{self, Write};
7use std::path::Path;
8
9pub(crate) trait DotAttributes {
12 fn dot_attributes<W>(
15 &self,
16 ctx: &BindgenContext,
17 out: &mut W,
18 ) -> io::Result<()>
19 where
20 W: Write;
21}
22
23pub(crate) fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
25where
26 P: AsRef<Path>,
27{
28 let file = File::create(path)?;
29 let mut dot_file = io::BufWriter::new(file);
30 writeln!(&mut dot_file, "digraph {{")?;
31
32 let mut err: Option<io::Result<_>> = None;
33
34 for (id, item) in ctx.items() {
35 let is_allowlisted = ctx.allowlisted_items().contains(&id);
36
37 writeln!(
38 &mut dot_file,
39 r#"{} [fontname="courier", color={}, label=< <table border="0" align="left">"#,
40 id.as_usize(),
41 if is_allowlisted { "black" } else { "gray" }
42 )?;
43 item.dot_attributes(ctx, &mut dot_file)?;
44 writeln!(&mut dot_file, r#"</table> >];"#)?;
45
46 item.trace(
47 ctx,
48 &mut |sub_id: ItemId, edge_kind| {
49 if err.is_some() {
50 return;
51 }
52
53 match writeln!(
54 &mut dot_file,
55 "{} -> {} [label={edge_kind:?}, color={}];",
56 id.as_usize(),
57 sub_id.as_usize(),
58 if is_allowlisted { "black" } else { "gray" }
59 ) {
60 Ok(_) => {}
61 Err(e) => err = Some(Err(e)),
62 }
63 },
64 &(),
65 );
66
67 if let Some(err) = err {
68 return err;
69 }
70
71 if let Some(module) = item.as_module() {
72 for child in module.children() {
73 writeln!(
74 &mut dot_file,
75 "{} -> {} [style=dotted, color=gray]",
76 item.id().as_usize(),
77 child.as_usize()
78 )?;
79 }
80 }
81 }
82
83 writeln!(&mut dot_file, "}}")?;
84 Ok(())
85}