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#[derive(Clone, Copy, PartialEq, Eq, Debug)]
158pub struct Style(u8);
159
160#[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 => "", 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 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 pub fn add(&mut self, two: Styles) {
371 self.0 |= two.to_u8();
372 }
373
374 pub fn remove(&mut self, two: Styles) {
388 self.0 &= !two.to_u8();
389 }
390
391 pub fn bold(mut self) -> Self {
393 self.add(Styles::Bold);
394 self
395 }
396
397 pub fn dimmed(mut self) -> Self {
399 self.add(Styles::Dimmed);
400 self
401 }
402
403 pub fn underline(mut self) -> Self {
405 self.add(Styles::Underline);
406 self
407 }
408
409 pub fn reversed(mut self) -> Self {
411 self.add(Styles::Reversed);
412 self
413 }
414
415 pub fn italic(mut self) -> Self {
417 self.add(Styles::Italic);
418 self
419 }
420
421 pub fn blink(mut self) -> Self {
423 self.add(Styles::Blink);
424 self
425 }
426
427 pub fn hidden(mut self) -> Self {
429 self.add(Styles::Hidden);
430 self
431 }
432
433 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 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 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}