1use crate::Selection;
17use crate::selection::LabelKey;
18use crate::selection::SelectionSYM;
19use crate::shape;
20
21pub struct SelectionPretty(String);
42
43impl std::fmt::Display for SelectionPretty {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 f.write_str(&self.0)
46 }
47}
48
49impl SelectionSYM for SelectionPretty {
50 fn false_() -> Self {
51 SelectionPretty("false_()".into())
52 }
53 fn true_() -> Self {
54 SelectionPretty("true_()".into())
55 }
56 fn all(s: Self) -> Self {
57 SelectionPretty(format!("all({})", s.0))
58 }
59 fn first(s: Self) -> Self {
60 SelectionPretty(format!("first({})", s.0))
61 }
62 fn range<R: Into<shape::Range>>(range: R, s: Self) -> Self {
63 let r = range.into();
64 SelectionPretty(format!("range({}, {})", r, s.0))
65 }
66 fn label<L: Into<LabelKey>>(labels: Vec<L>, s: Self) -> Self {
67 let labels_str = labels
68 .into_iter()
69 .map(|l| l.into().to_string())
70 .collect::<Vec<_>>()
71 .join(", ");
72 SelectionPretty(format!("label([{}], {})", labels_str, s.0))
73 }
74 fn any(s: Self) -> Self {
75 SelectionPretty(format!("any({})", s.0))
76 }
77 fn intersection(a: Self, b: Self) -> Self {
78 SelectionPretty(format!("intersection({}, {})", a.0, b.0))
79 }
80 fn union(a: Self, b: Self) -> Self {
81 SelectionPretty(format!("union({}, {})", a.0, b.0))
82 }
83}
84
85pub fn pretty(selection: &Selection) -> SelectionPretty {
103 selection.fold()
104}
105
106pub struct SelectionCompact(String);
138
139impl std::fmt::Display for SelectionCompact {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 f.write_str(&self.0)
142 }
143}
144
145impl SelectionSYM for SelectionCompact {
146 fn true_() -> Self {
147 SelectionCompact("".into())
148 }
149
150 fn false_() -> Self {
151 panic!("SelectionCompact: `false` has no compact surface syntax")
152 }
153
154 fn first(_: Self) -> Self {
155 panic!("SelectionCompact: `first` has no compact surface syntax")
156 }
157
158 fn all(s: Self) -> Self {
159 if s.0.is_empty() {
160 SelectionCompact("*".into())
161 } else {
162 SelectionCompact(format!("*,{}", s.0))
163 }
164 }
165
166 fn range<R: Into<shape::Range>>(range: R, s: Self) -> Self {
167 let r = range.into();
168 let range_str = match (r.0, r.1, r.2) {
169 (start, Some(end), 1) => format!("{}:{}", start, end),
170 (start, Some(end), step) => format!("{}:{}:{}", start, end, step),
171 (start, None, step) => format!("{}::{}", start, step),
172 };
173 if s.0.is_empty() {
174 SelectionCompact(range_str)
175 } else {
176 SelectionCompact(format!("{},{}", range_str, s.0))
177 }
178 }
179
180 fn label<L: Into<LabelKey>>(labels: Vec<L>, s: Self) -> Self {
181 let label_str = labels
182 .into_iter()
183 .map(|l| l.into().to_string())
184 .collect::<Vec<_>>()
185 .join(",");
186 if s.0.is_empty() {
187 panic!("SelectionCompact: label requires a combinator like '*', '?', or a range");
188 }
189 SelectionCompact(format!("[{}]{}", label_str, s.0))
190 }
191
192 fn any(s: Self) -> Self {
193 if s.0.is_empty() {
194 SelectionCompact("?".into())
195 } else {
196 SelectionCompact(format!("?,{}", s.0))
197 }
198 }
199
200 fn intersection(a: Self, b: Self) -> Self {
201 SelectionCompact(format!("({}&{})", a.0, b.0))
202 }
203
204 fn union(a: Self, b: Self) -> Self {
205 SelectionCompact(format!("({}|{})", a.0, b.0))
206 }
207}
208
209pub fn compact(selection: &Selection) -> SelectionCompact {
225 selection.fold()
226}
227
228#[cfg(test)]
229mod tests {
230 use crate::assert_round_trip;
231 use crate::selection::Selection;
232 use crate::shape;
233
234 #[test]
235 fn test_selection_to_compact_and_back() {
236 use crate::selection::dsl::*;
237
238 assert_round_trip!(all(true_()));
239 assert_round_trip!(all(all(true_())));
240 assert_round_trip!(all(all(all(true_()))));
241
242 assert_round_trip!(range(shape::Range(4, Some(8), 1), true_()));
243 assert_round_trip!(range(shape::Range(4, None, 1), true_()));
244 assert_round_trip!(range(shape::Range(4, Some(5), 1), true_()));
245 assert_round_trip!(range(shape::Range(0, None, 1), true_()));
246
247 assert_round_trip!(range(0, range(0, range(0, true_()))));
248 assert_round_trip!(range(1, range(1, range(1, true_()))));
249 assert_round_trip!(all(range(0, true_())));
250 assert_round_trip!(all(range(0, all(true_()))));
251
252 assert_round_trip!(all(all(range(4.., true_()))));
253 assert_round_trip!(all(all(range(shape::Range(1, None, 2), true_()))));
254
255 assert_round_trip!(union(
256 all(all(range(0..4, true_()))),
257 all(all(range(shape::Range(4, None, 1), true_()))),
258 ));
259 assert_round_trip!(union(
260 all(range(0, range(0..4, true_()))),
261 all(range(1, range(4..8, true_()))),
262 ));
263 assert_round_trip!(union(
264 all(all(range(0..2, true_()))),
265 all(all(range(shape::Range(6, None, 1), true_()))),
266 ));
267 assert_round_trip!(union(
268 all(all(range(shape::Range(1, Some(4), 2), true_()))),
269 all(all(range(shape::Range(5, None, 2), true_()))),
270 ));
271 assert_round_trip!(intersection(all(true_()), all(true_())));
272 assert_round_trip!(intersection(all(true_()), all(all(range(4..8, true_())))));
273 assert_round_trip!(intersection(
274 all(all(range(0..5, true_()))),
275 all(all(range(4..8, true_()))),
276 ));
277
278 assert_round_trip!(any(any(any(true_()))));
279 assert_round_trip!(range(0, any(range(0..4, true_()))));
280 assert_round_trip!(range(0, any(true_())));
281 assert_round_trip!(any(true_()));
282 assert_round_trip!(union(
283 range(0, range(0, any(true_()))),
284 range(0, range(0, any(true_()))),
285 ));
286 assert_round_trip!(union(all(all(range(1..4, true_()))), range(5..6, true_())));
287 assert_round_trip!(all(all(union(range(1..4, true_()), range(5..6, true_())))));
288 assert_round_trip!(all(union(
289 range(shape::Range(1, Some(4), 1), all(true_())),
290 range(shape::Range(5, Some(6), 1), all(true_())),
291 )));
292 assert_round_trip!(intersection(all(all(all(true_()))), all(all(all(true_()))),));
293 assert_round_trip!(intersection(
294 range(0, all(all(true_()))),
295 range(0, union(range(1, all(true_())), range(3, all(true_())))),
296 ));
297 assert_round_trip!(intersection(
298 all(all(union(
299 range(0..2, true_()),
300 range(shape::Range(6, None, 1), true_()),
301 ))),
302 all(all(range(shape::Range(4, None, 1), true_()))),
303 ));
304 assert_round_trip!(range(1..4, range(2, true_())));
305
306 }
310}