1use crate::{Effect, Toggle};
2use crate::write::{compile_time, run_time};
3use crate::introspect::Attr;
4use bitflags::bitflags;
5use std::fmt;
6
7bitflags! {
8 #[derive(PartialEq, Eq, Clone, Copy, fmt::Debug)]
9 pub(super) struct Attrs: u8 {
10 const Bold = 1 << 0;
11 const Faint = 1 << 1;
12 const Italic = 1 << 2;
13 const Underline = 1 << 3;
14 const Blink = 1 << 4;
15 const Reverse = 1 << 5;
16 const Hidden = 1 << 6;
17 const Strike = 1 << 7;
18 }
19}
20
21impl Attrs {
22 #[inline]
23 pub(super) const fn contains_effect(&self, effect: Effect) -> bool {
24 self.contains(Self::from_effect(effect))
25 }
26
27 #[inline]
28 const fn from_effect(effect: Effect) -> Self {
29 match effect {
30 Effect::Bold => Self::Bold,
31 Effect::Faint => Self::Faint,
32 Effect::Italic => Self::Italic,
33 Effect::Underline => Self::Underline,
34 Effect::Blink => Self::Blink,
35 Effect::Reverse => Self::Reverse,
36 Effect::Hidden => Self::Hidden,
37 Effect::Strike => Self::Strike,
38 }
39 }
40
41 #[inline]
43 pub(super) const fn with_overlaps(&self) -> Self {
44 if self.intersects(Attrs::Bold) {
45 self.union(Attrs::Faint)
46 } else if self.intersects(Attrs::Faint) {
47 self.union(Attrs::Bold)
48 } else {
49 *self
50 }
51 }
52
53 #[inline]
55 pub(super) const fn no_overlaps(&self) -> Self {
56 if self.contains(Attrs::Bold.union(Attrs::Faint)) {
57 self.difference(Attrs::Faint)
58 } else {
59 *self
60 }
61 }
62}
63
64#[derive(PartialEq, Eq, Clone, Copy)]
65pub(super) struct Effects { y: Attrs, n: Attrs }
66
67impl Effects {
68 #[inline]
69 pub(super) const fn from_effect(effect: Effect, toggle: Toggle) -> Self {
70 Self::new(Attrs::from_effect(effect), toggle)
71 }
72
73 #[inline]
74 const fn new(attrs: Attrs, toggle: Toggle) -> Self {
75 match toggle {
76 Toggle::Set => Self { y: attrs, n: Attrs::empty() },
77 Toggle::Reset => Self { y: Attrs::empty(), n: attrs },
78 }
79 }
80 #[inline]
81 pub(super) const fn is_empty(&self) -> bool { self.y.is_empty() && self.n.is_empty() }
82 #[inline]
83 pub(super) const fn is_reset(&self) -> bool { self.y.is_empty() && self.n.is_all() }
84 #[inline]
85 pub(super) const fn empty() -> Self{ Effects { y: Attrs::empty(), n: Attrs::empty() } }
86 #[inline]
87 pub(super) const fn reset() -> Self{ Effects { y: Attrs::empty(), n: Attrs::all() } }
88 #[inline]
89 pub(super) const fn get_effect(&self, ef: Effect) -> Option<Attr<Effect>> {
90 let attrs = Attrs::from_effect(ef);
91 if self.y.contains(attrs) {
92 Some(Attr::new_effect(ef, Toggle::Set))
93 } else if self.n.contains(attrs) {
94 Some(Attr::new_effect(ef, Toggle::Reset))
95 } else {
96 None
97 }
98 }
99 #[inline]
100 pub(super) const fn add(&self, other: Self) -> Self {
101 let other_attrs = other.attrs();
102 Self {
103 y: self.y.difference(other_attrs).union(other.y),
104 n: self.n.difference(other_attrs).union(other.n),
105 }
106 }
107 #[inline]
108 pub(super) const fn transition(&self, to_other: Self) -> Self {
109 let other_new_n = to_other.n.difference(self.n.with_overlaps());
111 let self_kill_y = self.y.difference(to_other.y).difference(other_new_n.with_overlaps());
113 let other_restore_y = to_other.y.intersection(self_kill_y.with_overlaps().union(other_new_n.with_overlaps()));
115 let y = to_other.y.difference(self.y).union(other_restore_y);
117 let n = other_new_n.union(self_kill_y).no_overlaps();
118 #[cfg(test)]
119 assert!(!y.intersects(n));
120 Self { y, n }
121 }
122 #[inline]
123 pub(super) const fn not(&self) -> Self {
124 Self {
125 y: Attrs::empty(),
126 n: self.y,
127 }
128 }
129 #[inline]
130 pub(super) const fn only(&self) -> Self {
131 Self {
132 y: self.y,
133 n: self.n.union(self.y.complement()),
134 }
135 }
136 #[inline]
137 pub(super) const fn remove(&self, attrs: Attrs) -> Self {
138 Self {
139 y: self.y.difference(attrs),
140 n: self.n.difference(attrs),
141 }
142 }
143 #[inline]
144 pub(super) const fn attrs(&self) -> Attrs {
145 self.y.union(self.n)
146 }
147
148 #[inline]
149 pub(super) fn write(&self, w: &mut run_time::Formatter<'_,'_>, toggle: Toggle) -> fmt::Result {
150 let attrs = match toggle {
151 Toggle::Set => self.y,
152 Toggle::Reset => self.n,
153 };
154 if attrs.contains(Attrs::Bold ) { w.write_effect(Effect::Bold, toggle)?; }
155 if attrs.contains(Attrs::Faint ) { w.write_effect(Effect::Faint, toggle)?; }
156 if attrs.contains(Attrs::Italic ) { w.write_effect(Effect::Italic, toggle)?; }
157 if attrs.contains(Attrs::Underline) { w.write_effect(Effect::Underline, toggle)?; }
158 if attrs.contains(Attrs::Blink ) { w.write_effect(Effect::Blink, toggle)?; }
159 if attrs.contains(Attrs::Reverse ) { w.write_effect(Effect::Reverse, toggle)?; }
160 if attrs.contains(Attrs::Hidden ) { w.write_effect(Effect::Hidden, toggle)?; }
161 if attrs.contains(Attrs::Strike ) { w.write_effect(Effect::Strike, toggle)?; }
162 Ok(())
163 }
164 #[inline]
165 pub(super) const fn write_const(&self, mut w: compile_time::Writer, toggle: Toggle) -> compile_time::Writer {
166 let attrs = match toggle {
167 Toggle::Set => self.y,
168 Toggle::Reset => self.n,
169 };
170 if attrs.contains(Attrs::Bold ) { w = w.write_effect(Effect::Bold, toggle); }
171 if attrs.contains(Attrs::Faint ) { w = w.write_effect(Effect::Faint, toggle); }
172 if attrs.contains(Attrs::Italic ) { w = w.write_effect(Effect::Italic, toggle); }
173 if attrs.contains(Attrs::Underline) { w = w.write_effect(Effect::Underline, toggle); }
174 if attrs.contains(Attrs::Blink ) { w = w.write_effect(Effect::Blink, toggle); }
175 if attrs.contains(Attrs::Reverse ) { w = w.write_effect(Effect::Reverse, toggle); }
176 if attrs.contains(Attrs::Hidden ) { w = w.write_effect(Effect::Hidden, toggle); }
177 if attrs.contains(Attrs::Strike ) { w = w.write_effect(Effect::Strike, toggle); }
178 w
179 }
180}
181
182impl From<&Effect> for Effects {
183 fn from(ef: &Effect) -> Self { Self::from_effect(*ef, Toggle::Set) }
184}
185impl From<Effect> for Effects {
186 fn from(ef: Effect) -> Self { Self::from_effect(ef, Toggle::Set) }
187}