| 1 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; | 
| 2 |  | 
|---|
| 3 | macro_rules! auto_impl_ref_binop_trait { | 
|---|
| 4 | (impl $trait_name:ident, $method:ident for $t:ty, $u:ty) => { | 
|---|
| 5 | impl $trait_name<&$u> for $t { | 
|---|
| 6 | type Output = <$t as $trait_name<$t>>::Output; | 
|---|
| 7 |  | 
|---|
| 8 | #[inline] | 
|---|
| 9 | fn $method(self, rhs: &$u) -> Self::Output { | 
|---|
| 10 | $trait_name::$method(self, *rhs) | 
|---|
| 11 | } | 
|---|
| 12 | } | 
|---|
| 13 |  | 
|---|
| 14 | impl $trait_name<$u> for &$t { | 
|---|
| 15 | type Output = <$t as $trait_name<$t>>::Output; | 
|---|
| 16 |  | 
|---|
| 17 | #[inline] | 
|---|
| 18 | fn $method(self, rhs: $u) -> Self::Output { | 
|---|
| 19 | $trait_name::$method(*self, rhs) | 
|---|
| 20 | } | 
|---|
| 21 | } | 
|---|
| 22 |  | 
|---|
| 23 | impl $trait_name<&$u> for &$t { | 
|---|
| 24 | type Output = <$t as $trait_name<$t>>::Output; | 
|---|
| 25 |  | 
|---|
| 26 | #[inline] | 
|---|
| 27 | fn $method(self, rhs: &$u) -> Self::Output { | 
|---|
| 28 | $trait_name::$method(*self, *rhs) | 
|---|
| 29 | } | 
|---|
| 30 | } | 
|---|
| 31 | }; | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | macro_rules! impl_assign_op_trait { | 
|---|
| 35 | ( | 
|---|
| 36 | $trait:ident, $method:ident for $t:ty, $u:ty, using $used_trait:ident::$used_method:ident | 
|---|
| 37 | ) => { | 
|---|
| 38 | impl $trait<$u> for $t { | 
|---|
| 39 | #[inline] | 
|---|
| 40 | fn $method(&mut self, other: $u) { | 
|---|
| 41 | *self = $used_trait::$used_method(&*self, other); | 
|---|
| 42 | } | 
|---|
| 43 | } | 
|---|
| 44 |  | 
|---|
| 45 | impl $trait<&$u> for $t { | 
|---|
| 46 | #[inline] | 
|---|
| 47 | fn $method(&mut self, other: &$u) { | 
|---|
| 48 | *self = $used_trait::$used_method(&*self, other); | 
|---|
| 49 | } | 
|---|
| 50 | } | 
|---|
| 51 | }; | 
|---|
| 52 | } | 
|---|
| 53 |  | 
|---|
| 54 | const CLEARV: u8 = 0b0000_0000; | 
|---|
| 55 | const BOLD: u8 = 0b0000_0001; | 
|---|
| 56 | const UNDERLINE: u8 = 0b0000_0010; | 
|---|
| 57 | const REVERSED: u8 = 0b0000_0100; | 
|---|
| 58 | const ITALIC: u8 = 0b0000_1000; | 
|---|
| 59 | const BLINK: u8 = 0b0001_0000; | 
|---|
| 60 | const HIDDEN: u8 = 0b0010_0000; | 
|---|
| 61 | const DIMMED: u8 = 0b0100_0000; | 
|---|
| 62 | const STRIKETHROUGH: u8 = 0b1000_0000; | 
|---|
| 63 |  | 
|---|
| 64 | static STYLES: [(u8, Styles); 8] = [ | 
|---|
| 65 | (BOLD, Styles::Bold), | 
|---|
| 66 | (DIMMED, Styles::Dimmed), | 
|---|
| 67 | (UNDERLINE, Styles::Underline), | 
|---|
| 68 | (REVERSED, Styles::Reversed), | 
|---|
| 69 | (ITALIC, Styles::Italic), | 
|---|
| 70 | (BLINK, Styles::Blink), | 
|---|
| 71 | (HIDDEN, Styles::Hidden), | 
|---|
| 72 | (STRIKETHROUGH, Styles::Strikethrough), | 
|---|
| 73 | ]; | 
|---|
| 74 |  | 
|---|
| 75 | pub static CLEAR: Style = Style(CLEARV); | 
|---|
| 76 |  | 
|---|
| 77 | /// A combinatorial style such as bold, italics, dimmed, etc. | 
|---|
| 78 | /// | 
|---|
| 79 | /// ## Creation | 
|---|
| 80 | /// | 
|---|
| 81 | /// `Style::default()` returns a `Style` with no style switches | 
|---|
| 82 | /// activated and is the default method of creating a plain `Style`. | 
|---|
| 83 | /// | 
|---|
| 84 | /// ## `Style` from a set of `Styles`s / `Styles` iterator | 
|---|
| 85 | /// | 
|---|
| 86 | /// `Style` implements `FromIter<Styles>` which means that it is | 
|---|
| 87 | /// possible to do the following: | 
|---|
| 88 | /// | 
|---|
| 89 | /// ```rust | 
|---|
| 90 | /// # use colored::*; | 
|---|
| 91 | /// let style = Style::from_iter([Styles::Bold, Styles::Italic, Styles::Strikethrough]); | 
|---|
| 92 | /// for styles in [Styles::Bold, Styles::Italic, Styles::Strikethrough] { | 
|---|
| 93 | ///     assert!(style.contains(styles)); | 
|---|
| 94 | /// } | 
|---|
| 95 | /// ``` | 
|---|
| 96 | /// | 
|---|
| 97 | /// As you can see, this is a good thing to keep in mind, although for | 
|---|
| 98 | /// most cases, where you're not setting styles dynamically and are | 
|---|
| 99 | /// simply creating a pre-defined set of styles, using [`Default`] and | 
|---|
| 100 | /// then using the builder-style methods is likely prettier. | 
|---|
| 101 | /// | 
|---|
| 102 | /// ```rust | 
|---|
| 103 | /// # use colored::*; | 
|---|
| 104 | /// let many_styles = Style::default() | 
|---|
| 105 | ///     .bold() | 
|---|
| 106 | ///     .underline() | 
|---|
| 107 | ///     .italic() | 
|---|
| 108 | ///     .blink(); | 
|---|
| 109 | /// ``` | 
|---|
| 110 | /// | 
|---|
| 111 | /// ## Implementation of logical bitwise operators | 
|---|
| 112 | /// | 
|---|
| 113 | /// `Style` implements bitwise logical operations that operate on | 
|---|
| 114 | /// the held style switches collectively. By far the most common | 
|---|
| 115 | /// and useful is the bitwise 'or' operator `|` which combines two | 
|---|
| 116 | /// styles, merging their combined styles into one. Example: | 
|---|
| 117 | /// | 
|---|
| 118 | /// ```rust | 
|---|
| 119 | /// # use colored::*; | 
|---|
| 120 | /// let only_bold = Style::from(Styles::Bold); | 
|---|
| 121 | /// // This line is actually an example of `Styles`'s bitwise logic impls but still. | 
|---|
| 122 | /// let underline_and_italic = Styles::Underline | Styles::Italic; | 
|---|
| 123 | /// let all_three = only_bold | underline_and_italic; | 
|---|
| 124 | /// | 
|---|
| 125 | /// assert!(all_three.contains(Styles::Bold) | 
|---|
| 126 | ///     && all_three.contains(Styles::Underline) | 
|---|
| 127 | ///     && all_three.contains(Styles::Italic)); | 
|---|
| 128 | /// ``` | 
|---|
| 129 | /// | 
|---|
| 130 | /// This functionality also allows for easily turning off styles | 
|---|
| 131 | /// of one `Styles` using another by combining the `&` and `!` | 
|---|
| 132 | /// operators. | 
|---|
| 133 | /// | 
|---|
| 134 | /// ```rust | 
|---|
| 135 | /// # use colored::*; | 
|---|
| 136 | /// let mut very_loud_style = Style::default() | 
|---|
| 137 | ///     .bold() | 
|---|
| 138 | ///     .underline() | 
|---|
| 139 | ///     .italic() | 
|---|
| 140 | ///     .strikethrough() | 
|---|
| 141 | ///     .hidden(); | 
|---|
| 142 | /// | 
|---|
| 143 | /// // Oops! Some of those should not be in there! | 
|---|
| 144 | /// // This Style now has all styles _except_ the two we don't want | 
|---|
| 145 | /// // (hidden and strikethough). | 
|---|
| 146 | /// let remove_mask = | 
|---|
| 147 | ///     !Style::from_iter([Styles::Hidden, Styles::Strikethrough]); | 
|---|
| 148 | /// very_loud_style &= remove_mask; | 
|---|
| 149 | /// | 
|---|
| 150 | /// // `very_loud_style` no longer contains the undesired style | 
|---|
| 151 | /// // switches... | 
|---|
| 152 | /// assert!(!very_loud_style.contains(Styles::Hidden) | 
|---|
| 153 | ///     && !very_loud_style.contains(Styles::Strikethrough)); | 
|---|
| 154 | /// // ...but it retains everything else! | 
|---|
| 155 | /// assert!(very_loud_style.contains(Styles::Bold)); | 
|---|
| 156 | /// ``` | 
|---|
| 157 | #[ derive(Clone, Copy, PartialEq, Eq, Debug)] | 
|---|
| 158 | pub struct Style(u8); | 
|---|
| 159 |  | 
|---|
| 160 | /// Enum containing all of the available style settings that can be | 
|---|
| 161 | /// applied to a [`Styles`] and by extension, a colrized type. | 
|---|
| 162 | /// | 
|---|
| 163 | /// ## Implementation of bitwise logical operators | 
|---|
| 164 | /// | 
|---|
| 165 | /// The implementations of [`BitAnd`], [`BitOr`], [`BitXor`], and | 
|---|
| 166 | /// [`Not`] are really extensions of [`Style`]'s implementations of | 
|---|
| 167 | /// the same. [`BitOr`] is great for starting chains of `Styles`'s | 
|---|
| 168 | /// for creating [`Style`]'s. | 
|---|
| 169 | /// | 
|---|
| 170 | /// ``` | 
|---|
| 171 | /// # use colored::*; | 
|---|
| 172 | /// let my_styles = | 
|---|
| 173 | ///     // BitOr<Styles> for Styles (Styles | Styles) = Style | 
|---|
| 174 | ///     Styles::Bold | Styles::Underline | 
|---|
| 175 | ///     // BitOr<Styles> for Style (Style | Styles) = Style | 
|---|
| 176 | ///     | Styles::Italic; | 
|---|
| 177 | /// | 
|---|
| 178 | /// for s in [Styles::Bold, Styles::Underline, Styles::Italic] { | 
|---|
| 179 | ///     assert!(my_styles.contains(s)); | 
|---|
| 180 | /// } | 
|---|
| 181 | /// ``` | 
|---|
| 182 | /// | 
|---|
| 183 | /// [`Not`] has far fewer use cases but can still find use in | 
|---|
| 184 | /// turning a `Styles` into a [`Style`] with all styles activated | 
|---|
| 185 | /// except that `Styles`. | 
|---|
| 186 | /// | 
|---|
| 187 | /// ``` | 
|---|
| 188 | /// # use colored::*; | 
|---|
| 189 | /// let everything_but_bold = !Styles::Bold; | 
|---|
| 190 | /// | 
|---|
| 191 | /// assert!(everything_but_bold.contains(Styles::Underline)); | 
|---|
| 192 | /// assert!(everything_but_bold.contains(Styles::Strikethrough)); | 
|---|
| 193 | /// assert!(!everything_but_bold.contains(Styles::Bold)); | 
|---|
| 194 | /// ``` | 
|---|
| 195 | #[ derive(Clone, Copy, PartialEq, Eq, Debug)] | 
|---|
| 196 | #[ allow(missing_docs)] | 
|---|
| 197 | pub enum Styles { | 
|---|
| 198 | Clear, | 
|---|
| 199 | Bold, | 
|---|
| 200 | Dimmed, | 
|---|
| 201 | Underline, | 
|---|
| 202 | Reversed, | 
|---|
| 203 | Italic, | 
|---|
| 204 | Blink, | 
|---|
| 205 | Hidden, | 
|---|
| 206 | Strikethrough, | 
|---|
| 207 | } | 
|---|
| 208 |  | 
|---|
| 209 | impl Styles { | 
|---|
| 210 | fn to_str<'a>(self) -> &'a str { | 
|---|
| 211 | match self { | 
|---|
| 212 | Styles::Clear => "", // unreachable, but we don't want to panic | 
|---|
| 213 | Styles::Bold => "1", | 
|---|
| 214 | Styles::Dimmed => "2", | 
|---|
| 215 | Styles::Italic => "3", | 
|---|
| 216 | Styles::Underline => "4", | 
|---|
| 217 | Styles::Blink => "5", | 
|---|
| 218 | Styles::Reversed => "7", | 
|---|
| 219 | Styles::Hidden => "8", | 
|---|
| 220 | Styles::Strikethrough => "9", | 
|---|
| 221 | } | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 | fn to_u8(self) -> u8 { | 
|---|
| 225 | match self { | 
|---|
| 226 | Styles::Clear => CLEARV, | 
|---|
| 227 | Styles::Bold => BOLD, | 
|---|
| 228 | Styles::Dimmed => DIMMED, | 
|---|
| 229 | Styles::Italic => ITALIC, | 
|---|
| 230 | Styles::Underline => UNDERLINE, | 
|---|
| 231 | Styles::Blink => BLINK, | 
|---|
| 232 | Styles::Reversed => REVERSED, | 
|---|
| 233 | Styles::Hidden => HIDDEN, | 
|---|
| 234 | Styles::Strikethrough => STRIKETHROUGH, | 
|---|
| 235 | } | 
|---|
| 236 | } | 
|---|
| 237 |  | 
|---|
| 238 | fn from_u8(u: u8) -> Option<Vec<Styles>> { | 
|---|
| 239 | if u == CLEARV { | 
|---|
| 240 | return None; | 
|---|
| 241 | } | 
|---|
| 242 |  | 
|---|
| 243 | let res: Vec<Styles> = STYLES | 
|---|
| 244 | .iter() | 
|---|
| 245 | .filter(|&(mask, _)| (0 != (u & mask))) | 
|---|
| 246 | .map(|&(_, value)| value) | 
|---|
| 247 | .collect(); | 
|---|
| 248 | if res.is_empty() { | 
|---|
| 249 | None | 
|---|
| 250 | } else { | 
|---|
| 251 | Some(res) | 
|---|
| 252 | } | 
|---|
| 253 | } | 
|---|
| 254 | } | 
|---|
| 255 |  | 
|---|
| 256 | impl BitAnd<Styles> for Styles { | 
|---|
| 257 | type Output = Style; | 
|---|
| 258 |  | 
|---|
| 259 | fn bitand(self, rhs: Styles) -> Self::Output { | 
|---|
| 260 | Style(self.to_u8() & rhs.to_u8()) | 
|---|
| 261 | } | 
|---|
| 262 | } | 
|---|
| 263 |  | 
|---|
| 264 | auto_impl_ref_binop_trait!(impl BitAnd, bitand for Styles, Styles); | 
|---|
| 265 |  | 
|---|
| 266 | impl BitAnd<Style> for Styles { | 
|---|
| 267 | type Output = Style; | 
|---|
| 268 |  | 
|---|
| 269 | fn bitand(self, rhs: Style) -> Self::Output { | 
|---|
| 270 | Style(self.to_u8() & rhs.0) | 
|---|
| 271 | } | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | auto_impl_ref_binop_trait!(impl BitAnd, bitand for Styles, Style); | 
|---|
| 275 |  | 
|---|
| 276 | impl BitOr<Styles> for Styles { | 
|---|
| 277 | type Output = Style; | 
|---|
| 278 |  | 
|---|
| 279 | fn bitor(self, rhs: Styles) -> Self::Output { | 
|---|
| 280 | Style(self.to_u8() | rhs.to_u8()) | 
|---|
| 281 | } | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 | auto_impl_ref_binop_trait!(impl BitOr, bitor for Styles, Styles); | 
|---|
| 285 |  | 
|---|
| 286 | impl BitOr<Style> for Styles { | 
|---|
| 287 | type Output = Style; | 
|---|
| 288 |  | 
|---|
| 289 | fn bitor(self, rhs: Style) -> Self::Output { | 
|---|
| 290 | Style(self.to_u8() | rhs.0) | 
|---|
| 291 | } | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | auto_impl_ref_binop_trait!(impl BitOr, bitor for Styles, Style); | 
|---|
| 295 |  | 
|---|
| 296 | impl BitXor<Styles> for Styles { | 
|---|
| 297 | type Output = Style; | 
|---|
| 298 |  | 
|---|
| 299 | fn bitxor(self, rhs: Styles) -> Self::Output { | 
|---|
| 300 | Style(self.to_u8() ^ rhs.to_u8()) | 
|---|
| 301 | } | 
|---|
| 302 | } | 
|---|
| 303 |  | 
|---|
| 304 | auto_impl_ref_binop_trait!(impl BitXor, bitxor for Styles, Styles); | 
|---|
| 305 |  | 
|---|
| 306 | impl BitXor<Style> for Styles { | 
|---|
| 307 | type Output = Style; | 
|---|
| 308 |  | 
|---|
| 309 | fn bitxor(self, rhs: Style) -> Self::Output { | 
|---|
| 310 | Style(self.to_u8() ^ rhs.0) | 
|---|
| 311 | } | 
|---|
| 312 | } | 
|---|
| 313 |  | 
|---|
| 314 | auto_impl_ref_binop_trait!(impl BitXor, bitxor for Styles, Style); | 
|---|
| 315 |  | 
|---|
| 316 | impl Not for Styles { | 
|---|
| 317 | type Output = Style; | 
|---|
| 318 |  | 
|---|
| 319 | fn not(self) -> Self::Output { | 
|---|
| 320 | Style(!self.to_u8()) | 
|---|
| 321 | } | 
|---|
| 322 | } | 
|---|
| 323 |  | 
|---|
| 324 | impl Not for &Styles { | 
|---|
| 325 | type Output = Style; | 
|---|
| 326 |  | 
|---|
| 327 | fn not(self) -> Self::Output { | 
|---|
| 328 | Style(!self.to_u8()) | 
|---|
| 329 | } | 
|---|
| 330 | } | 
|---|
| 331 |  | 
|---|
| 332 | impl Style { | 
|---|
| 333 | /// Check if the current style has one of [`Styles`](Styles) switched on. | 
|---|
| 334 | /// | 
|---|
| 335 | /// ```rust | 
|---|
| 336 | /// # use colored::*; | 
|---|
| 337 | /// let colored = "".bold().italic(); | 
|---|
| 338 | /// assert_eq!(colored.style.contains(Styles::Bold), true); | 
|---|
| 339 | /// assert_eq!(colored.style.contains(Styles::Italic), true); | 
|---|
| 340 | /// assert_eq!(colored.style.contains(Styles::Dimmed), false); | 
|---|
| 341 | /// ``` | 
|---|
| 342 | pub fn contains(self, style: Styles) -> bool { | 
|---|
| 343 | let s = style.to_u8(); | 
|---|
| 344 | self.0 & s == s | 
|---|
| 345 | } | 
|---|
| 346 |  | 
|---|
| 347 | pub(crate) fn to_str(self) -> String { | 
|---|
| 348 | let styles = Styles::from_u8(self.0).unwrap_or_default(); | 
|---|
| 349 | styles | 
|---|
| 350 | .iter() | 
|---|
| 351 | .map(|s| s.to_str()) | 
|---|
| 352 | .collect::<Vec<&str>>() | 
|---|
| 353 | .join( ";") | 
|---|
| 354 | } | 
|---|
| 355 |  | 
|---|
| 356 | /// Adds the `two` style switch to this Style. | 
|---|
| 357 | /// | 
|---|
| 358 | /// ```rust | 
|---|
| 359 | /// # use colored::*; | 
|---|
| 360 | /// let cstr = "".red().bold(); | 
|---|
| 361 | /// let mut style = cstr.style; | 
|---|
| 362 | /// style.add(Styles::Italic); | 
|---|
| 363 | /// let mut cstr2 = "".blue(); | 
|---|
| 364 | /// cstr2.style = style; | 
|---|
| 365 | /// | 
|---|
| 366 | /// assert!(cstr2.style.contains(Styles::Bold)); | 
|---|
| 367 | /// assert!(cstr2.style.contains(Styles::Italic)); | 
|---|
| 368 | /// assert_eq!(cstr2.fgcolor, Some(Color::Blue)); | 
|---|
| 369 | /// ``` | 
|---|
| 370 | pub fn add(&mut self, two: Styles) { | 
|---|
| 371 | self.0 |= two.to_u8(); | 
|---|
| 372 | } | 
|---|
| 373 |  | 
|---|
| 374 | /// Turns off a style switch. | 
|---|
| 375 | /// | 
|---|
| 376 | /// ```rust | 
|---|
| 377 | /// use colored::*; | 
|---|
| 378 | /// let cstr = "".red().bold().italic(); | 
|---|
| 379 | /// let mut style = cstr.style; | 
|---|
| 380 | /// style.remove(Styles::Italic); | 
|---|
| 381 | /// let mut cstr2 = "".blue(); | 
|---|
| 382 | /// cstr2.style = style; | 
|---|
| 383 | /// assert!(cstr2.style.contains(Styles::Bold)); | 
|---|
| 384 | /// assert!(!cstr2.style.contains(Styles::Italic)); | 
|---|
| 385 | /// assert_eq!(cstr2.fgcolor, Some(Color::Blue)); | 
|---|
| 386 | /// ``` | 
|---|
| 387 | pub fn remove(&mut self, two: Styles) { | 
|---|
| 388 | self.0 &= !two.to_u8(); | 
|---|
| 389 | } | 
|---|
| 390 |  | 
|---|
| 391 | /// Makes this `Style` include Bold. | 
|---|
| 392 | pub fn bold(mut self) -> Self { | 
|---|
| 393 | self.add(Styles::Bold); | 
|---|
| 394 | self | 
|---|
| 395 | } | 
|---|
| 396 |  | 
|---|
| 397 | /// Makes this `Style` include Dimmed. | 
|---|
| 398 | pub fn dimmed(mut self) -> Self { | 
|---|
| 399 | self.add(Styles::Dimmed); | 
|---|
| 400 | self | 
|---|
| 401 | } | 
|---|
| 402 |  | 
|---|
| 403 | /// Makes this `Style` include Underline. | 
|---|
| 404 | pub fn underline(mut self) -> Self { | 
|---|
| 405 | self.add(Styles::Underline); | 
|---|
| 406 | self | 
|---|
| 407 | } | 
|---|
| 408 |  | 
|---|
| 409 | /// Makes this `Style` include Reversed. | 
|---|
| 410 | pub fn reversed(mut self) -> Self { | 
|---|
| 411 | self.add(Styles::Reversed); | 
|---|
| 412 | self | 
|---|
| 413 | } | 
|---|
| 414 |  | 
|---|
| 415 | /// Makes this `Style` include Italic. | 
|---|
| 416 | pub fn italic(mut self) -> Self { | 
|---|
| 417 | self.add(Styles::Italic); | 
|---|
| 418 | self | 
|---|
| 419 | } | 
|---|
| 420 |  | 
|---|
| 421 | /// Makes this `Style` include Blink. | 
|---|
| 422 | pub fn blink(mut self) -> Self { | 
|---|
| 423 | self.add(Styles::Blink); | 
|---|
| 424 | self | 
|---|
| 425 | } | 
|---|
| 426 |  | 
|---|
| 427 | /// Makes this `Style` include Hidden. | 
|---|
| 428 | pub fn hidden(mut self) -> Self { | 
|---|
| 429 | self.add(Styles::Hidden); | 
|---|
| 430 | self | 
|---|
| 431 | } | 
|---|
| 432 |  | 
|---|
| 433 | /// Makes this `Style` include Strikethrough. | 
|---|
| 434 | pub fn strikethrough(mut self) -> Self { | 
|---|
| 435 | self.add(Styles::Strikethrough); | 
|---|
| 436 | self | 
|---|
| 437 | } | 
|---|
| 438 | } | 
|---|
| 439 |  | 
|---|
| 440 | impl BitAnd<Style> for Style { | 
|---|
| 441 | type Output = Style; | 
|---|
| 442 |  | 
|---|
| 443 | fn bitand(self, rhs: Style) -> Self::Output { | 
|---|
| 444 | Style(self.0 & rhs.0) | 
|---|
| 445 | } | 
|---|
| 446 | } | 
|---|
| 447 |  | 
|---|
| 448 | auto_impl_ref_binop_trait!(impl BitAnd, bitand for Style, Style); | 
|---|
| 449 |  | 
|---|
| 450 | impl BitAnd<Styles> for Style { | 
|---|
| 451 | type Output = Style; | 
|---|
| 452 |  | 
|---|
| 453 | fn bitand(self, rhs: Styles) -> Self::Output { | 
|---|
| 454 | Style(self.0 & rhs.to_u8()) | 
|---|
| 455 | } | 
|---|
| 456 | } | 
|---|
| 457 |  | 
|---|
| 458 | auto_impl_ref_binop_trait!(impl BitAnd, bitand for Style, Styles); | 
|---|
| 459 |  | 
|---|
| 460 | impl BitOr<Style> for Style { | 
|---|
| 461 | type Output = Style; | 
|---|
| 462 |  | 
|---|
| 463 | fn bitor(self, rhs: Style) -> Self::Output { | 
|---|
| 464 | Style(self.0 | rhs.0) | 
|---|
| 465 | } | 
|---|
| 466 | } | 
|---|
| 467 |  | 
|---|
| 468 | auto_impl_ref_binop_trait!(impl BitOr, bitor for Style, Style); | 
|---|
| 469 |  | 
|---|
| 470 | impl BitOr<Styles> for Style { | 
|---|
| 471 | type Output = Style; | 
|---|
| 472 |  | 
|---|
| 473 | fn bitor(self, rhs: Styles) -> Self::Output { | 
|---|
| 474 | Style(self.0 | rhs.to_u8()) | 
|---|
| 475 | } | 
|---|
| 476 | } | 
|---|
| 477 |  | 
|---|
| 478 | auto_impl_ref_binop_trait!(impl BitOr, bitor for Style, Styles); | 
|---|
| 479 |  | 
|---|
| 480 | impl BitXor<Style> for Style { | 
|---|
| 481 | type Output = Style; | 
|---|
| 482 |  | 
|---|
| 483 | fn bitxor(self, rhs: Style) -> Self::Output { | 
|---|
| 484 | Style(self.0 ^ rhs.0) | 
|---|
| 485 | } | 
|---|
| 486 | } | 
|---|
| 487 |  | 
|---|
| 488 | auto_impl_ref_binop_trait!(impl BitXor, bitxor for Style, Style); | 
|---|
| 489 |  | 
|---|
| 490 | impl BitXor<Styles> for Style { | 
|---|
| 491 | type Output = Style; | 
|---|
| 492 |  | 
|---|
| 493 | fn bitxor(self, rhs: Styles) -> Self::Output { | 
|---|
| 494 | Style(self.0 ^ rhs.to_u8()) | 
|---|
| 495 | } | 
|---|
| 496 | } | 
|---|
| 497 |  | 
|---|
| 498 | auto_impl_ref_binop_trait!(impl BitXor, bitxor for Style, Styles); | 
|---|
| 499 |  | 
|---|
| 500 | impl Not for Style { | 
|---|
| 501 | type Output = Style; | 
|---|
| 502 |  | 
|---|
| 503 | fn not(self) -> Self::Output { | 
|---|
| 504 | Style(!self.0) | 
|---|
| 505 | } | 
|---|
| 506 | } | 
|---|
| 507 |  | 
|---|
| 508 | impl Not for &Style { | 
|---|
| 509 | type Output = Style; | 
|---|
| 510 |  | 
|---|
| 511 | fn not(self) -> Self::Output { | 
|---|
| 512 | Style(!self.0) | 
|---|
| 513 | } | 
|---|
| 514 | } | 
|---|
| 515 |  | 
|---|
| 516 | impl_assign_op_trait!(BitAndAssign, bitand_assign for Style, Style, using BitAnd::bitand); | 
|---|
| 517 |  | 
|---|
| 518 | impl_assign_op_trait!(BitAndAssign, bitand_assign for Style, Styles, using BitAnd::bitand); | 
|---|
| 519 |  | 
|---|
| 520 | impl_assign_op_trait!(BitOrAssign, bitor_assign for Style, Style, using BitOr::bitor); | 
|---|
| 521 |  | 
|---|
| 522 | impl_assign_op_trait!(BitOrAssign, bitor_assign for Style, Styles, using BitOr::bitor); | 
|---|
| 523 |  | 
|---|
| 524 | impl_assign_op_trait!(BitXorAssign, bitxor_assign for Style, Style, using BitXor::bitxor); | 
|---|
| 525 |  | 
|---|
| 526 | impl_assign_op_trait!(BitXorAssign, bitxor_assign for Style, Styles, using BitXor::bitxor); | 
|---|
| 527 |  | 
|---|
| 528 | impl Default for Style { | 
|---|
| 529 | fn default() -> Self { | 
|---|
| 530 | CLEAR | 
|---|
| 531 | } | 
|---|
| 532 | } | 
|---|
| 533 |  | 
|---|
| 534 | impl From<Styles> for Style { | 
|---|
| 535 | fn from(value: Styles) -> Self { | 
|---|
| 536 | Style(value.to_u8()) | 
|---|
| 537 | } | 
|---|
| 538 | } | 
|---|
| 539 |  | 
|---|
| 540 | impl From<&Styles> for Style { | 
|---|
| 541 | fn from(value: &Styles) -> Self { | 
|---|
| 542 | Style(value.to_u8()) | 
|---|
| 543 | } | 
|---|
| 544 | } | 
|---|
| 545 |  | 
|---|
| 546 | impl FromIterator<Styles> for Style { | 
|---|
| 547 | fn from_iter<T: IntoIterator<Item = Styles>>(iter: T) -> Self { | 
|---|
| 548 | let mut style: Style = Style::default(); | 
|---|
| 549 | for styles: Styles in iter.into_iter() { | 
|---|
| 550 | style.add(two:styles); | 
|---|
| 551 | } | 
|---|
| 552 | style | 
|---|
| 553 | } | 
|---|
| 554 | } | 
|---|
| 555 |  | 
|---|
| 556 | #[ cfg(test)] | 
|---|
| 557 | mod tests { | 
|---|
| 558 | use super::*; | 
|---|
| 559 |  | 
|---|
| 560 | mod u8_to_styles_invalid_is_none { | 
|---|
| 561 | use super::super::Styles; | 
|---|
| 562 | use super::super::CLEARV; | 
|---|
| 563 |  | 
|---|
| 564 | #[ test] | 
|---|
| 565 | fn empty_is_none() { | 
|---|
| 566 | assert_eq!(None, Styles::from_u8(CLEARV)); | 
|---|
| 567 | } | 
|---|
| 568 | } | 
|---|
| 569 |  | 
|---|
| 570 | mod u8_to_styles_isomorphism { | 
|---|
| 571 | use super::super::Styles; | 
|---|
| 572 | use super::super::{ | 
|---|
| 573 | BLINK, BOLD, DIMMED, HIDDEN, ITALIC, REVERSED, STRIKETHROUGH, UNDERLINE, | 
|---|
| 574 | }; | 
|---|
| 575 |  | 
|---|
| 576 | macro_rules! value_isomorph { | 
|---|
| 577 | ($name:ident, $value:expr) => { | 
|---|
| 578 | #[test] | 
|---|
| 579 | fn $name() { | 
|---|
| 580 | let u = Styles::from_u8($value); | 
|---|
| 581 | assert!( | 
|---|
| 582 | u.is_some(), | 
|---|
| 583 | "{}: Styles::from_u8 -> None", | 
|---|
| 584 | stringify!($value) | 
|---|
| 585 | ); | 
|---|
| 586 | let u = u.unwrap(); | 
|---|
| 587 | assert!( | 
|---|
| 588 | u.len() == 1, | 
|---|
| 589 | "{}: Styles::from_u8 found {} styles (expected 1)", | 
|---|
| 590 | stringify!($value), | 
|---|
| 591 | u.len() | 
|---|
| 592 | ); | 
|---|
| 593 | assert!( | 
|---|
| 594 | u[0].to_u8() == $value, | 
|---|
| 595 | "{}: to_u8() doesn't match its const value", | 
|---|
| 596 | stringify!($value) | 
|---|
| 597 | ); | 
|---|
| 598 | } | 
|---|
| 599 | }; | 
|---|
| 600 | } | 
|---|
| 601 |  | 
|---|
| 602 | value_isomorph!(bold, BOLD); | 
|---|
| 603 | value_isomorph!(underline, UNDERLINE); | 
|---|
| 604 | value_isomorph!(reversed, REVERSED); | 
|---|
| 605 | value_isomorph!(italic, ITALIC); | 
|---|
| 606 | value_isomorph!(blink, BLINK); | 
|---|
| 607 | value_isomorph!(hidden, HIDDEN); | 
|---|
| 608 | value_isomorph!(dimmed, DIMMED); | 
|---|
| 609 | value_isomorph!(strikethrough, STRIKETHROUGH); | 
|---|
| 610 | } | 
|---|
| 611 |  | 
|---|
| 612 | mod styles_combine_complex { | 
|---|
| 613 | use super::super::Styles::*; | 
|---|
| 614 | use super::super::{Style, Styles}; | 
|---|
| 615 |  | 
|---|
| 616 | fn style_from_multiples(styles: &[Styles]) -> Style { | 
|---|
| 617 | let mut res = Style(styles[0].to_u8()); | 
|---|
| 618 | for s in &styles[1..] { | 
|---|
| 619 | res = Style(res.0 | s.to_u8()); | 
|---|
| 620 | } | 
|---|
| 621 | res | 
|---|
| 622 | } | 
|---|
| 623 |  | 
|---|
| 624 | macro_rules! test_aggreg { | 
|---|
| 625 | ($styles:expr, $expect:expr) => {{ | 
|---|
| 626 | let v = style_from_multiples($styles); | 
|---|
| 627 | let r = Styles::from_u8(v.0).expect( "should find styles"); | 
|---|
| 628 | assert_eq!(&$expect as &[Styles], &r[..]) | 
|---|
| 629 | }}; | 
|---|
| 630 | } | 
|---|
| 631 |  | 
|---|
| 632 | #[ test] | 
|---|
| 633 | fn aggreg1() { | 
|---|
| 634 | let styles: &[Styles] = &[Bold, Bold, Bold]; | 
|---|
| 635 | test_aggreg!(styles, [Bold]); | 
|---|
| 636 | } | 
|---|
| 637 |  | 
|---|
| 638 | #[ test] | 
|---|
| 639 | fn aggreg2() { | 
|---|
| 640 | let styles: &[Styles] = &[Italic, Italic, Bold, Bold]; | 
|---|
| 641 | test_aggreg!(styles, [Bold, Italic]); | 
|---|
| 642 | } | 
|---|
| 643 |  | 
|---|
| 644 | #[ test] | 
|---|
| 645 | fn aggreg3() { | 
|---|
| 646 | let styles: &[Styles] = &[Bold, Italic, Bold]; | 
|---|
| 647 | test_aggreg!(styles, [Bold, Italic]); | 
|---|
| 648 | } | 
|---|
| 649 |  | 
|---|
| 650 | macro_rules! test_combine { | 
|---|
| 651 | ($styles:expr) => {{ | 
|---|
| 652 | let v = style_from_multiples($styles); | 
|---|
| 653 | let r = Styles::from_u8(v.0).expect( "should find styles"); | 
|---|
| 654 | assert_eq!($styles, &r[..]) | 
|---|
| 655 | }}; | 
|---|
| 656 | } | 
|---|
| 657 |  | 
|---|
| 658 | #[ test] | 
|---|
| 659 | fn two1() { | 
|---|
| 660 | let s: &[Styles] = &[Bold, Underline]; | 
|---|
| 661 | test_combine!(s); | 
|---|
| 662 | } | 
|---|
| 663 |  | 
|---|
| 664 | #[ test] | 
|---|
| 665 | fn two2() { | 
|---|
| 666 | let s: &[Styles] = &[Underline, Italic]; | 
|---|
| 667 | test_combine!(s); | 
|---|
| 668 | } | 
|---|
| 669 |  | 
|---|
| 670 | #[ test] | 
|---|
| 671 | fn two3() { | 
|---|
| 672 | let s: &[Styles] = &[Bold, Italic]; | 
|---|
| 673 | test_combine!(s); | 
|---|
| 674 | } | 
|---|
| 675 |  | 
|---|
| 676 | #[ test] | 
|---|
| 677 | fn three1() { | 
|---|
| 678 | let s: &[Styles] = &[Bold, Underline, Italic]; | 
|---|
| 679 | test_combine!(s); | 
|---|
| 680 | } | 
|---|
| 681 |  | 
|---|
| 682 | #[ test] | 
|---|
| 683 | fn three2() { | 
|---|
| 684 | let s: &[Styles] = &[Dimmed, Underline, Italic]; | 
|---|
| 685 | test_combine!(s); | 
|---|
| 686 | } | 
|---|
| 687 |  | 
|---|
| 688 | #[ test] | 
|---|
| 689 | fn four() { | 
|---|
| 690 | let s: &[Styles] = &[Dimmed, Underline, Italic, Hidden]; | 
|---|
| 691 | test_combine!(s); | 
|---|
| 692 | } | 
|---|
| 693 |  | 
|---|
| 694 | #[ test] | 
|---|
| 695 | fn five() { | 
|---|
| 696 | let s: &[Styles] = &[Dimmed, Underline, Italic, Blink, Hidden]; | 
|---|
| 697 | test_combine!(s); | 
|---|
| 698 | } | 
|---|
| 699 |  | 
|---|
| 700 | #[ test] | 
|---|
| 701 | fn six() { | 
|---|
| 702 | let s: &[Styles] = &[Bold, Dimmed, Underline, Italic, Blink, Hidden]; | 
|---|
| 703 | test_combine!(s); | 
|---|
| 704 | } | 
|---|
| 705 |  | 
|---|
| 706 | #[ test] | 
|---|
| 707 | fn all() { | 
|---|
| 708 | let s: &[Styles] = &[ | 
|---|
| 709 | Bold, | 
|---|
| 710 | Dimmed, | 
|---|
| 711 | Underline, | 
|---|
| 712 | Reversed, | 
|---|
| 713 | Italic, | 
|---|
| 714 | Blink, | 
|---|
| 715 | Hidden, | 
|---|
| 716 | Strikethrough, | 
|---|
| 717 | ]; | 
|---|
| 718 | test_combine!(s); | 
|---|
| 719 | } | 
|---|
| 720 | } | 
|---|
| 721 |  | 
|---|
| 722 | #[ test] | 
|---|
| 723 | fn test_style_contains() { | 
|---|
| 724 | let mut style = Style(Styles::Bold.to_u8()); | 
|---|
| 725 | style.add(Styles::Italic); | 
|---|
| 726 |  | 
|---|
| 727 | assert!(style.contains(Styles::Bold)); | 
|---|
| 728 | assert!(style.contains(Styles::Italic)); | 
|---|
| 729 | assert!(!style.contains(Styles::Dimmed)); | 
|---|
| 730 | } | 
|---|
| 731 |  | 
|---|
| 732 | mod style_bitwise_logic { | 
|---|
| 733 | use super::*; | 
|---|
| 734 |  | 
|---|
| 735 | macro_rules! check_impl { | 
|---|
| 736 | ($lh:expr, $method:path, $rh:expr => $res:expr) => { | 
|---|
| 737 | assert_eq!($method($lh, $rh), $res); | 
|---|
| 738 | assert_eq!($method(&$lh, $rh), $res); | 
|---|
| 739 | assert_eq!($method($lh, &$rh), $res); | 
|---|
| 740 | assert_eq!($method(&$lh, &$rh), $res); | 
|---|
| 741 | }; | 
|---|
| 742 | } | 
|---|
| 743 |  | 
|---|
| 744 | macro_rules! check_impl_reflexive { | 
|---|
| 745 | ($lh:expr, $method:path, $rh:expr => $res:expr) => { | 
|---|
| 746 | check_impl!($lh, $method, $rh => $res); | 
|---|
| 747 | check_impl!($rh, $method, $lh => $res); | 
|---|
| 748 | } | 
|---|
| 749 | } | 
|---|
| 750 |  | 
|---|
| 751 | /// TTABLE = TRUTH_TABLE | 
|---|
| 752 | const TTABLE: (u8, u8) = (0b0101, 0b0011); | 
|---|
| 753 |  | 
|---|
| 754 | #[ test] | 
|---|
| 755 | fn binops() { | 
|---|
| 756 | let tstyle_l = Style(TTABLE.0); | 
|---|
| 757 | let tstyle_r = Style(TTABLE.1); | 
|---|
| 758 | let and_res = Style(TTABLE.0 & TTABLE.1); | 
|---|
| 759 | let or_res = Style(TTABLE.0 | TTABLE.1); | 
|---|
| 760 | let xor_res = Style(TTABLE.0 ^ TTABLE.1); | 
|---|
| 761 |  | 
|---|
| 762 | check_impl!(tstyle_l, BitAnd::bitand, tstyle_r => and_res); | 
|---|
| 763 | check_impl!(tstyle_l, BitOr::bitor, tstyle_r => or_res); | 
|---|
| 764 | check_impl!(tstyle_l, BitXor::bitxor, tstyle_r => xor_res); | 
|---|
| 765 | } | 
|---|
| 766 |  | 
|---|
| 767 | #[ test] | 
|---|
| 768 | fn binops_with_styles() { | 
|---|
| 769 | let bold_underline = Style(0b0011); | 
|---|
| 770 |  | 
|---|
| 771 | check_impl_reflexive!( | 
|---|
| 772 | bold_underline, | 
|---|
| 773 | BitAnd::bitand, | 
|---|
| 774 | Styles::Bold | 
|---|
| 775 | => Style(0b0000_0001) | 
|---|
| 776 | ); | 
|---|
| 777 | check_impl_reflexive!( | 
|---|
| 778 | bold_underline, | 
|---|
| 779 | BitOr::bitor, | 
|---|
| 780 | Styles::Reversed | 
|---|
| 781 | => Style(0b0000_0111) | 
|---|
| 782 | ); | 
|---|
| 783 | check_impl_reflexive!( | 
|---|
| 784 | bold_underline, | 
|---|
| 785 | BitXor::bitxor, | 
|---|
| 786 | Styles::Underline | 
|---|
| 787 | => Style(0b0000_0001) | 
|---|
| 788 | ); | 
|---|
| 789 | } | 
|---|
| 790 |  | 
|---|
| 791 | #[ test] | 
|---|
| 792 | fn not() { | 
|---|
| 793 | let not_bold = !Style(BOLD); | 
|---|
| 794 | assert!(!not_bold.contains(Styles::Bold)); | 
|---|
| 795 | assert!(not_bold.contains(Styles::Strikethrough)); | 
|---|
| 796 | assert_eq!(!Style(0b0011_0101), Style(0b1100_1010)); | 
|---|
| 797 | } | 
|---|
| 798 |  | 
|---|
| 799 | #[ test] | 
|---|
| 800 | fn assign_ops() { | 
|---|
| 801 | let original_style = Style(0b0011); | 
|---|
| 802 | let op_style = Style(0b0101); | 
|---|
| 803 |  | 
|---|
| 804 | let mut style = original_style; | 
|---|
| 805 | style &= op_style; | 
|---|
| 806 | assert_eq!(style, Style(0b0001)); | 
|---|
| 807 |  | 
|---|
| 808 | style = original_style; | 
|---|
| 809 | style |= op_style; | 
|---|
| 810 | assert_eq!(style, Style(0b0111)); | 
|---|
| 811 |  | 
|---|
| 812 | style = original_style; | 
|---|
| 813 | style ^= op_style; | 
|---|
| 814 | assert_eq!(style, Style(0b0110)); | 
|---|
| 815 | } | 
|---|
| 816 |  | 
|---|
| 817 | #[ test] | 
|---|
| 818 | fn assign_ops_with_styles() { | 
|---|
| 819 | let original_style = Style(0b0011); | 
|---|
| 820 |  | 
|---|
| 821 | let mut style = original_style; | 
|---|
| 822 | style &= Styles::Bold; | 
|---|
| 823 | assert_eq!(style, Style(0b0001)); | 
|---|
| 824 |  | 
|---|
| 825 | style = original_style; | 
|---|
| 826 | style |= Styles::Reversed; | 
|---|
| 827 | assert_eq!(style, Style(0b0111)); | 
|---|
| 828 |  | 
|---|
| 829 | style = original_style; | 
|---|
| 830 | style ^= Styles::Bold; | 
|---|
| 831 | assert_eq!(style, Style(0b0010)); | 
|---|
| 832 | } | 
|---|
| 833 |  | 
|---|
| 834 | #[ test] | 
|---|
| 835 | fn styles_binops() { | 
|---|
| 836 | check_impl!( | 
|---|
| 837 | Styles::Bold, | 
|---|
| 838 | BitAnd::bitand, | 
|---|
| 839 | Styles::Bold | 
|---|
| 840 | => Style(0b0000_0001) | 
|---|
| 841 | ); | 
|---|
| 842 | // The check_impl is only to verify it works with all the combos | 
|---|
| 843 | // of refs. We already know it compines so let's spare ourselves | 
|---|
| 844 | // the extra assertions. | 
|---|
| 845 | assert_eq!(Styles::Bold & Styles::Underline, Style(0b0000_0000)); | 
|---|
| 846 |  | 
|---|
| 847 | check_impl!( | 
|---|
| 848 | Styles::Bold, | 
|---|
| 849 | BitOr::bitor, | 
|---|
| 850 | Styles::Underline | 
|---|
| 851 | => Style(0b0000_0011) | 
|---|
| 852 | ); | 
|---|
| 853 | assert_eq!(Styles::Bold | Styles::Bold, Style(0b0000_0001)); | 
|---|
| 854 |  | 
|---|
| 855 | check_impl!( | 
|---|
| 856 | Styles::Bold, | 
|---|
| 857 | BitXor::bitxor, | 
|---|
| 858 | Styles::Underline | 
|---|
| 859 | => Style(0b0000_0011) | 
|---|
| 860 | ); | 
|---|
| 861 | assert_eq!(Styles::Bold ^ Styles::Bold, Style(0b0000_0000)); | 
|---|
| 862 | } | 
|---|
| 863 |  | 
|---|
| 864 | #[ test] | 
|---|
| 865 | fn styles_not() { | 
|---|
| 866 | let not_bold = !Styles::Bold; | 
|---|
| 867 | assert_eq!(not_bold, Style(!BOLD)); | 
|---|
| 868 | } | 
|---|
| 869 | } | 
|---|
| 870 | } | 
|---|
| 871 |  | 
|---|