daab/diagnostics/
visgraph.rs

1
2
3use super::CanBase;
4use super::Doctor;
5use super::BuilderHandle;
6use super::ArtifactHandle;
7
8use std::io::Write;
9
10
11/// Output options for `VisgrapDoc`.
12///
13/// **Notice: This struc is only available if the `diagnostics` feature has been activated**.
14///
15/// This struct contains outputting options for the `VisgraphDoc`.
16///
17/// It has a `Default` impl with the following value:
18/// ```
19/// # use daab::diagnostics::VisgraphDocOptions;
20/// // Value of default()
21/// let opts = VisgraphDocOptions {
22///     show_builder_values: false,
23///     show_artifact_values: true,
24/// };
25/// assert_eq!(opts, VisgraphDocOptions::default());
26/// ```
27///
28#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29pub struct VisgraphDocOptions {
30	/// Configures whether builders should be only visualized by their
31	/// value (`true`) instead of by their type (`false`)
32	/// .
33	pub show_builder_values: bool,
34	
35	/// Configures whether artifacts should be only visualized by their
36	/// value (`true`) instead of by their type (`false`)
37	pub show_artifact_values: bool,
38}
39
40impl Default for VisgraphDocOptions {
41	fn default() -> Self {
42		VisgraphDocOptions {
43			show_builder_values: false,
44			show_artifact_values: true,
45		}
46	}
47}
48
49/// Debugger outputting Visgraph dot file.
50///
51/// **Notice: This struct is only available if the `diagnostics` feature has been activated**.
52///
53/// The Visgraph Doctor generates a DOT graph about the dependencies of
54/// the builders and generated artifacts.
55///
56/// ## Example
57///
58/// ```no_run
59/// use std::fs::File;
60/// use daab::rc::Cache;
61/// use daab::diagnostics::{VisgraphDoc, VisgraphDocOptions};
62///
63/// let mut cache = Cache::new_with_doctor(
64///     VisgraphDoc::new(
65///         VisgraphDocOptions {
66///             show_builder_values: false,
67///             show_artifact_values: true,
68///         },
69///         File::create("test-graph.dot").unwrap()
70///     )
71/// );
72///
73/// //...
74/// ```
75///
76/// Example output in [DOT format]:
77///
78/// ```text
79/// strict digraph { graph [labeljust = l];
80///   "0x7faf30003960" [label = "alloc::rc::Rc<daab::test::BuilderSimpleNode>"]
81///   "0x7faf30005090" [label = "alloc::rc::Rc<daab::test::BuilderLeaf>"]
82///   "0x7faf30003960" -> "0x7faf30005090"
83///   "0x7faf30005090" [label = "alloc::rc::Rc<daab::test::BuilderLeaf>"]
84///   "0.0-0x7faf30015710" [label = "#0.0 daab::test::Leaf :
85/// Leaf {
86///     id: 0,
87/// }", shape = box]
88///   "0x7faf30005090" -> "0.0-0x7faf30015710" [arrowhead = "none"]
89/// }
90/// ```
91///
92///[DOT format]: https://en.wikipedia.org/wiki/DOT_%28graph_description_language%29
93///
94pub struct VisgraphDoc<W: Write> {
95	/// Output options
96	opts: VisgraphDocOptions,
97	
98	/// Output Write
99	output: Option<W>,
100	
101	/// Counts (generation, instance) of artifacts
102	/// It is used to making each artifact unique.
103	/// The generation increases whenever a artifact might be recreated
104	/// i.e. after a call to `clear()` or `invalidate()`.
105	count: (u64, u64),
106}
107
108impl<W: Write> VisgraphDoc<W> {
109	/// Creates a new Visgraph Doctor
110	///
111	pub fn new(opts: VisgraphDocOptions,
112		mut output: W) -> Self {
113		
114		writeln!(output, "strict digraph {{ graph [labeljust = l];").unwrap();
115		
116		VisgraphDoc {
117			opts,
118			output: Some(output),
119			count: (0, 0),
120		}
121	}
122	
123	/// Strigify given builder entry.
124	fn builder_str<'a, BCan>(&self, builder: &'a BuilderHandle<BCan>) -> &'a str {
125		if self.opts.show_builder_values {
126			&builder.dbg_text
127		} else {
128			builder.type_name
129		}
130	}
131	
132	fn output(&mut self) -> &mut W {
133		self.output.as_mut().unwrap()
134	}
135	
136	fn finish(&mut self) {
137		writeln!(self.output(), "}}").unwrap();
138	}
139	
140	/// Dismantles this struct and returns the inner `Write`.
141	///
142	pub fn into_inner(mut self) -> W {
143		self.finish();
144		self.output.take().unwrap()
145	}
146}
147
148impl<W: Write> Drop for VisgraphDoc<W> {
149	fn drop(&mut self) {
150		if self.output.is_some() {
151			self.finish();
152		}
153	}
154}
155
156impl<ArtCan: CanBase, BCan, W: Write> Doctor<ArtCan, BCan> for VisgraphDoc<W> {
157	fn resolve(&mut self, builder: &BuilderHandle<BCan>, used: &BuilderHandle<BCan>) {
158
159		let s = self.builder_str(builder);
160		writeln!(self.output(),
161			r#"  "{:p}" [label = {:?}]"#,
162			builder.id(),
163			s
164		).unwrap();
165
166		let s = self.builder_str(used);
167		writeln!(self.output(),
168			r#"  "{:p}" [label = {:?}]"#,
169			used.id(),
170			s
171		).unwrap();
172
173		writeln!(self.output(),
174			r#"  "{:p}" -> "{:p}""#,
175			builder.id(),
176			used.id()
177		).unwrap();
178
179		self.output().flush().unwrap();
180
181	}
182	
183	
184	fn build(&mut self, builder: &BuilderHandle<BCan>, artifact: &ArtifactHandle<ArtCan>) {
185		let count = self.count;
186		
187		let s = self.builder_str(builder);
188		writeln!(self.output(),
189			r#"  "{:p}" [label = {:?}]"#,
190			builder.id(),
191			s
192		).unwrap();
193		
194		let s = if self.opts.show_artifact_values {
195			format!(" :\n{}", artifact.dbg_text)
196		} else {
197			"".into()
198		};
199		
200		writeln!(self.output(),
201			r##"  "{0}.{1}-{2:p}" [label = "#{0}.{1} {3}{4}", shape = box]"##,
202			count.0,
203			count.1,
204			artifact.value.can_as_ptr(),
205			artifact.type_name,
206			s
207		).unwrap();
208			
209		writeln!(self.output(),
210			r#"  "{:p}" -> "{}.{}-{:p}" [arrowhead = "none"]"#,
211			builder.id(),
212			count.0,
213			count.1,
214			artifact.value.can_as_ptr()
215		).unwrap();
216		
217		self.output().flush().unwrap();
218			
219		
220		self.count.1 += 1;
221		
222	}
223	
224	fn clear(&mut self) {
225		// Generations inc
226		self.count.0 += 1;
227		self.count.1 = 0;
228	}
229	
230	fn invalidate(&mut self, _builder: &BuilderHandle<BCan>) {
231		// Generations inc
232		self.count.0 += 1;
233		self.count.1 = 0;
234	}
235}
236
237
238