Skip to main content

graphrecords_query/
explain.rs

1use crate::Operand;
2pub use graphrecords_macros::Explain;
3use std::fmt::{self, Display, Formatter, Write};
4
5#[diagnostic::on_unimplemented(
6    message = "`{Self}` cannot explain itself",
7    note = "implement `Explain` for `{Self}` or derive it with `#[derive(Explain)]`"
8)]
9pub trait Explain {
10    fn describe<'a>(&'a self, formatter: &mut ExplainFormatter<'a, '_>) -> fmt::Result;
11}
12
13pub trait Labeled {
14    const LABEL: &'static str;
15}
16
17impl<O: Operand> Explain for O {
18    fn describe<'a>(&'a self, formatter: &mut ExplainFormatter<'a, '_>) -> fmt::Result {
19        self.context().describe(formatter)
20    }
21}
22
23pub struct ExplainFormatter<'a, 'writer> {
24    writer: &'writer mut dyn Write,
25    children: Vec<(Option<&'static str>, &'a dyn Explain)>,
26}
27
28impl<'a> ExplainFormatter<'a, '_> {
29    pub fn child(&mut self, child: &'a dyn Explain) -> &mut Self {
30        self.children.push((None, child));
31        self
32    }
33
34    pub fn labeled_child(&mut self, label: &'static str, child: &'a dyn Explain) -> &mut Self {
35        self.children.push((Some(label), child));
36        self
37    }
38}
39
40impl Write for ExplainFormatter<'_, '_> {
41    fn write_str(&mut self, text: &str) -> fmt::Result {
42        self.writer.write_str(text)
43    }
44}
45
46pub struct Explanation<'a> {
47    root: &'a dyn Explain,
48}
49
50impl<'a> Explanation<'a> {
51    #[must_use]
52    pub fn new(root: &'a dyn Explain) -> Self {
53        Self { root }
54    }
55}
56
57impl Display for Explanation<'_> {
58    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
59        write_node(self.root, formatter, "")
60    }
61}
62
63fn write_node(node: &dyn Explain, formatter: &mut Formatter<'_>, prefix: &str) -> fmt::Result {
64    let children = {
65        let mut explain_formatter = ExplainFormatter {
66            writer: formatter,
67            children: Vec::new(),
68        };
69        node.describe(&mut explain_formatter)?;
70
71        explain_formatter.children
72    };
73
74    let count = children.len();
75
76    for (index, (label, child)) in children.into_iter().enumerate() {
77        let last = index + 1 == count;
78
79        write!(formatter, "\n{prefix}{}", if last { "└─ " } else { "├─ " })?;
80
81        if let Some(label) = label {
82            write!(formatter, "{label}: ")?;
83        }
84
85        let mut child_prefix = String::from(prefix);
86        child_prefix.push_str(if last { "   " } else { "│  " });
87        write_node(child, formatter, &child_prefix)?;
88    }
89
90    Ok(())
91}