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
use std::collections::HashMap;
use std::sync::Arc;

use super::super::*;

#[derive(Debug)]
pub enum Map {
    WithPrefixes(GroupMap),
    Prefixless(GroupMap, CommandMap),
}

pub trait ParseMap {
    type Storage;

    fn get(&self, n: &str) -> Option<Self::Storage>;
    fn min_length(&self) -> usize;
    fn max_length(&self) -> usize;
    fn is_empty(&self) -> bool;
}

#[derive(Debug, Default)]
pub struct CommandMap {
    cmds: HashMap<&'static str, (&'static Command, Arc<CommandMap>)>,
    min_length: usize,
    max_length: usize,
}

impl CommandMap {
    pub fn new(cmds: &[&'static Command]) -> Self {
        let mut map = Self::default();

        for cmd in cmds {
            let sub_map = Arc::new(Self::new(&cmd.options.sub_commands));

            for name in cmd.options.names {
                let len = name.chars().count();
                map.min_length = std::cmp::min(len, map.min_length);
                map.max_length = std::cmp::max(len, map.max_length);

                map.cmds.insert(*name, (*cmd, sub_map.clone()));
            }
        }

        map
    }
}

impl ParseMap for CommandMap {
    type Storage = (&'static Command, Arc<CommandMap>);

    #[inline]
    fn min_length(&self) -> usize {
        self.min_length
    }

    #[inline]
    fn max_length(&self) -> usize {
        self.max_length
    }

    #[inline]
    fn get(&self, name: &str) -> Option<Self::Storage> {
        self.cmds.get(&name).cloned()
    }

    #[inline]
    fn is_empty(&self) -> bool {
        self.cmds.is_empty()
    }
}

#[derive(Debug, Default)]
pub struct GroupMap {
    groups: HashMap<&'static str, (&'static CommandGroup, Arc<GroupMap>, Arc<CommandMap>)>,
    min_length: usize,
    max_length: usize,
}

impl GroupMap {
    pub fn new(groups: &[&'static CommandGroup]) -> Self {
        let mut map = Self::default();

        for group in groups {
            let subgroups_map = Arc::new(Self::new(&group.options.sub_groups));
            let commands_map = Arc::new(CommandMap::new(&group.options.commands));

            for prefix in group.options.prefixes {
                let len = prefix.chars().count();
                map.min_length = std::cmp::min(len, map.min_length);
                map.max_length = std::cmp::max(len, map.max_length);

                map.groups.insert(*prefix, (*group, subgroups_map.clone(), commands_map.clone()));
            }
        }

        map
    }
}

impl ParseMap for GroupMap {
    type Storage = (&'static CommandGroup, Arc<GroupMap>, Arc<CommandMap>);

    #[inline]
    fn min_length(&self) -> usize {
        self.min_length
    }

    #[inline]
    fn max_length(&self) -> usize {
        self.max_length
    }

    #[inline]
    fn get(&self, name: &str) -> Option<Self::Storage> {
        self.groups.get(&name).cloned()
    }

    #[inline]
    fn is_empty(&self) -> bool {
        self.groups.is_empty()
    }
}