1mod color;
7mod theme;
8pub use color::{Color, ColorDepth};
9pub use theme::{Theme, ThemeBuilder};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum Breakpoint {
17 Xs,
19 Sm,
21 Md,
23 Lg,
25 Xl,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub enum Border {
36 Single,
38 Double,
40 Rounded,
42 Thick,
44 Dashed,
46 DashedThick,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
55pub struct BorderChars {
56 pub tl: char,
58 pub tr: char,
60 pub bl: char,
62 pub br: char,
64 pub h: char,
66 pub v: char,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73pub struct BorderSides {
74 pub top: bool,
75 pub right: bool,
76 pub bottom: bool,
77 pub left: bool,
78}
79
80impl BorderSides {
81 pub const fn all() -> Self {
82 Self {
83 top: true,
84 right: true,
85 bottom: true,
86 left: true,
87 }
88 }
89
90 pub const fn none() -> Self {
91 Self {
92 top: false,
93 right: false,
94 bottom: false,
95 left: false,
96 }
97 }
98
99 pub const fn horizontal() -> Self {
100 Self {
101 top: true,
102 right: false,
103 bottom: true,
104 left: false,
105 }
106 }
107
108 pub const fn vertical() -> Self {
109 Self {
110 top: false,
111 right: true,
112 bottom: false,
113 left: true,
114 }
115 }
116
117 pub fn has_horizontal(&self) -> bool {
118 self.top || self.bottom
119 }
120
121 pub fn has_vertical(&self) -> bool {
122 self.left || self.right
123 }
124}
125
126impl Default for BorderSides {
127 fn default() -> Self {
128 Self::all()
129 }
130}
131
132impl Border {
133 pub const fn chars(self) -> BorderChars {
135 match self {
136 Self::Single => BorderChars {
137 tl: '┌',
138 tr: '┐',
139 bl: '└',
140 br: '┘',
141 h: '─',
142 v: '│',
143 },
144 Self::Double => BorderChars {
145 tl: '╔',
146 tr: '╗',
147 bl: '╚',
148 br: '╝',
149 h: '═',
150 v: '║',
151 },
152 Self::Rounded => BorderChars {
153 tl: '╭',
154 tr: '╮',
155 bl: '╰',
156 br: '╯',
157 h: '─',
158 v: '│',
159 },
160 Self::Thick => BorderChars {
161 tl: '┏',
162 tr: '┓',
163 bl: '┗',
164 br: '┛',
165 h: '━',
166 v: '┃',
167 },
168 Self::Dashed => BorderChars {
169 tl: '┌',
170 tr: '┐',
171 bl: '└',
172 br: '┘',
173 h: '┄',
174 v: '┆',
175 },
176 Self::DashedThick => BorderChars {
177 tl: '┏',
178 tr: '┓',
179 bl: '┗',
180 br: '┛',
181 h: '┅',
182 v: '┇',
183 },
184 }
185 }
186}
187
188#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
193#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
194pub struct Padding {
195 pub top: u32,
197 pub right: u32,
199 pub bottom: u32,
201 pub left: u32,
203}
204
205impl Padding {
206 pub const fn all(v: u32) -> Self {
208 Self::new(v, v, v, v)
209 }
210
211 pub const fn xy(x: u32, y: u32) -> Self {
213 Self::new(y, x, y, x)
214 }
215
216 pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
218 Self {
219 top,
220 right,
221 bottom,
222 left,
223 }
224 }
225
226 pub const fn horizontal(self) -> u32 {
228 self.left + self.right
229 }
230
231 pub const fn vertical(self) -> u32 {
233 self.top + self.bottom
234 }
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
242#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
243pub struct Margin {
244 pub top: u32,
246 pub right: u32,
248 pub bottom: u32,
250 pub left: u32,
252}
253
254impl Margin {
255 pub const fn all(v: u32) -> Self {
257 Self::new(v, v, v, v)
258 }
259
260 pub const fn xy(x: u32, y: u32) -> Self {
262 Self::new(y, x, y, x)
263 }
264
265 pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
267 Self {
268 top,
269 right,
270 bottom,
271 left,
272 }
273 }
274
275 pub const fn horizontal(self) -> u32 {
277 self.left + self.right
278 }
279
280 pub const fn vertical(self) -> u32 {
282 self.top + self.bottom
283 }
284}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
299#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
300#[must_use = "configure constraints using the returned value"]
301pub struct Constraints {
302 pub min_width: Option<u32>,
304 pub max_width: Option<u32>,
306 pub min_height: Option<u32>,
308 pub max_height: Option<u32>,
310 pub width_pct: Option<u8>,
312 pub height_pct: Option<u8>,
314}
315
316impl Constraints {
317 pub const fn min_w(mut self, min_width: u32) -> Self {
319 self.min_width = Some(min_width);
320 self
321 }
322
323 pub const fn max_w(mut self, max_width: u32) -> Self {
325 self.max_width = Some(max_width);
326 self
327 }
328
329 pub const fn min_h(mut self, min_height: u32) -> Self {
331 self.min_height = Some(min_height);
332 self
333 }
334
335 pub const fn max_h(mut self, max_height: u32) -> Self {
337 self.max_height = Some(max_height);
338 self
339 }
340
341 pub const fn w_pct(mut self, pct: u8) -> Self {
343 self.width_pct = Some(pct);
344 self
345 }
346
347 pub const fn h_pct(mut self, pct: u8) -> Self {
349 self.height_pct = Some(pct);
350 self
351 }
352}
353
354#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
360#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
361pub enum Align {
362 #[default]
364 Start,
365 Center,
367 End,
369}
370
371#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
380#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
381pub enum Justify {
382 #[default]
384 Start,
385 Center,
387 End,
389 SpaceBetween,
391 SpaceAround,
393 SpaceEvenly,
395}
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
402#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
403#[cfg_attr(feature = "serde", serde(transparent))]
404pub struct Modifiers(pub u8);
405
406impl Modifiers {
407 pub const NONE: Self = Self(0);
409 pub const BOLD: Self = Self(1 << 0);
411 pub const DIM: Self = Self(1 << 1);
413 pub const ITALIC: Self = Self(1 << 2);
415 pub const UNDERLINE: Self = Self(1 << 3);
417 pub const REVERSED: Self = Self(1 << 4);
419 pub const STRIKETHROUGH: Self = Self(1 << 5);
421
422 #[inline]
424 pub fn contains(self, other: Self) -> bool {
425 (self.0 & other.0) == other.0
426 }
427
428 #[inline]
430 pub fn insert(&mut self, other: Self) {
431 self.0 |= other.0;
432 }
433
434 #[inline]
436 pub fn is_empty(self) -> bool {
437 self.0 == 0
438 }
439}
440
441impl std::ops::BitOr for Modifiers {
442 type Output = Self;
443 #[inline]
444 fn bitor(self, rhs: Self) -> Self {
445 Self(self.0 | rhs.0)
446 }
447}
448
449impl std::ops::BitOrAssign for Modifiers {
450 #[inline]
451 fn bitor_assign(&mut self, rhs: Self) {
452 self.0 |= rhs.0;
453 }
454}
455
456#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
470#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
471#[must_use = "build and pass the returned Style value"]
472pub struct Style {
473 pub fg: Option<Color>,
475 pub bg: Option<Color>,
477 pub modifiers: Modifiers,
479}
480
481impl Style {
482 pub const fn new() -> Self {
484 Self {
485 fg: None,
486 bg: None,
487 modifiers: Modifiers::NONE,
488 }
489 }
490
491 pub const fn fg(mut self, color: Color) -> Self {
493 self.fg = Some(color);
494 self
495 }
496
497 pub const fn bg(mut self, color: Color) -> Self {
499 self.bg = Some(color);
500 self
501 }
502
503 pub fn bold(mut self) -> Self {
505 self.modifiers |= Modifiers::BOLD;
506 self
507 }
508
509 pub fn dim(mut self) -> Self {
511 self.modifiers |= Modifiers::DIM;
512 self
513 }
514
515 pub fn italic(mut self) -> Self {
517 self.modifiers |= Modifiers::ITALIC;
518 self
519 }
520
521 pub fn underline(mut self) -> Self {
523 self.modifiers |= Modifiers::UNDERLINE;
524 self
525 }
526
527 pub fn reversed(mut self) -> Self {
529 self.modifiers |= Modifiers::REVERSED;
530 self
531 }
532
533 pub fn strikethrough(mut self) -> Self {
535 self.modifiers |= Modifiers::STRIKETHROUGH;
536 self
537 }
538}
539
540#[derive(Debug, Clone, Copy, Default)]
564pub struct ContainerStyle {
565 pub border: Option<Border>,
567 pub border_sides: Option<BorderSides>,
569 pub border_style: Option<Style>,
571 pub bg: Option<Color>,
573 pub text_color: Option<Color>,
575 pub dark_bg: Option<Color>,
577 pub dark_border_style: Option<Style>,
579 pub padding: Option<Padding>,
581 pub margin: Option<Margin>,
583 pub gap: Option<u32>,
585 pub row_gap: Option<u32>,
587 pub col_gap: Option<u32>,
589 pub grow: Option<u16>,
591 pub align: Option<Align>,
593 pub align_self: Option<Align>,
595 pub justify: Option<Justify>,
597 pub w: Option<u32>,
599 pub h: Option<u32>,
601 pub min_w: Option<u32>,
603 pub max_w: Option<u32>,
605 pub min_h: Option<u32>,
607 pub max_h: Option<u32>,
609 pub w_pct: Option<u8>,
611 pub h_pct: Option<u8>,
613}
614
615impl ContainerStyle {
616 pub const fn new() -> Self {
618 Self {
619 border: None,
620 border_sides: None,
621 border_style: None,
622 bg: None,
623 text_color: None,
624 dark_bg: None,
625 dark_border_style: None,
626 padding: None,
627 margin: None,
628 gap: None,
629 row_gap: None,
630 col_gap: None,
631 grow: None,
632 align: None,
633 align_self: None,
634 justify: None,
635 w: None,
636 h: None,
637 min_w: None,
638 max_w: None,
639 min_h: None,
640 max_h: None,
641 w_pct: None,
642 h_pct: None,
643 }
644 }
645
646 pub const fn border(mut self, border: Border) -> Self {
648 self.border = Some(border);
649 self
650 }
651
652 pub const fn border_sides(mut self, sides: BorderSides) -> Self {
654 self.border_sides = Some(sides);
655 self
656 }
657
658 pub const fn bg(mut self, color: Color) -> Self {
660 self.bg = Some(color);
661 self
662 }
663
664 pub const fn text_color(mut self, color: Color) -> Self {
666 self.text_color = Some(color);
667 self
668 }
669
670 pub const fn dark_bg(mut self, color: Color) -> Self {
672 self.dark_bg = Some(color);
673 self
674 }
675
676 pub const fn p(mut self, value: u32) -> Self {
678 self.padding = Some(Padding {
679 top: value,
680 bottom: value,
681 left: value,
682 right: value,
683 });
684 self
685 }
686
687 pub const fn px(mut self, value: u32) -> Self {
689 let p = match self.padding {
690 Some(p) => Padding {
691 left: value,
692 right: value,
693 ..p
694 },
695 None => Padding {
696 top: 0,
697 bottom: 0,
698 left: value,
699 right: value,
700 },
701 };
702 self.padding = Some(p);
703 self
704 }
705
706 pub const fn py(mut self, value: u32) -> Self {
708 let p = match self.padding {
709 Some(p) => Padding {
710 top: value,
711 bottom: value,
712 ..p
713 },
714 None => Padding {
715 top: value,
716 bottom: value,
717 left: 0,
718 right: 0,
719 },
720 };
721 self.padding = Some(p);
722 self
723 }
724
725 pub const fn m(mut self, value: u32) -> Self {
727 self.margin = Some(Margin {
728 top: value,
729 bottom: value,
730 left: value,
731 right: value,
732 });
733 self
734 }
735
736 pub const fn gap(mut self, value: u32) -> Self {
738 self.gap = Some(value);
739 self
740 }
741
742 pub const fn row_gap(mut self, value: u32) -> Self {
744 self.row_gap = Some(value);
745 self
746 }
747
748 pub const fn col_gap(mut self, value: u32) -> Self {
750 self.col_gap = Some(value);
751 self
752 }
753
754 pub const fn grow(mut self, value: u16) -> Self {
756 self.grow = Some(value);
757 self
758 }
759
760 pub const fn w(mut self, value: u32) -> Self {
762 self.w = Some(value);
763 self
764 }
765
766 pub const fn h(mut self, value: u32) -> Self {
768 self.h = Some(value);
769 self
770 }
771
772 pub const fn min_w(mut self, value: u32) -> Self {
774 self.min_w = Some(value);
775 self
776 }
777
778 pub const fn max_w(mut self, value: u32) -> Self {
780 self.max_w = Some(value);
781 self
782 }
783
784 pub const fn align(mut self, value: Align) -> Self {
786 self.align = Some(value);
787 self
788 }
789
790 pub const fn align_self(mut self, value: Align) -> Self {
792 self.align_self = Some(value);
793 self
794 }
795
796 pub const fn justify(mut self, value: Justify) -> Self {
798 self.justify = Some(value);
799 self
800 }
801
802 pub const fn min_h(mut self, value: u32) -> Self {
804 self.min_h = Some(value);
805 self
806 }
807
808 pub const fn max_h(mut self, value: u32) -> Self {
810 self.max_h = Some(value);
811 self
812 }
813
814 pub const fn w_pct(mut self, value: u8) -> Self {
816 self.w_pct = Some(value);
817 self
818 }
819
820 pub const fn h_pct(mut self, value: u8) -> Self {
822 self.h_pct = Some(value);
823 self
824 }
825}
826
827#[derive(Debug, Clone, Copy, Default)]
828#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
829pub struct WidgetColors {
830 pub fg: Option<Color>,
832 pub bg: Option<Color>,
834 pub border: Option<Color>,
836 pub accent: Option<Color>,
838}
839
840impl WidgetColors {
841 pub const fn new() -> Self {
843 Self {
844 fg: None,
845 bg: None,
846 border: None,
847 accent: None,
848 }
849 }
850
851 pub const fn fg(mut self, color: Color) -> Self {
853 self.fg = Some(color);
854 self
855 }
856
857 pub const fn bg(mut self, color: Color) -> Self {
859 self.bg = Some(color);
860 self
861 }
862
863 pub const fn border(mut self, color: Color) -> Self {
865 self.border = Some(color);
866 self
867 }
868
869 pub const fn accent(mut self, color: Color) -> Self {
871 self.accent = Some(color);
872 self
873 }
874}
875
876#[cfg(test)]
877mod tests {
878 use super::*;
879
880 #[test]
881 fn style_new_is_default() {
882 let style = Style::new();
883 assert_eq!(style.fg, None);
884 assert_eq!(style.bg, None);
885 assert_eq!(style.modifiers, Modifiers::NONE);
886 assert_eq!(style, Style::default());
887 }
888
889 #[test]
890 fn style_bold_and_fg_set_expected_fields() {
891 let style = Style::new().bold().fg(Color::Red);
892 assert_eq!(style.fg, Some(Color::Red));
893 assert_eq!(style.bg, None);
894 assert!(style.modifiers.contains(Modifiers::BOLD));
895 }
896
897 #[test]
898 fn style_multiple_modifiers_accumulate() {
899 let style = Style::new().italic().underline().dim();
900 assert!(style.modifiers.contains(Modifiers::ITALIC));
901 assert!(style.modifiers.contains(Modifiers::UNDERLINE));
902 assert!(style.modifiers.contains(Modifiers::DIM));
903 }
904
905 #[test]
906 fn style_repeated_fg_overrides_previous_color() {
907 let style = Style::new().fg(Color::Blue).fg(Color::Green);
908 assert_eq!(style.fg, Some(Color::Green));
909 }
910
911 #[test]
912 fn style_repeated_bg_overrides_previous_color() {
913 let style = Style::new().bg(Color::Blue).bg(Color::Green);
914 assert_eq!(style.bg, Some(Color::Green));
915 }
916
917 #[test]
918 fn style_override_preserves_existing_modifiers() {
919 let style = Style::new().bold().fg(Color::Red).fg(Color::Yellow);
920 assert_eq!(style.fg, Some(Color::Yellow));
921 assert!(style.modifiers.contains(Modifiers::BOLD));
922 }
923
924 #[test]
925 fn padding_all_sets_all_sides() {
926 let p = Padding::all(3);
927 assert_eq!(p.top, 3);
928 assert_eq!(p.right, 3);
929 assert_eq!(p.bottom, 3);
930 assert_eq!(p.left, 3);
931 }
932
933 #[test]
934 fn padding_xy_sets_axis_values() {
935 let p = Padding::xy(4, 2);
936 assert_eq!(p.top, 2);
937 assert_eq!(p.bottom, 2);
938 assert_eq!(p.left, 4);
939 assert_eq!(p.right, 4);
940 }
941
942 #[test]
943 fn padding_new_and_totals_are_correct() {
944 let p = Padding::new(1, 2, 3, 4);
945 assert_eq!(p.top, 1);
946 assert_eq!(p.right, 2);
947 assert_eq!(p.bottom, 3);
948 assert_eq!(p.left, 4);
949 assert_eq!(p.horizontal(), 6);
950 assert_eq!(p.vertical(), 4);
951 }
952
953 #[test]
954 fn margin_all_and_xy_are_correct() {
955 let all = Margin::all(5);
956 assert_eq!(all, Margin::new(5, 5, 5, 5));
957
958 let xy = Margin::xy(7, 1);
959 assert_eq!(xy.top, 1);
960 assert_eq!(xy.bottom, 1);
961 assert_eq!(xy.left, 7);
962 assert_eq!(xy.right, 7);
963 }
964
965 #[test]
966 fn margin_new_and_totals_are_correct() {
967 let m = Margin::new(2, 4, 6, 8);
968 assert_eq!(m.horizontal(), 12);
969 assert_eq!(m.vertical(), 8);
970 }
971
972 #[test]
973 fn constraints_min_max_builder_sets_values() {
974 let c = Constraints::default()
975 .min_w(10)
976 .max_w(40)
977 .min_h(5)
978 .max_h(20);
979 assert_eq!(c.min_width, Some(10));
980 assert_eq!(c.max_width, Some(40));
981 assert_eq!(c.min_height, Some(5));
982 assert_eq!(c.max_height, Some(20));
983 }
984
985 #[test]
986 fn constraints_percentage_builder_sets_values() {
987 let c = Constraints::default().w_pct(50).h_pct(80);
988 assert_eq!(c.width_pct, Some(50));
989 assert_eq!(c.height_pct, Some(80));
990 }
991
992 #[test]
993 fn border_sides_all_has_both_axes() {
994 let sides = BorderSides::all();
995 assert!(sides.top && sides.right && sides.bottom && sides.left);
996 assert!(sides.has_horizontal());
997 assert!(sides.has_vertical());
998 }
999
1000 #[test]
1001 fn border_sides_none_has_no_axes() {
1002 let sides = BorderSides::none();
1003 assert!(!sides.top && !sides.right && !sides.bottom && !sides.left);
1004 assert!(!sides.has_horizontal());
1005 assert!(!sides.has_vertical());
1006 }
1007
1008 #[test]
1009 fn border_sides_horizontal_only() {
1010 let sides = BorderSides::horizontal();
1011 assert!(sides.top);
1012 assert!(sides.bottom);
1013 assert!(!sides.left);
1014 assert!(!sides.right);
1015 assert!(sides.has_horizontal());
1016 assert!(!sides.has_vertical());
1017 }
1018
1019 #[test]
1020 fn border_sides_vertical_only() {
1021 let sides = BorderSides::vertical();
1022 assert!(!sides.top);
1023 assert!(!sides.bottom);
1024 assert!(sides.left);
1025 assert!(sides.right);
1026 assert!(!sides.has_horizontal());
1027 assert!(sides.has_vertical());
1028 }
1029
1030 #[test]
1031 fn container_style_new_is_empty() {
1032 let s = ContainerStyle::new();
1033 assert_eq!(s.border, None);
1034 assert_eq!(s.bg, None);
1035 assert_eq!(s.padding, None);
1036 assert_eq!(s.margin, None);
1037 assert_eq!(s.gap, None);
1038 assert_eq!(s.align, None);
1039 assert_eq!(s.justify, None);
1040 }
1041
1042 #[test]
1043 fn container_style_const_construction_and_fields() {
1044 const CARD: ContainerStyle = ContainerStyle::new()
1045 .border(Border::Rounded)
1046 .border_sides(BorderSides::horizontal())
1047 .p(2)
1048 .m(1)
1049 .gap(3)
1050 .align(Align::Center)
1051 .justify(Justify::SpaceBetween)
1052 .w(60)
1053 .h(20);
1054
1055 assert_eq!(CARD.border, Some(Border::Rounded));
1056 assert_eq!(CARD.border_sides, Some(BorderSides::horizontal()));
1057 assert_eq!(CARD.padding, Some(Padding::all(2)));
1058 assert_eq!(CARD.margin, Some(Margin::all(1)));
1059 assert_eq!(CARD.gap, Some(3));
1060 assert_eq!(CARD.align, Some(Align::Center));
1061 assert_eq!(CARD.justify, Some(Justify::SpaceBetween));
1062 assert_eq!(CARD.w, Some(60));
1063 assert_eq!(CARD.h, Some(20));
1064 }
1065
1066 #[test]
1067 fn widget_colors_new_is_empty() {
1068 let colors = WidgetColors::new();
1069 assert_eq!(colors.fg, None);
1070 assert_eq!(colors.bg, None);
1071 assert_eq!(colors.border, None);
1072 assert_eq!(colors.accent, None);
1073
1074 let defaults = WidgetColors::default();
1075 assert_eq!(defaults.fg, None);
1076 assert_eq!(defaults.bg, None);
1077 assert_eq!(defaults.border, None);
1078 assert_eq!(defaults.accent, None);
1079 }
1080
1081 #[test]
1082 fn widget_colors_builder_sets_all_fields() {
1083 let colors = WidgetColors::new()
1084 .fg(Color::White)
1085 .bg(Color::Black)
1086 .border(Color::Cyan)
1087 .accent(Color::Yellow);
1088
1089 assert_eq!(colors.fg, Some(Color::White));
1090 assert_eq!(colors.bg, Some(Color::Black));
1091 assert_eq!(colors.border, Some(Color::Cyan));
1092 assert_eq!(colors.accent, Some(Color::Yellow));
1093 }
1094
1095 #[test]
1096 fn align_default_is_start() {
1097 assert_eq!(Align::default(), Align::Start);
1098 }
1099
1100 #[test]
1101 fn justify_default_is_start() {
1102 assert_eq!(Justify::default(), Justify::Start);
1103 }
1104
1105 #[test]
1106 fn align_and_justify_variants_are_distinct() {
1107 assert_ne!(Align::Start, Align::Center);
1108 assert_ne!(Align::Center, Align::End);
1109
1110 assert_ne!(Justify::Start, Justify::Center);
1111 assert_ne!(Justify::Center, Justify::End);
1112 assert_ne!(Justify::SpaceBetween, Justify::SpaceAround);
1113 assert_ne!(Justify::SpaceAround, Justify::SpaceEvenly);
1114 }
1115}