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
use {
    crate::{
        col::Col,
        order::Order,
    },
    lfs_core::Mount,
    std::{
        error,
        fmt,
        str::FromStr,
    },
};

/// Sorting directive: the column and the order (asc or desc)
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Sorting {
    col: Col,
    order: Order,
}

impl Default for Sorting {
    fn default() -> Self {
        let col = Col::default_sort_col();
        let order = col.default_sort_order();
        Self { col, order }
    }
}

impl Sorting {
    pub fn sort(self, mounts: &mut [Mount]) {
        let comparator = self.col.comparator();
        mounts.sort_by(comparator);
        if self.order == Order::Desc {
            mounts.reverse();
        }
    }
}

#[derive(Debug)]
pub struct ParseSortingError {
    raw: String,
    reason: String,
}
impl ParseSortingError {
    pub fn new<S: Into<String>, E: ToString>(raw: S, reason: E) -> Self {
        Self {
            raw: raw.into(),
            reason: reason.to_string(),
        }
    }
}
impl fmt::Display for ParseSortingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?} can't be parsed as a sort expression because {}", self.raw, self.reason)
    }
}
impl error::Error for ParseSortingError {}

impl FromStr for Sorting {
    type Err = ParseSortingError;
    fn from_str(s: &str) -> Result<Self, ParseSortingError> {
        let cut_idx_len = s
            .char_indices()
            .find(|(_idx, c)| c.is_whitespace() || *c == '-')
            .map(|(idx, c)| (idx, c.len_utf8()));
        let (s_col, s_order) = match cut_idx_len {
            Some((idx, len)) => (&s[..idx], Some(&s[idx+len..])),
            None => (s, None),
        };
        let col: Col = s_col.parse()
            .map_err(|pce| ParseSortingError::new(s, Box::new(pce)))?;
        let order = match s_order {
            Some(s_order) => {
                s_order.parse()
                    .map_err(|poe| ParseSortingError::new(s, Box::new(poe)))?
            }
            None => {
                col.default_sort_order()
            }
        };
        Ok(Self { col, order })
    }
}