1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
use std::io::Write;

/// # Trait, which enables you to write a dot file
/// * similar to `Dot` trait, but lables are generated differently
/// * Dot files can be used to visualize a graph
/// * To visualize, you can use something like
/// ```dot
/// twopi dotfile.dot -Tpdf > dotfile.pdf
/// circo dotfile.dot -Tpdf > dotfile.pdf
/// ```
/// You can also try some of the other [roadmaps](https://www.graphviz.org/).
pub trait DotExtra<T, A>{

    /// * create a dot representation
    /// * you can use the indices and the container `A` (usually stored at each
    ///     index) to create the lables
    fn dot_from_container_index<F, S1, S2, W>(&self, writer: W, dot_options: S1, f: F)
        -> Result<(), std::io::Error>
        where
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(usize, &A) -> S2,
            W: Write;

    /// * same as `self.dot_string_from_container_index` but returns String instead
    fn dot_string_from_container_index<F, S1, S2>(&self, dot_options: S1, f: F)
        -> String
        where
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(usize, &A) -> S2
    {
        let mut s = Vec::new();
        self.dot_from_container_index(
            &mut s,
            dot_options,
            f
        ).unwrap();
        String::from_utf8(s).unwrap()
    }

    /// * create a dot representation
    /// * you can use the information of the container `A` (usually stored at each
    ///     index) to create the lables
    fn dot_from_container<F, S1, S2, W>(&self, writer: W, dot_options: S1, mut f: F)
        -> Result<(), std::io::Error>
        where
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(&A) -> S2,
            W: Write
    {
        self.dot_from_container_index(
            writer,
            dot_options,
            |_, a| f(a)
        )
    }

    /// * same as `self.dot_from_container` but returns String instead
    fn dot_string_from_container<F, S1, S2>(&self, dot_options: S1, f: F)
        -> String
        where
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(&A) -> S2
    {
        let mut s = Vec::<u8>::new();
        self.dot_from_container(
            &mut s,
            dot_options,
            f
        ).unwrap();
        String::from_utf8(s).unwrap()
    }

    /// * create a dot representation
    /// * you can use the indices and `T` (usually something contained in `A` (see `dot_from_container`)
    ///   and stored at each vertex) to create the lables
    fn dot_from_contained_index<F, S1, S2, W>(&self, writer: W, dot_options: S1, f: F)
        -> Result<(), std::io::Error>
        where
            W: Write,
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(usize, &T) -> S2;

    /// * same as `self.dot_from_contained` but returns String instead
    fn dot_string_from_contained_index<F, S1, S2>(&self, dot_options: S1, f: F)
        -> String
        where
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(usize, &T) -> S2
    {
        let mut s = Vec::<u8>::new();
        self.dot_from_contained_index(
            &mut s,
            dot_options,
            f
        ).unwrap();
        String::from_utf8(s).unwrap()
    }

    /// * create a dot representation
    /// * you can use `T` (usually something contained in `A` (see `dot_from_container`)
    ///   and stored at each vertex) to create the lables
    fn dot_from_contained<F, S1, S2, W>(&self, writer: W, dot_options: S1, mut f: F)
        -> Result<(), std::io::Error>
        where
            W: Write,
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(&T) -> S2
    {
        self.dot_from_contained_index(
            writer,
            dot_options,
            |_, c| f(c)
        )
    }

    /// * same as `self.dot_from_contained` but returns String
    fn dot_string_from_contained<F, S1, S2>(&self, dot_options: S1, f: F)
        -> String
        where
            S1: AsRef<str>,
            S2: AsRef<str>,
            F: FnMut(&T) -> S2
    {
        let mut s = Vec::<u8>::new();
        self.dot_from_contained(
            &mut s,
            dot_options,
            f
        ).unwrap();
        String::from_utf8(s).unwrap()
    }
}

/// # Trait, which enables you to write a dot file
/// * Dot files can be used to visualize a graph
/// * To visualize, you can use something like
/// ```dot
/// twopi dotfile.dot -Tpdf > dotfile.pdf
/// circo dotfile.dot -Tpdf > dotfile.pdf
/// ```
/// You can also try some of the other [roadmaps](https://www.graphviz.org/).
pub trait Dot {

    /// * use function `f` to create labels depending on the index
    /// * for valid `dot_options` use `dot_options!` macro and take a look at module `dot_constants`
    fn dot_from_indices<F, W, S1, S2>(&self, writer: W, dot_options: S1, f: F)
        -> Result<(), std::io::Error>
    where
        S1: AsRef<str>,
        S2: AsRef<str>,
        W: Write,
        F: FnMut(usize) -> S2;

    /// * same as `self.dot_from_indices` but returns String instead
    fn dot_string_from_indices<F, S1, S2>(&self, dot_options: S1, f: F)
        -> String
    where
        S1: AsRef<str>,
        S2: AsRef<str>,
        F: FnMut(usize) -> S2
    {
        let mut s = Vec::new();
        self.dot_from_indices(
            &mut s,
            dot_options,
            f
        ).unwrap();
        String::from_utf8(s).unwrap()
    }

    /// * use index as labels for the nodes
    /// * default implementation uses `dot_from_indices`
    fn dot_with_indices<S, W>(
        &self, writer: W,
        dot_options: S
    ) -> Result<(), std::io::Error>
    where
        S: AsRef<str>,
        W: Write
    {
        self.dot_from_indices(
            writer,
            dot_options,
            |index| {
                index.to_string()
            }
        )
    }

    /// * same as `self.dot_with_indices` but returns String instead
    fn dot_string_with_indices<S>(&self, dot_options: S) -> String
        where
            S: AsRef<str>
    {
        let mut s = Vec::<u8>::new();
        self.dot_with_indices(
            &mut s,
            dot_options
        ).unwrap();
        String::from_utf8(s).unwrap()
    }

    /// * create dot file with empty labels
    /// * default implementation uses `dot_from_indices`
    fn dot<S, W>(&self, writer: W, dot_options: S) -> Result<(), std::io::Error>
        where
            S: AsRef<str>,
            W: Write
    {
        self.dot_from_indices(
            writer,
            dot_options,
            |_| {
                ""
            }
        )
    }

    /// * same as `self.dot()`, but returns a String instead
    fn dot_string<S>(&self, dot_options: S) -> String
        where
            S: AsRef<str>
    {
        let mut s = Vec::<u8>::new();
        self.dot(&mut s, dot_options).unwrap();
        String::from_utf8(s).unwrap()
    }
}