credence_lib/render/catalog/
annotation.rs

1use super::{super::super::util::*, columns::*};
2
3use {
4    compris::{annotate::*, normal::*},
5    std::cmp::*,
6};
7
8//
9// CatalogAnnotation
10//
11
12/// Catalog annotation.
13pub struct CatalogAnnotation<'own> {
14    /// Sort column.
15    pub sort_column: Option<RefTraversal<'own, WithAnnotations>>,
16
17    /// Sort ascending.
18    pub sort_ascending: bool,
19
20    /// Extra columns.
21    pub extra_columns: ExtraColumns<'own>,
22}
23
24impl<'own> CatalogAnnotation<'own> {
25    /// Constructor.
26    pub fn new(
27        sort_column: Option<RefTraversal<'own, WithAnnotations>>,
28        sort_ascending: bool,
29        extra_columns: ExtraColumns<'own>,
30    ) -> Self {
31        Self { sort_column, sort_ascending, extra_columns }
32    }
33
34    /// Resolve.
35    pub fn resolve(variant: &'own Variant<WithAnnotations>) -> Self {
36        let extra_columns = flatten_columns(
37            traverse!(variant, "columns").and_then(
38                |columns| {
39                    if let Variant::Map(map) = columns { Some(map) } else { None }
40                },
41            ),
42        );
43
44        let (sort_column, sort_ascending) = traverse!(variant, "sort")
45            .and_then(|sort| match sort {
46                Variant::Map(map) => Some((
47                    map.inner.get(&"column".into()).and_then(to_ref_traversal),
48                    map.inner
49                        .get(&"ascending".into())
50                        .map(|ascending| match ascending {
51                            Variant::Boolean(ascending) => ascending.inner,
52                            _ => true,
53                        })
54                        .unwrap_or(true),
55                )),
56
57                Variant::List(_) | Variant::Text(_) => Some((to_ref_traversal(sort), true)),
58
59                _ => None,
60            })
61            .unwrap_or((None, true));
62
63        Self::new(sort_column, sort_ascending, extra_columns)
64    }
65
66    /// Sort rows by column.
67    pub fn sort(self, rows: &mut Vec<Variant<WithAnnotations>>) {
68        let ascending = self.sort_ascending;
69        let sort_column = self.into_sort_column();
70        rows.sort_by(|row1, row2| cmp_rows_by_column(row1, row2, &sort_column, ascending));
71    }
72
73    /// Into sort column (defaults to "title").
74    fn into_sort_column(self) -> Traversal<WithAnnotations> {
75        self.sort_column.map(to_traversal).unwrap_or_else(|| vec!["title".into()])
76    }
77}
78
79fn cmp_rows_by_column<AnnotatedT>(
80    row1: &Variant<AnnotatedT>,
81    row2: &Variant<AnnotatedT>,
82    column_path: &Traversal<AnnotatedT>,
83    ascending: bool,
84) -> Ordering {
85    if let Some(a) = row1.traverse(column_path.iter())
86        && let Some(b) = row2.traverse(column_path.iter())
87    {
88        let ordering = cmp_variant_lowercase(a, b);
89        if ascending { ordering } else { ordering.reverse() }
90    } else {
91        Ordering::Less
92    }
93}