Skip to main content

ez_tui/types/
cpt_ids.rs

1use crate::FocusChain;
2use std::fmt::Debug;
3use std::hash::Hash;
4use std::iter;
5use strum::IntoEnumIterator;
6use strum_macros::EnumIter;
7
8/// Trait to be defined on your client's component idq enum.
9pub trait EzCptIds:
10    Default + Eq + PartialEq + IntoEnumIterator + Clone + Hash + Debug + Send + FocusChain + 'static
11{
12}
13
14/// A dummy type to be used when you don't have any component ids
15#[derive(PartialEq, Eq, Clone, Debug, Hash, Default)]
16pub struct NoClientCptId;
17
18impl FocusChain for NoClientCptId {
19    fn after(&self) -> Option<Self> {
20        None
21    }
22
23    fn before(&self) -> Option<Self> {
24        None
25    }
26
27    fn last() -> Option<Self> {
28        None
29    }
30
31    fn first() -> Option<Self> {
32        None
33    }
34}
35impl EzCptIds for NoClientCptId {}
36
37impl IntoEnumIterator for NoClientCptId {
38    type Iterator = iter::Empty<NoClientCptId>;
39
40    fn iter() -> Self::Iterator {
41        iter::empty()
42    }
43}
44
45/// Wrapper around the client's component ids enum
46#[allow(missing_docs)]
47#[derive(Ord, PartialOrd, PartialEq, Eq, Clone, Debug, Hash, EnumIter)]
48pub enum EzCptId<CID>
49where
50    CID: EzCptIds + Default,
51{
52    StateDebugger,
53    LogsViewer,
54    TickIndicator,
55    FrameIndicator,
56    Legends,
57    Client(CID),
58}
59
60impl<CID> Default for EzCptId<CID>
61where
62    CID: EzCptIds,
63{
64    fn default() -> Self {
65        EzCptId::Client(CID::default())
66    }
67}
68
69impl<CID> From<CID> for EzCptId<CID>
70where
71    CID: EzCptIds,
72{
73    fn from(cpt_id: CID) -> Self {
74        Self::Client(cpt_id)
75    }
76}
77
78impl<CID> EzCptIds for EzCptId<CID> where CID: EzCptIds {}
79impl<CID> FocusChain for EzCptId<CID>
80where
81    CID: EzCptIds,
82{
83    fn after(&self) -> Option<Self> {
84        if let EzCptId::Client(cid) = &self
85            && let Some(id) = cid.after()
86        {
87            return Some(EzCptId::Client(id));
88        }
89        let mut iter = Self::iter();
90        while let Some(current) = iter.next() {
91            if &current == self {
92                return iter.next();
93            }
94        }
95        None
96    }
97
98    fn before(&self) -> Option<Self> {
99        if let EzCptId::Client(cid) = &self
100            && let Some(id) = cid.before()
101        {
102            return Some(EzCptId::Client(id));
103        }
104        let iter = Self::iter();
105        let mut previous = None;
106        for current in iter {
107            if &current == self {
108                return previous;
109            }
110            previous = Some(current);
111        }
112        None
113    }
114    fn last() -> Option<Self> {
115        match Self::iter().next_back() {
116            Some(v) => match v {
117                EzCptId::Client(_cid) => CID::last().map(|v| EzCptId::Client(v)),
118                _ => Some(v),
119            },
120            None => None,
121        }
122    }
123    fn first() -> Option<Self> {
124        match Self::iter().next() {
125            Some(v) => match v {
126                EzCptId::Client(_cid) => CID::first().map(|v| EzCptId::Client(v)),
127                _ => Some(v),
128            },
129            None => None,
130        }
131    }
132}