colored/
style.rs

1use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
2
3macro_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
34macro_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
54const CLEARV: u8 = 0b0000_0000;
55const BOLD: u8 = 0b0000_0001;
56const UNDERLINE: u8 = 0b0000_0010;
57const REVERSED: u8 = 0b0000_0100;
58const ITALIC: u8 = 0b0000_1000;
59const BLINK: u8 = 0b0001_0000;
60const HIDDEN: u8 = 0b0010_0000;
61const DIMMED: u8 = 0b0100_0000;
62const STRIKETHROUGH: u8 = 0b1000_0000;
63
64static 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
75pub 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)]
158pub 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)]
197pub enum Styles {
198    Clear,
199    Bold,
200    Dimmed,
201    Underline,
202    Reversed,
203    Italic,
204    Blink,
205    Hidden,
206    Strikethrough,
207}
208
209impl 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
256impl 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
264auto_impl_ref_binop_trait!(impl BitAnd, bitand for Styles, Styles);
265
266impl 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
274auto_impl_ref_binop_trait!(impl BitAnd, bitand for Styles, Style);
275
276impl 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
284auto_impl_ref_binop_trait!(impl BitOr, bitor for Styles, Styles);
285
286impl 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
294auto_impl_ref_binop_trait!(impl BitOr, bitor for Styles, Style);
295
296impl 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
304auto_impl_ref_binop_trait!(impl BitXor, bitxor for Styles, Styles);
305
306impl 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
314auto_impl_ref_binop_trait!(impl BitXor, bitxor for Styles, Style);
315
316impl Not for Styles {
317    type Output = Style;
318
319    fn not(self) -> Self::Output {
320        Style(!self.to_u8())
321    }
322}
323
324impl Not for &Styles {
325    type Output = Style;
326
327    fn not(self) -> Self::Output {
328        Style(!self.to_u8())
329    }
330}
331
332impl 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
440impl 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
448auto_impl_ref_binop_trait!(impl BitAnd, bitand for Style, Style);
449
450impl 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
458auto_impl_ref_binop_trait!(impl BitAnd, bitand for Style, Styles);
459
460impl 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
468auto_impl_ref_binop_trait!(impl BitOr, bitor for Style, Style);
469
470impl 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
478auto_impl_ref_binop_trait!(impl BitOr, bitor for Style, Styles);
479
480impl 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
488auto_impl_ref_binop_trait!(impl BitXor, bitxor for Style, Style);
489
490impl 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
498auto_impl_ref_binop_trait!(impl BitXor, bitxor for Style, Styles);
499
500impl Not for Style {
501    type Output = Style;
502
503    fn not(self) -> Self::Output {
504        Style(!self.0)
505    }
506}
507
508impl Not for &Style {
509    type Output = Style;
510
511    fn not(self) -> Self::Output {
512        Style(!self.0)
513    }
514}
515
516impl_assign_op_trait!(BitAndAssign, bitand_assign for Style, Style, using BitAnd::bitand);
517
518impl_assign_op_trait!(BitAndAssign, bitand_assign for Style, Styles, using BitAnd::bitand);
519
520impl_assign_op_trait!(BitOrAssign, bitor_assign for Style, Style, using BitOr::bitor);
521
522impl_assign_op_trait!(BitOrAssign, bitor_assign for Style, Styles, using BitOr::bitor);
523
524impl_assign_op_trait!(BitXorAssign, bitxor_assign for Style, Style, using BitXor::bitxor);
525
526impl_assign_op_trait!(BitXorAssign, bitxor_assign for Style, Styles, using BitXor::bitxor);
527
528impl Default for Style {
529    fn default() -> Self {
530        CLEAR
531    }
532}
533
534impl From<Styles> for Style {
535    fn from(value: Styles) -> Self {
536        Style(value.to_u8())
537    }
538}
539
540impl From<&Styles> for Style {
541    fn from(value: &Styles) -> Self {
542        Style(value.to_u8())
543    }
544}
545
546impl FromIterator<Styles> for Style {
547    fn from_iter<T: IntoIterator<Item = Styles>>(iter: T) -> Self {
548        let mut style = Style::default();
549        for styles in iter.into_iter() {
550            style.add(styles);
551        }
552        style
553    }
554}
555
556#[cfg(test)]
557mod 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}