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
use std::cmp::Ordering;

use clashctl_core::mod_use;

mod_use![con_sort, proxy_sort, rule_sort];

pub trait Sortable<'a, S: SortMethod<Self::Item<'a>>> {
    type Item<'b>;
    fn sort_with(&mut self, method: &S);
}

pub trait SortMethod<Item> {
    fn sort_fn(&self, a: &Item, b: &Item) -> Ordering;
}

pub trait EndlessSelf {
    fn next_self(&mut self);
    fn prev_self(&mut self);
}

#[derive(
    Debug,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    strum::EnumString,
    strum::Display,
    strum::EnumVariantNames,
)]
#[strum(ascii_case_insensitive)]
pub enum SortOrder {
    Ascendant,
    Descendant,
}

pub trait OrderBy {
    fn order_by(self, order: SortOrder) -> Ordering;
}

impl OrderBy for Ordering {
    fn order_by(self, order: SortOrder) -> Ordering {
        if matches!(order, SortOrder::Descendant) {
            self.reverse()
        } else {
            self
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, Hash)]
pub struct Noop;

impl Noop {
    pub const fn new() -> Self {
        Noop
    }
}

impl ToString for Noop {
    fn to_string(&self) -> String {
        "".into()
    }
}

impl<Item> SortMethod<Item> for Noop {
    #[inline]
    fn sort_fn(&self, _: &Item, _: &Item) -> Ordering {
        Ordering::Equal
    }
}

impl EndlessSelf for Noop {
    fn next_self(&mut self) {}

    fn prev_self(&mut self) {}
}

impl<T, F> SortMethod<T> for F
where
    F: Fn(&T, &T) -> Ordering,
{
    #[inline]
    fn sort_fn(&self, a: &T, b: &T) -> Ordering {
        self(a, b)
    }
}

impl<'a, T, M> Sortable<'a, M> for Vec<T>
where
    M: SortMethod<T>,
{
    type Item<'b> = T;

    #[inline]
    fn sort_with(&mut self, method: &M) {
        self.sort_by(|a, b| method.sort_fn(a, b))
    }
}

// #[macro_export]
// macro_rules! endless {
//     ( $ty:path = $from:ident => $( $to:ident $(=>)? )+ ) => {
//         impl EndlessSelf for $ty {
//             fn next_self(&mut self) {
//                 use $ty::*;
//                 match self {
//                     endless!( @inner $ty = $from => $( $to => )+ )
//                 }
//             }
//             fn prev_self(&mut self) {}
//         }
//     };
//     ( @inner $ty:path = $prev:ident => $from:ident => $( $to:ident $(=>)? )+ ) => {
//         $ty::$prev => $ty::$from,
//         endless!(@inner $ty = $from => $($to =>)+),
//     };
//     ( @inner $ty:path = $from:ident => $to:ident ) => {
//         $from => $to,
//     }
// }

// endless!( RuleSortBy = Payload => Proxy => Type );