oxihuman_core/
command_list.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
10pub enum CmdPriority {
11 Low,
12 Normal,
13 High,
14}
15
16#[allow(dead_code)]
18#[derive(Debug, Clone)]
19pub struct CmdEntry {
20 pub name: String,
21 pub priority: CmdPriority,
22 pub enabled: bool,
23 pub tag: Option<String>,
24}
25
26#[allow(dead_code)]
28#[derive(Debug, Clone, Default)]
29pub struct CommandList {
30 entries: Vec<CmdEntry>,
31}
32
33#[allow(dead_code)]
34impl CommandList {
35 pub fn new() -> Self {
36 Self::default()
37 }
38
39 pub fn push(&mut self, name: &str, priority: CmdPriority) {
40 self.entries.push(CmdEntry {
41 name: name.to_string(),
42 priority,
43 enabled: true,
44 tag: None,
45 });
46 }
47
48 pub fn push_tagged(&mut self, name: &str, priority: CmdPriority, tag: &str) {
49 self.entries.push(CmdEntry {
50 name: name.to_string(),
51 priority,
52 enabled: true,
53 tag: Some(tag.to_string()),
54 });
55 }
56
57 pub fn len(&self) -> usize {
58 self.entries.len()
59 }
60
61 pub fn is_empty(&self) -> bool {
62 self.entries.is_empty()
63 }
64
65 pub fn get(&self, index: usize) -> Option<&CmdEntry> {
66 self.entries.get(index)
67 }
68
69 pub fn enable(&mut self, name: &str) {
70 for e in &mut self.entries {
71 if e.name == name {
72 e.enabled = true;
73 }
74 }
75 }
76
77 pub fn disable(&mut self, name: &str) {
78 for e in &mut self.entries {
79 if e.name == name {
80 e.enabled = false;
81 }
82 }
83 }
84
85 pub fn enabled_names(&self) -> Vec<&str> {
86 self.entries
87 .iter()
88 .filter(|e| e.enabled)
89 .map(|e| e.name.as_str())
90 .collect()
91 }
92
93 pub fn sorted_by_priority(&self) -> Vec<&CmdEntry> {
94 let mut v: Vec<&CmdEntry> = self.entries.iter().collect();
95 v.sort_by(|a, b| b.priority.cmp(&a.priority));
96 v
97 }
98
99 pub fn by_tag(&self, tag: &str) -> Vec<&CmdEntry> {
100 self.entries
101 .iter()
102 .filter(|e| e.tag.as_deref() == Some(tag))
103 .collect()
104 }
105
106 pub fn remove(&mut self, name: &str) -> bool {
107 let before = self.entries.len();
108 self.entries.retain(|e| e.name != name);
109 self.entries.len() < before
110 }
111
112 pub fn clear(&mut self) {
113 self.entries.clear();
114 }
115
116 pub fn contains(&self, name: &str) -> bool {
117 self.entries.iter().any(|e| e.name == name)
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn new_is_empty() {
127 let cl = CommandList::new();
128 assert!(cl.is_empty());
129 assert_eq!(cl.len(), 0);
130 }
131
132 #[test]
133 fn push_and_get() {
134 let mut cl = CommandList::new();
135 cl.push("draw", CmdPriority::Normal);
136 assert_eq!(cl.len(), 1);
137 assert_eq!(cl.get(0).expect("should succeed").name, "draw");
138 assert!(cl.get(0).expect("should succeed").enabled);
139 }
140
141 #[test]
142 fn contains_works() {
143 let mut cl = CommandList::new();
144 cl.push("update", CmdPriority::High);
145 assert!(cl.contains("update"));
146 assert!(!cl.contains("missing"));
147 }
148
149 #[test]
150 fn enable_disable() {
151 let mut cl = CommandList::new();
152 cl.push("tick", CmdPriority::Normal);
153 cl.disable("tick");
154 assert!(!cl.get(0).expect("should succeed").enabled);
155 cl.enable("tick");
156 assert!(cl.get(0).expect("should succeed").enabled);
157 }
158
159 #[test]
160 fn enabled_names_filters() {
161 let mut cl = CommandList::new();
162 cl.push("a", CmdPriority::Normal);
163 cl.push("b", CmdPriority::Low);
164 cl.disable("b");
165 let names = cl.enabled_names();
166 assert_eq!(names, vec!["a"]);
167 }
168
169 #[test]
170 fn sorted_by_priority_descending() {
171 let mut cl = CommandList::new();
172 cl.push("lo", CmdPriority::Low);
173 cl.push("hi", CmdPriority::High);
174 cl.push("nm", CmdPriority::Normal);
175 let sorted = cl.sorted_by_priority();
176 assert_eq!(sorted[0].priority, CmdPriority::High);
177 assert_eq!(sorted[2].priority, CmdPriority::Low);
178 }
179
180 #[test]
181 fn push_tagged_and_by_tag() {
182 let mut cl = CommandList::new();
183 cl.push_tagged("render_a", CmdPriority::Normal, "render");
184 cl.push_tagged("render_b", CmdPriority::Normal, "render");
185 cl.push("logic", CmdPriority::Normal);
186 let tagged = cl.by_tag("render");
187 assert_eq!(tagged.len(), 2);
188 }
189
190 #[test]
191 fn remove_entry() {
192 let mut cl = CommandList::new();
193 cl.push("x", CmdPriority::Normal);
194 assert!(cl.remove("x"));
195 assert!(cl.is_empty());
196 assert!(!cl.remove("x"));
197 }
198
199 #[test]
200 fn clear_empties_list() {
201 let mut cl = CommandList::new();
202 cl.push("a", CmdPriority::Normal);
203 cl.push("b", CmdPriority::High);
204 cl.clear();
205 assert!(cl.is_empty());
206 }
207
208 #[test]
209 fn multiple_same_name_priority() {
210 let mut cl = CommandList::new();
211 cl.push("dup", CmdPriority::Normal);
212 cl.push("dup", CmdPriority::High);
213 assert_eq!(cl.len(), 2);
214 cl.disable("dup");
215 assert!(cl.enabled_names().is_empty());
216 }
217}