oxihuman_core/
string_set.rs1#![allow(dead_code)]
4
5use std::collections::BTreeSet;
8
9#[allow(dead_code)]
11pub struct StringSet {
12 inner: BTreeSet<String>,
13 add_count: u64,
14 remove_count: u64,
15}
16
17#[allow(dead_code)]
18impl StringSet {
19 pub fn new() -> Self {
20 Self {
21 inner: BTreeSet::new(),
22 add_count: 0,
23 remove_count: 0,
24 }
25 }
26
27 pub fn insert(&mut self, s: &str) -> bool {
28 let inserted = self.inner.insert(s.to_string());
29 if inserted {
30 self.add_count += 1;
31 }
32 inserted
33 }
34
35 pub fn remove(&mut self, s: &str) -> bool {
36 let removed = self.inner.remove(s);
37 if removed {
38 self.remove_count += 1;
39 }
40 removed
41 }
42
43 pub fn contains(&self, s: &str) -> bool {
44 self.inner.contains(s)
45 }
46
47 pub fn len(&self) -> usize {
48 self.inner.len()
49 }
50
51 pub fn is_empty(&self) -> bool {
52 self.inner.is_empty()
53 }
54
55 pub fn to_vec(&self) -> Vec<String> {
56 self.inner.iter().cloned().collect()
57 }
58
59 pub fn clear(&mut self) {
60 self.inner.clear();
61 }
62
63 pub fn intersection(&self, other: &StringSet) -> StringSet {
65 let mut result = StringSet::new();
66 for s in &self.inner {
67 if other.contains(s) {
68 result.insert(s);
69 }
70 }
71 result
72 }
73
74 pub fn union(&self, other: &StringSet) -> StringSet {
76 let mut result = StringSet::new();
77 for s in &self.inner {
78 result.insert(s);
79 }
80 for s in &other.inner {
81 result.insert(s);
82 }
83 result
84 }
85
86 pub fn difference(&self, other: &StringSet) -> StringSet {
88 let mut result = StringSet::new();
89 for s in &self.inner {
90 if !other.contains(s) {
91 result.insert(s);
92 }
93 }
94 result
95 }
96
97 pub fn add_count(&self) -> u64 {
98 self.add_count
99 }
100 pub fn remove_count(&self) -> u64 {
101 self.remove_count
102 }
103
104 pub fn starts_with_prefix(&self, prefix: &str) -> Vec<String> {
105 self.inner
106 .iter()
107 .filter(|s| s.starts_with(prefix))
108 .cloned()
109 .collect()
110 }
111}
112
113impl Default for StringSet {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119pub fn new_string_set() -> StringSet {
120 StringSet::new()
121}
122
123pub fn ss_insert(set: &mut StringSet, s: &str) -> bool {
124 set.insert(s)
125}
126
127pub fn ss_contains(set: &StringSet, s: &str) -> bool {
128 set.contains(s)
129}
130
131pub fn ss_remove(set: &mut StringSet, s: &str) -> bool {
132 set.remove(s)
133}
134
135pub fn ss_len(set: &StringSet) -> usize {
136 set.len()
137}
138
139pub fn ss_to_vec(set: &StringSet) -> Vec<String> {
140 set.to_vec()
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn new_is_empty() {
149 let s = new_string_set();
150 assert!(s.is_empty());
151 }
152
153 #[test]
154 fn insert_and_contains() {
155 let mut s = new_string_set();
156 ss_insert(&mut s, "hello");
157 assert!(ss_contains(&s, "hello"));
158 assert!(!ss_contains(&s, "world"));
159 }
160
161 #[test]
162 fn insert_duplicate_returns_false() {
163 let mut s = new_string_set();
164 assert!(ss_insert(&mut s, "x"));
165 assert!(!ss_insert(&mut s, "x"));
166 assert_eq!(ss_len(&s), 1);
167 }
168
169 #[test]
170 fn remove_present() {
171 let mut s = new_string_set();
172 ss_insert(&mut s, "y");
173 assert!(ss_remove(&mut s, "y"));
174 assert!(!ss_contains(&s, "y"));
175 }
176
177 #[test]
178 fn sorted_iteration() {
179 let mut s = new_string_set();
180 ss_insert(&mut s, "c");
181 ss_insert(&mut s, "a");
182 ss_insert(&mut s, "b");
183 assert_eq!(
184 ss_to_vec(&s),
185 vec!["a".to_string(), "b".to_string(), "c".to_string()]
186 );
187 }
188
189 #[test]
190 fn intersection() {
191 let mut a = new_string_set();
192 let mut b = new_string_set();
193 ss_insert(&mut a, "x");
194 ss_insert(&mut a, "y");
195 ss_insert(&mut b, "y");
196 ss_insert(&mut b, "z");
197 let inter = a.intersection(&b);
198 assert_eq!(inter.to_vec(), vec!["y".to_string()]);
199 }
200
201 #[test]
202 fn union_combines() {
203 let mut a = new_string_set();
204 let mut b = new_string_set();
205 ss_insert(&mut a, "x");
206 ss_insert(&mut b, "y");
207 assert_eq!(a.union(&b).len(), 2);
208 }
209
210 #[test]
211 fn difference() {
212 let mut a = new_string_set();
213 let mut b = new_string_set();
214 ss_insert(&mut a, "x");
215 ss_insert(&mut a, "y");
216 ss_insert(&mut b, "y");
217 let diff = a.difference(&b);
218 assert_eq!(diff.to_vec(), vec!["x".to_string()]);
219 }
220
221 #[test]
222 fn starts_with_prefix() {
223 let mut s = new_string_set();
224 ss_insert(&mut s, "asset_mesh");
225 ss_insert(&mut s, "asset_tex");
226 ss_insert(&mut s, "config");
227 let matches = s.starts_with_prefix("asset_");
228 assert_eq!(matches.len(), 2);
229 }
230
231 #[test]
232 fn clear_empties_set() {
233 let mut s = new_string_set();
234 ss_insert(&mut s, "a");
235 s.clear();
236 assert!(s.is_empty());
237 }
238}