mz_repr/explain/
dot.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Structs and traits for `EXPLAIN AS DOT`.
11
12use crate::explain::*;
13
14/// A trait implemented by explanation types that can be rendered as
15/// [`ExplainFormat::Dot`].
16pub trait DisplayDot<C = ()>
17where
18    Self: Sized,
19{
20    fn fmt_dot(&self, f: &mut fmt::Formatter<'_>, ctx: &mut C) -> fmt::Result;
21}
22
23impl<A, C> DisplayDot<C> for Box<A>
24where
25    A: DisplayDot<C>,
26{
27    fn fmt_dot(&self, f: &mut fmt::Formatter<'_>, ctx: &mut C) -> fmt::Result {
28        self.as_ref().fmt_dot(f, ctx)
29    }
30}
31
32impl<A, C> DisplayDot<C> for Option<A>
33where
34    A: DisplayDot<C>,
35{
36    fn fmt_dot(&self, f: &mut fmt::Formatter<'_>, ctx: &mut C) -> fmt::Result {
37        if let Some(val) = self {
38            val.fmt_dot(f, ctx)
39        } else {
40            fmt::Result::Ok(())
41        }
42    }
43}
44
45impl DisplayDot for UnsupportedFormat {
46    fn fmt_dot(&self, _f: &mut fmt::Formatter<'_>, _ctx: &mut ()) -> fmt::Result {
47        unreachable!()
48    }
49}
50
51/// Render a type `t: T` as [`ExplainFormat::Dot`].
52///
53/// # Panics
54///
55/// Panics if the [`DisplayDot::fmt_dot`] call returns a [`fmt::Error`].
56pub fn dot_string<T: DisplayDot<()>>(t: &T) -> String {
57    struct DotString<'a, T>(&'a T);
58
59    impl<'a, T: DisplayDot> fmt::Display for DotString<'a, T> {
60        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61            self.0.fmt_dot(f, &mut ())
62        }
63    }
64
65    DotString::<'_>(t).to_string()
66}
67
68/// Apply `f: F` to create a rendering context of type `C` and render the given
69/// type `t: T` as [`ExplainFormat::Dot`] within that context.
70///
71/// # Panics
72///
73/// Panics if the [`DisplayDot::fmt_dot`] call returns a [`fmt::Error`].
74pub fn dot_string_at<'a, T: DisplayDot<C>, C, F: Fn() -> C>(t: &'a T, f: F) -> String {
75    struct DotStringAt<'a, T, C, F: Fn() -> C> {
76        t: &'a T,
77        f: F,
78    }
79
80    impl<T: DisplayDot<C>, C, F: Fn() -> C> DisplayDot<()> for DotStringAt<'_, T, C, F> {
81        fn fmt_dot(&self, f: &mut fmt::Formatter<'_>, _ctx: &mut ()) -> fmt::Result {
82            let mut ctx = (self.f)();
83            self.t.fmt_dot(f, &mut ctx)
84        }
85    }
86
87    dot_string(&DotStringAt { t, f })
88}