fluent_ansi/style/
encoded_effects.rs1use crate::{AllEffects, Effect, UnderlineEffect};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
4pub(crate) struct EncodedEffects(u16);
5
6impl EncodedEffects {
7 #[must_use]
8 pub(crate) const fn new() -> Self {
9 Self(0)
10 }
11
12 #[must_use]
13 pub(crate) fn set(self, effect: Effect, value: bool) -> Self {
14 if value {
15 self.add(effect)
16 } else {
17 self.remove(effect)
18 }
19 }
20
21 #[must_use]
22 fn add(self, effect: Effect) -> Self {
23 let underline_effect = UnderlineEffect::all().find(|t| t.to_effect() == effect);
24 if let Some(underline_effect) = underline_effect {
25 self.set_underline(Some(underline_effect))
26 } else {
27 self.set_bit(effect)
28 }
29 }
30
31 #[must_use]
32 fn remove(self, effect: Effect) -> Self {
33 self.clear_bit(effect)
34 }
35
36 #[must_use]
37 pub(crate) fn set_underline(self, underline_effect: Option<UnderlineEffect>) -> Self {
38 let encoded_effects = self.remove_underline();
39 if let Some(underline_effect) = underline_effect {
40 encoded_effects.set_bit(underline_effect.to_effect())
41 } else {
42 encoded_effects
43 }
44 }
45
46 #[must_use]
47 fn remove_underline(self) -> Self {
48 let mut encoded_effects = self;
49 for underline_effect in UnderlineEffect::all() {
50 encoded_effects = encoded_effects.clear_bit(underline_effect.to_effect());
51 }
52 encoded_effects
53 }
54
55 #[must_use]
56 pub(crate) fn get(self, effect: Effect) -> bool {
57 self.0 & Self::bit_mask(effect) != 0
58 }
59
60 #[must_use]
61 pub(crate) fn get_effects(self) -> GetEffects {
62 GetEffects {
63 inner: Effect::all(),
64 encoded_effects: self,
65 }
66 }
67
68 #[must_use]
69 fn set_bit(self, effect: Effect) -> Self {
70 let bits = self.0 | Self::bit_mask(effect);
71 Self(bits)
72 }
73
74 #[must_use]
75 fn clear_bit(self, effect: Effect) -> Self {
76 let bits = self.0 & !Self::bit_mask(effect);
77 Self(bits)
78 }
79
80 #[must_use]
81 fn bit_mask(effect: Effect) -> u16 {
82 let bit_index = effect as u16;
83 1 << bit_index
84 }
85}
86
87#[derive(Debug, Clone)]
89pub struct GetEffects {
90 inner: AllEffects,
91 encoded_effects: EncodedEffects,
92}
93impl Iterator for GetEffects {
94 type Item = Effect;
95
96 fn next(&mut self) -> Option<Self::Item> {
97 self.inner
98 .by_ref()
99 .find(|&effect| self.encoded_effects.get(effect))
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 fn underline_effects() -> impl Iterator<Item = Effect> {
108 UnderlineEffect::all().map(UnderlineEffect::to_effect)
109 }
110
111 #[test]
112 fn default() {
113 let effects = EncodedEffects::default();
114
115 for effect in Effect::all() {
116 assert_eq!(effects.get(effect), false);
117 }
118 }
119
120 #[test]
121 fn set_true() {
122 for added_effect in Effect::all() {
123 let effects = EncodedEffects(0).set(added_effect, true);
124
125 for checked_effect in Effect::all() {
126 assert_eq!(
127 effects.get(checked_effect),
128 added_effect == checked_effect,
129 "{added_effect:?} {checked_effect:?}"
130 );
131 }
132 }
133 }
134
135 #[test]
136 fn set_false() {
137 for removed_effect in Effect::all() {
138 let effects = EncodedEffects(!0).set(removed_effect, false);
139
140 for checked_effect in Effect::all() {
141 assert_eq!(
142 effects.get(checked_effect),
143 removed_effect != checked_effect,
144 "{removed_effect:?} {checked_effect:?}"
145 );
146 }
147 }
148 }
149
150 #[test]
151 fn set_underline_effect_true() {
152 for initial_effect in underline_effects() {
153 let encoded_effects = EncodedEffects::default().set(initial_effect, true);
155
156 for other_effect in underline_effects() {
157 if other_effect == initial_effect {
158 continue;
159 }
160
161 let encoded_effects = encoded_effects.set(other_effect, true);
163
164 assert!(
166 !encoded_effects.get(initial_effect),
167 "{initial_effect:?} should not be set"
168 );
169 assert!(
170 encoded_effects.get(other_effect),
171 "{other_effect:?} should be set"
172 );
173 }
174 }
175 }
176
177 #[test]
178 fn set_underline_some() {
179 for initial_effect in UnderlineEffect::all() {
180 let encoded_effects = EncodedEffects::default().set(initial_effect.to_effect(), true);
182
183 for other_effect in UnderlineEffect::all() {
184 if other_effect == initial_effect {
185 continue;
186 }
187
188 let encoded_effects = encoded_effects.set_underline(Some(other_effect));
190
191 assert!(
193 !encoded_effects.get(initial_effect.to_effect()),
194 "{initial_effect:?} should not be set"
195 );
196 assert!(
197 encoded_effects.get(other_effect.to_effect()),
198 "{other_effect:?} should be set"
199 );
200 }
201 }
202 }
203
204 macro_rules! test_clear_underline {
205 ($method:ident ( $( $arg:expr )?) ) => {
206 for initial_effect in UnderlineEffect::all() {
207 let encoded_effects = EncodedEffects::default().set(initial_effect.to_effect(), true);
209
210 let encoded_effects = encoded_effects.$method( $( $arg )? );
212
213 for checked_effect in UnderlineEffect::all() {
214 assert!(
215 !encoded_effects.get(checked_effect.to_effect()),
216 "{initial_effect:?} should not be set"
217 );
218 }
219 }
220 };
221 }
222
223 #[test]
224 fn set_underline_none() {
225 test_clear_underline!(set_underline(None));
226 }
227
228 #[test]
229 fn remove_underline() {
230 test_clear_underline!(remove_underline());
231 }
232
233 #[test]
234 fn get_effects() {
235 let effects = EncodedEffects::default()
236 .add(Effect::Bold)
237 .add(Effect::SolidUnderline);
238
239 let mut get_effects = effects.get_effects();
240
241 assert_eq!(get_effects.next(), Some(Effect::Bold));
242 assert_eq!(get_effects.next(), Some(Effect::SolidUnderline));
243 assert_eq!(get_effects.next(), None);
244 }
245}