1mod color;
7mod theme;
8pub use color::{Color, ColorDepth};
9pub use theme::{Theme, ThemeBuilder};
10
11#[non_exhaustive]
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub enum Breakpoint {
18 Xs,
20 Sm,
22 Md,
24 Lg,
26 Xl,
28}
29
30#[non_exhaustive]
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub enum Border {
38 Single,
40 Double,
42 Rounded,
44 Thick,
46 Dashed,
48 DashedThick,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub struct BorderChars {
58 pub tl: char,
60 pub tr: char,
62 pub bl: char,
64 pub br: char,
66 pub h: char,
68 pub v: char,
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75pub struct BorderSides {
76 pub top: bool,
78 pub right: bool,
80 pub bottom: bool,
82 pub left: bool,
84}
85
86impl BorderSides {
87 pub const fn all() -> Self {
89 Self {
90 top: true,
91 right: true,
92 bottom: true,
93 left: true,
94 }
95 }
96
97 pub const fn none() -> Self {
99 Self {
100 top: false,
101 right: false,
102 bottom: false,
103 left: false,
104 }
105 }
106
107 pub const fn horizontal() -> Self {
109 Self {
110 top: true,
111 right: false,
112 bottom: true,
113 left: false,
114 }
115 }
116
117 pub const fn vertical() -> Self {
119 Self {
120 top: false,
121 right: true,
122 bottom: false,
123 left: true,
124 }
125 }
126
127 pub fn has_horizontal(&self) -> bool {
129 self.top || self.bottom
130 }
131
132 pub fn has_vertical(&self) -> bool {
134 self.left || self.right
135 }
136}
137
138impl Default for BorderSides {
139 fn default() -> Self {
140 Self::all()
141 }
142}
143
144impl Border {
145 pub const fn chars(self) -> BorderChars {
147 match self {
148 Self::Single => BorderChars {
149 tl: '┌',
150 tr: '┐',
151 bl: '└',
152 br: '┘',
153 h: '─',
154 v: '│',
155 },
156 Self::Double => BorderChars {
157 tl: '╔',
158 tr: '╗',
159 bl: '╚',
160 br: '╝',
161 h: '═',
162 v: '║',
163 },
164 Self::Rounded => BorderChars {
165 tl: '╭',
166 tr: '╮',
167 bl: '╰',
168 br: '╯',
169 h: '─',
170 v: '│',
171 },
172 Self::Thick => BorderChars {
173 tl: '┏',
174 tr: '┓',
175 bl: '┗',
176 br: '┛',
177 h: '━',
178 v: '┃',
179 },
180 Self::Dashed => BorderChars {
181 tl: '┌',
182 tr: '┐',
183 bl: '└',
184 br: '┘',
185 h: '┄',
186 v: '┆',
187 },
188 Self::DashedThick => BorderChars {
189 tl: '┏',
190 tr: '┓',
191 bl: '┗',
192 br: '┛',
193 h: '┅',
194 v: '┇',
195 },
196 }
197 }
198}
199
200#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
205#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
206pub struct Padding {
207 pub top: u32,
209 pub right: u32,
211 pub bottom: u32,
213 pub left: u32,
215}
216
217impl Padding {
218 pub const fn all(v: u32) -> Self {
220 Self::new(v, v, v, v)
221 }
222
223 pub const fn xy(x: u32, y: u32) -> Self {
225 Self::new(y, x, y, x)
226 }
227
228 pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
230 Self {
231 top,
232 right,
233 bottom,
234 left,
235 }
236 }
237
238 pub const fn horizontal(self) -> u32 {
240 self.left + self.right
241 }
242
243 pub const fn vertical(self) -> u32 {
245 self.top + self.bottom
246 }
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
254#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
255pub struct Margin {
256 pub top: u32,
258 pub right: u32,
260 pub bottom: u32,
262 pub left: u32,
264}
265
266impl Margin {
267 pub const fn all(v: u32) -> Self {
269 Self::new(v, v, v, v)
270 }
271
272 pub const fn xy(x: u32, y: u32) -> Self {
274 Self::new(y, x, y, x)
275 }
276
277 pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
279 Self {
280 top,
281 right,
282 bottom,
283 left,
284 }
285 }
286
287 pub const fn horizontal(self) -> u32 {
289 self.left + self.right
290 }
291
292 pub const fn vertical(self) -> u32 {
294 self.top + self.bottom
295 }
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
311#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
312#[must_use = "configure constraints using the returned value"]
313pub struct Constraints {
314 pub min_width: Option<u32>,
316 pub max_width: Option<u32>,
318 pub min_height: Option<u32>,
320 pub max_height: Option<u32>,
322 pub width_pct: Option<u8>,
324 pub height_pct: Option<u8>,
326}
327
328impl Constraints {
329 pub const fn min_w(mut self, min_width: u32) -> Self {
331 self.min_width = Some(min_width);
332 self
333 }
334
335 pub const fn max_w(mut self, max_width: u32) -> Self {
337 self.max_width = Some(max_width);
338 self
339 }
340
341 pub const fn min_h(mut self, min_height: u32) -> Self {
343 self.min_height = Some(min_height);
344 self
345 }
346
347 pub const fn max_h(mut self, max_height: u32) -> Self {
349 self.max_height = Some(max_height);
350 self
351 }
352
353 pub const fn w_pct(mut self, pct: u8) -> Self {
355 self.width_pct = Some(pct);
356 self
357 }
358
359 pub const fn h_pct(mut self, pct: u8) -> Self {
361 self.height_pct = Some(pct);
362 self
363 }
364}
365
366#[non_exhaustive]
372#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
373#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
374pub enum Align {
375 #[default]
377 Start,
378 Center,
380 End,
382}
383
384#[non_exhaustive]
393#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
394#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
395pub enum Justify {
396 #[default]
398 Start,
399 Center,
401 End,
403 SpaceBetween,
405 SpaceAround,
407 SpaceEvenly,
409}
410
411#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
416#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
417#[cfg_attr(feature = "serde", serde(transparent))]
418pub struct Modifiers(pub u8);
419
420impl Modifiers {
421 pub const NONE: Self = Self(0);
423 pub const BOLD: Self = Self(1 << 0);
425 pub const DIM: Self = Self(1 << 1);
427 pub const ITALIC: Self = Self(1 << 2);
429 pub const UNDERLINE: Self = Self(1 << 3);
431 pub const REVERSED: Self = Self(1 << 4);
433 pub const STRIKETHROUGH: Self = Self(1 << 5);
435
436 #[inline]
438 pub fn contains(self, other: Self) -> bool {
439 (self.0 & other.0) == other.0
440 }
441
442 #[inline]
444 pub fn insert(&mut self, other: Self) {
445 self.0 |= other.0;
446 }
447
448 #[inline]
450 pub fn is_empty(self) -> bool {
451 self.0 == 0
452 }
453}
454
455impl std::ops::BitOr for Modifiers {
456 type Output = Self;
457 #[inline]
458 fn bitor(self, rhs: Self) -> Self {
459 Self(self.0 | rhs.0)
460 }
461}
462
463impl std::ops::BitOrAssign for Modifiers {
464 #[inline]
465 fn bitor_assign(&mut self, rhs: Self) {
466 self.0 |= rhs.0;
467 }
468}
469
470#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
484#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
485#[must_use = "build and pass the returned Style value"]
486pub struct Style {
487 pub fg: Option<Color>,
489 pub bg: Option<Color>,
491 pub modifiers: Modifiers,
493}
494
495impl Style {
496 pub const fn new() -> Self {
498 Self {
499 fg: None,
500 bg: None,
501 modifiers: Modifiers::NONE,
502 }
503 }
504
505 pub const fn fg(mut self, color: Color) -> Self {
507 self.fg = Some(color);
508 self
509 }
510
511 pub const fn bg(mut self, color: Color) -> Self {
513 self.bg = Some(color);
514 self
515 }
516
517 pub fn bold(mut self) -> Self {
519 self.modifiers |= Modifiers::BOLD;
520 self
521 }
522
523 pub fn dim(mut self) -> Self {
525 self.modifiers |= Modifiers::DIM;
526 self
527 }
528
529 pub fn italic(mut self) -> Self {
531 self.modifiers |= Modifiers::ITALIC;
532 self
533 }
534
535 pub fn underline(mut self) -> Self {
537 self.modifiers |= Modifiers::UNDERLINE;
538 self
539 }
540
541 pub fn reversed(mut self) -> Self {
543 self.modifiers |= Modifiers::REVERSED;
544 self
545 }
546
547 pub fn strikethrough(mut self) -> Self {
549 self.modifiers |= Modifiers::STRIKETHROUGH;
550 self
551 }
552}
553
554#[derive(Debug, Clone, Copy, Default)]
578pub struct ContainerStyle {
579 pub border: Option<Border>,
581 pub border_sides: Option<BorderSides>,
583 pub border_style: Option<Style>,
585 pub bg: Option<Color>,
587 pub text_color: Option<Color>,
589 pub dark_bg: Option<Color>,
591 pub dark_border_style: Option<Style>,
593 pub padding: Option<Padding>,
595 pub margin: Option<Margin>,
597 pub gap: Option<u32>,
599 pub row_gap: Option<u32>,
601 pub col_gap: Option<u32>,
603 pub grow: Option<u16>,
605 pub align: Option<Align>,
607 pub align_self: Option<Align>,
609 pub justify: Option<Justify>,
611 pub w: Option<u32>,
613 pub h: Option<u32>,
615 pub min_w: Option<u32>,
617 pub max_w: Option<u32>,
619 pub min_h: Option<u32>,
621 pub max_h: Option<u32>,
623 pub w_pct: Option<u8>,
625 pub h_pct: Option<u8>,
627}
628
629impl ContainerStyle {
630 pub const fn new() -> Self {
632 Self {
633 border: None,
634 border_sides: None,
635 border_style: None,
636 bg: None,
637 text_color: None,
638 dark_bg: None,
639 dark_border_style: None,
640 padding: None,
641 margin: None,
642 gap: None,
643 row_gap: None,
644 col_gap: None,
645 grow: None,
646 align: None,
647 align_self: None,
648 justify: None,
649 w: None,
650 h: None,
651 min_w: None,
652 max_w: None,
653 min_h: None,
654 max_h: None,
655 w_pct: None,
656 h_pct: None,
657 }
658 }
659
660 pub const fn border(mut self, border: Border) -> Self {
662 self.border = Some(border);
663 self
664 }
665
666 pub const fn border_sides(mut self, sides: BorderSides) -> Self {
668 self.border_sides = Some(sides);
669 self
670 }
671
672 pub const fn bg(mut self, color: Color) -> Self {
674 self.bg = Some(color);
675 self
676 }
677
678 pub const fn text_color(mut self, color: Color) -> Self {
680 self.text_color = Some(color);
681 self
682 }
683
684 pub const fn dark_bg(mut self, color: Color) -> Self {
686 self.dark_bg = Some(color);
687 self
688 }
689
690 pub const fn p(mut self, value: u32) -> Self {
692 self.padding = Some(Padding {
693 top: value,
694 bottom: value,
695 left: value,
696 right: value,
697 });
698 self
699 }
700
701 pub const fn px(mut self, value: u32) -> Self {
703 let p = match self.padding {
704 Some(p) => Padding {
705 left: value,
706 right: value,
707 ..p
708 },
709 None => Padding {
710 top: 0,
711 bottom: 0,
712 left: value,
713 right: value,
714 },
715 };
716 self.padding = Some(p);
717 self
718 }
719
720 pub const fn py(mut self, value: u32) -> Self {
722 let p = match self.padding {
723 Some(p) => Padding {
724 top: value,
725 bottom: value,
726 ..p
727 },
728 None => Padding {
729 top: value,
730 bottom: value,
731 left: 0,
732 right: 0,
733 },
734 };
735 self.padding = Some(p);
736 self
737 }
738
739 pub const fn m(mut self, value: u32) -> Self {
741 self.margin = Some(Margin {
742 top: value,
743 bottom: value,
744 left: value,
745 right: value,
746 });
747 self
748 }
749
750 pub const fn gap(mut self, value: u32) -> Self {
752 self.gap = Some(value);
753 self
754 }
755
756 pub const fn row_gap(mut self, value: u32) -> Self {
758 self.row_gap = Some(value);
759 self
760 }
761
762 pub const fn col_gap(mut self, value: u32) -> Self {
764 self.col_gap = Some(value);
765 self
766 }
767
768 pub const fn grow(mut self, value: u16) -> Self {
770 self.grow = Some(value);
771 self
772 }
773
774 pub const fn w(mut self, value: u32) -> Self {
776 self.w = Some(value);
777 self
778 }
779
780 pub const fn h(mut self, value: u32) -> Self {
782 self.h = Some(value);
783 self
784 }
785
786 pub const fn min_w(mut self, value: u32) -> Self {
788 self.min_w = Some(value);
789 self
790 }
791
792 pub const fn max_w(mut self, value: u32) -> Self {
794 self.max_w = Some(value);
795 self
796 }
797
798 pub const fn align(mut self, value: Align) -> Self {
800 self.align = Some(value);
801 self
802 }
803
804 pub const fn align_self(mut self, value: Align) -> Self {
806 self.align_self = Some(value);
807 self
808 }
809
810 pub const fn justify(mut self, value: Justify) -> Self {
812 self.justify = Some(value);
813 self
814 }
815
816 pub const fn min_h(mut self, value: u32) -> Self {
818 self.min_h = Some(value);
819 self
820 }
821
822 pub const fn max_h(mut self, value: u32) -> Self {
824 self.max_h = Some(value);
825 self
826 }
827
828 pub const fn w_pct(mut self, value: u8) -> Self {
830 self.w_pct = Some(value);
831 self
832 }
833
834 pub const fn h_pct(mut self, value: u8) -> Self {
836 self.h_pct = Some(value);
837 self
838 }
839}
840
841#[derive(Debug, Clone, Copy, Default)]
842#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
843pub struct WidgetColors {
845 pub fg: Option<Color>,
847 pub bg: Option<Color>,
849 pub border: Option<Color>,
851 pub accent: Option<Color>,
853}
854
855impl WidgetColors {
856 pub const fn new() -> Self {
858 Self {
859 fg: None,
860 bg: None,
861 border: None,
862 accent: None,
863 }
864 }
865
866 pub const fn fg(mut self, color: Color) -> Self {
868 self.fg = Some(color);
869 self
870 }
871
872 pub const fn bg(mut self, color: Color) -> Self {
874 self.bg = Some(color);
875 self
876 }
877
878 pub const fn border(mut self, color: Color) -> Self {
880 self.border = Some(color);
881 self
882 }
883
884 pub const fn accent(mut self, color: Color) -> Self {
886 self.accent = Some(color);
887 self
888 }
889}
890
891#[cfg(test)]
892mod tests {
893 use super::*;
894
895 #[test]
896 fn style_new_is_default() {
897 let style = Style::new();
898 assert_eq!(style.fg, None);
899 assert_eq!(style.bg, None);
900 assert_eq!(style.modifiers, Modifiers::NONE);
901 assert_eq!(style, Style::default());
902 }
903
904 #[test]
905 fn style_bold_and_fg_set_expected_fields() {
906 let style = Style::new().bold().fg(Color::Red);
907 assert_eq!(style.fg, Some(Color::Red));
908 assert_eq!(style.bg, None);
909 assert!(style.modifiers.contains(Modifiers::BOLD));
910 }
911
912 #[test]
913 fn style_multiple_modifiers_accumulate() {
914 let style = Style::new().italic().underline().dim();
915 assert!(style.modifiers.contains(Modifiers::ITALIC));
916 assert!(style.modifiers.contains(Modifiers::UNDERLINE));
917 assert!(style.modifiers.contains(Modifiers::DIM));
918 }
919
920 #[test]
921 fn style_repeated_fg_overrides_previous_color() {
922 let style = Style::new().fg(Color::Blue).fg(Color::Green);
923 assert_eq!(style.fg, Some(Color::Green));
924 }
925
926 #[test]
927 fn style_repeated_bg_overrides_previous_color() {
928 let style = Style::new().bg(Color::Blue).bg(Color::Green);
929 assert_eq!(style.bg, Some(Color::Green));
930 }
931
932 #[test]
933 fn style_override_preserves_existing_modifiers() {
934 let style = Style::new().bold().fg(Color::Red).fg(Color::Yellow);
935 assert_eq!(style.fg, Some(Color::Yellow));
936 assert!(style.modifiers.contains(Modifiers::BOLD));
937 }
938
939 #[test]
940 fn padding_all_sets_all_sides() {
941 let p = Padding::all(3);
942 assert_eq!(p.top, 3);
943 assert_eq!(p.right, 3);
944 assert_eq!(p.bottom, 3);
945 assert_eq!(p.left, 3);
946 }
947
948 #[test]
949 fn padding_xy_sets_axis_values() {
950 let p = Padding::xy(4, 2);
951 assert_eq!(p.top, 2);
952 assert_eq!(p.bottom, 2);
953 assert_eq!(p.left, 4);
954 assert_eq!(p.right, 4);
955 }
956
957 #[test]
958 fn padding_new_and_totals_are_correct() {
959 let p = Padding::new(1, 2, 3, 4);
960 assert_eq!(p.top, 1);
961 assert_eq!(p.right, 2);
962 assert_eq!(p.bottom, 3);
963 assert_eq!(p.left, 4);
964 assert_eq!(p.horizontal(), 6);
965 assert_eq!(p.vertical(), 4);
966 }
967
968 #[test]
969 fn margin_all_and_xy_are_correct() {
970 let all = Margin::all(5);
971 assert_eq!(all, Margin::new(5, 5, 5, 5));
972
973 let xy = Margin::xy(7, 1);
974 assert_eq!(xy.top, 1);
975 assert_eq!(xy.bottom, 1);
976 assert_eq!(xy.left, 7);
977 assert_eq!(xy.right, 7);
978 }
979
980 #[test]
981 fn margin_new_and_totals_are_correct() {
982 let m = Margin::new(2, 4, 6, 8);
983 assert_eq!(m.horizontal(), 12);
984 assert_eq!(m.vertical(), 8);
985 }
986
987 #[test]
988 fn constraints_min_max_builder_sets_values() {
989 let c = Constraints::default()
990 .min_w(10)
991 .max_w(40)
992 .min_h(5)
993 .max_h(20);
994 assert_eq!(c.min_width, Some(10));
995 assert_eq!(c.max_width, Some(40));
996 assert_eq!(c.min_height, Some(5));
997 assert_eq!(c.max_height, Some(20));
998 }
999
1000 #[test]
1001 fn constraints_percentage_builder_sets_values() {
1002 let c = Constraints::default().w_pct(50).h_pct(80);
1003 assert_eq!(c.width_pct, Some(50));
1004 assert_eq!(c.height_pct, Some(80));
1005 }
1006
1007 #[test]
1008 fn border_sides_all_has_both_axes() {
1009 let sides = BorderSides::all();
1010 assert!(sides.top && sides.right && sides.bottom && sides.left);
1011 assert!(sides.has_horizontal());
1012 assert!(sides.has_vertical());
1013 }
1014
1015 #[test]
1016 fn border_sides_none_has_no_axes() {
1017 let sides = BorderSides::none();
1018 assert!(!sides.top && !sides.right && !sides.bottom && !sides.left);
1019 assert!(!sides.has_horizontal());
1020 assert!(!sides.has_vertical());
1021 }
1022
1023 #[test]
1024 fn border_sides_horizontal_only() {
1025 let sides = BorderSides::horizontal();
1026 assert!(sides.top);
1027 assert!(sides.bottom);
1028 assert!(!sides.left);
1029 assert!(!sides.right);
1030 assert!(sides.has_horizontal());
1031 assert!(!sides.has_vertical());
1032 }
1033
1034 #[test]
1035 fn border_sides_vertical_only() {
1036 let sides = BorderSides::vertical();
1037 assert!(!sides.top);
1038 assert!(!sides.bottom);
1039 assert!(sides.left);
1040 assert!(sides.right);
1041 assert!(!sides.has_horizontal());
1042 assert!(sides.has_vertical());
1043 }
1044
1045 #[test]
1046 fn container_style_new_is_empty() {
1047 let s = ContainerStyle::new();
1048 assert_eq!(s.border, None);
1049 assert_eq!(s.bg, None);
1050 assert_eq!(s.padding, None);
1051 assert_eq!(s.margin, None);
1052 assert_eq!(s.gap, None);
1053 assert_eq!(s.align, None);
1054 assert_eq!(s.justify, None);
1055 }
1056
1057 #[test]
1058 fn container_style_const_construction_and_fields() {
1059 const CARD: ContainerStyle = ContainerStyle::new()
1060 .border(Border::Rounded)
1061 .border_sides(BorderSides::horizontal())
1062 .p(2)
1063 .m(1)
1064 .gap(3)
1065 .align(Align::Center)
1066 .justify(Justify::SpaceBetween)
1067 .w(60)
1068 .h(20);
1069
1070 assert_eq!(CARD.border, Some(Border::Rounded));
1071 assert_eq!(CARD.border_sides, Some(BorderSides::horizontal()));
1072 assert_eq!(CARD.padding, Some(Padding::all(2)));
1073 assert_eq!(CARD.margin, Some(Margin::all(1)));
1074 assert_eq!(CARD.gap, Some(3));
1075 assert_eq!(CARD.align, Some(Align::Center));
1076 assert_eq!(CARD.justify, Some(Justify::SpaceBetween));
1077 assert_eq!(CARD.w, Some(60));
1078 assert_eq!(CARD.h, Some(20));
1079 }
1080
1081 #[test]
1082 fn widget_colors_new_is_empty() {
1083 let colors = WidgetColors::new();
1084 assert_eq!(colors.fg, None);
1085 assert_eq!(colors.bg, None);
1086 assert_eq!(colors.border, None);
1087 assert_eq!(colors.accent, None);
1088
1089 let defaults = WidgetColors::default();
1090 assert_eq!(defaults.fg, None);
1091 assert_eq!(defaults.bg, None);
1092 assert_eq!(defaults.border, None);
1093 assert_eq!(defaults.accent, None);
1094 }
1095
1096 #[test]
1097 fn widget_colors_builder_sets_all_fields() {
1098 let colors = WidgetColors::new()
1099 .fg(Color::White)
1100 .bg(Color::Black)
1101 .border(Color::Cyan)
1102 .accent(Color::Yellow);
1103
1104 assert_eq!(colors.fg, Some(Color::White));
1105 assert_eq!(colors.bg, Some(Color::Black));
1106 assert_eq!(colors.border, Some(Color::Cyan));
1107 assert_eq!(colors.accent, Some(Color::Yellow));
1108 }
1109
1110 #[test]
1111 fn align_default_is_start() {
1112 assert_eq!(Align::default(), Align::Start);
1113 }
1114
1115 #[test]
1116 fn justify_default_is_start() {
1117 assert_eq!(Justify::default(), Justify::Start);
1118 }
1119
1120 #[test]
1121 fn align_and_justify_variants_are_distinct() {
1122 assert_ne!(Align::Start, Align::Center);
1123 assert_ne!(Align::Center, Align::End);
1124
1125 assert_ne!(Justify::Start, Justify::Center);
1126 assert_ne!(Justify::Center, Justify::End);
1127 assert_ne!(Justify::SpaceBetween, Justify::SpaceAround);
1128 assert_ne!(Justify::SpaceAround, Justify::SpaceEvenly);
1129 }
1130}