1 | /// Border is a representation of a cells's borders (left, right, top, bottom, and the corners) |
2 | /// |
3 | /// |
4 | /// ```text |
5 | /// top border |
6 | /// | |
7 | /// V |
8 | /// corner top left ------> +_______+ <---- corner top left |
9 | /// | | |
10 | /// left border ----------> | cell | <---- right border |
11 | /// | | |
12 | /// corner bottom right --> +_______+ <---- corner bottom right |
13 | /// ^ |
14 | /// | |
15 | /// bottom border |
16 | /// ``` |
17 | #[derive (Debug, Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] |
18 | pub struct Border<T> { |
19 | /// A character for a top. |
20 | pub top: Option<T>, |
21 | /// A character for a bottom. |
22 | pub bottom: Option<T>, |
23 | /// A character for a left. |
24 | pub left: Option<T>, |
25 | /// A character for a right. |
26 | pub right: Option<T>, |
27 | /// A character for a left top corner. |
28 | pub left_top_corner: Option<T>, |
29 | /// A character for a left bottom corner. |
30 | pub left_bottom_corner: Option<T>, |
31 | /// A character for a right top corner. |
32 | pub right_top_corner: Option<T>, |
33 | /// A character for a right bottom corner. |
34 | pub right_bottom_corner: Option<T>, |
35 | } |
36 | |
37 | impl<T> Border<T> { |
38 | /// This function constructs a cell borders with all sides set. |
39 | #[allow (clippy::too_many_arguments)] |
40 | pub const fn new( |
41 | top: Option<T>, |
42 | bottom: Option<T>, |
43 | left: Option<T>, |
44 | right: Option<T>, |
45 | left_top_corner: Option<T>, |
46 | left_bottom_corner: Option<T>, |
47 | right_top_corner: Option<T>, |
48 | right_bottom_corner: Option<T>, |
49 | ) -> Self { |
50 | Self { |
51 | top, |
52 | bottom, |
53 | left, |
54 | right, |
55 | left_top_corner, |
56 | left_bottom_corner, |
57 | right_top_corner, |
58 | right_bottom_corner, |
59 | } |
60 | } |
61 | |
62 | /// This function constructs a cell borders with all sides set. |
63 | #[allow (clippy::too_many_arguments)] |
64 | pub const fn full( |
65 | top: T, |
66 | bottom: T, |
67 | left: T, |
68 | right: T, |
69 | top_left: T, |
70 | top_right: T, |
71 | bottom_left: T, |
72 | bottom_right: T, |
73 | ) -> Self { |
74 | Self::new( |
75 | Some(top), |
76 | Some(bottom), |
77 | Some(left), |
78 | Some(right), |
79 | Some(top_left), |
80 | Some(bottom_left), |
81 | Some(top_right), |
82 | Some(bottom_right), |
83 | ) |
84 | } |
85 | |
86 | /// This function constructs a cell borders with all sides being empty (set off). |
87 | pub const fn empty() -> Self { |
88 | Self::new(None, None, None, None, None, None, None, None) |
89 | } |
90 | |
91 | /// Checks whether any side is set. |
92 | pub const fn is_empty(&self) -> bool { |
93 | self.top.is_none() |
94 | && self.left_top_corner.is_none() |
95 | && self.right_top_corner.is_none() |
96 | && self.bottom.is_none() |
97 | && self.left_bottom_corner.is_none() |
98 | && self.left_top_corner.is_none() |
99 | && self.left.is_none() |
100 | && self.right.is_none() |
101 | } |
102 | |
103 | /// Verifies whether anything is set on the top. |
104 | pub const fn has_top(&self) -> bool { |
105 | self.top.is_some() || self.left_top_corner.is_some() || self.right_top_corner.is_some() |
106 | } |
107 | |
108 | /// Verifies whether anything is set on the bottom. |
109 | pub const fn has_bottom(&self) -> bool { |
110 | self.bottom.is_some() |
111 | || self.left_bottom_corner.is_some() |
112 | || self.right_bottom_corner.is_some() |
113 | } |
114 | |
115 | /// Verifies whether anything is set on the left. |
116 | pub const fn has_left(&self) -> bool { |
117 | self.left.is_some() || self.left_top_corner.is_some() || self.left_bottom_corner.is_some() |
118 | } |
119 | |
120 | /// Verifies whether anything is set on the right. |
121 | pub const fn has_right(&self) -> bool { |
122 | self.right.is_some() |
123 | || self.right_top_corner.is_some() |
124 | || self.right_bottom_corner.is_some() |
125 | } |
126 | } |
127 | |
128 | impl<T: Copy> Border<T> { |
129 | /// This function constructs a cell borders with all sides's char set to a given character. |
130 | /// |
131 | /// It behaves like [`Border::full`] with the same character set to each side. |
132 | pub fn filled(c: T) -> Self { |
133 | Self::full(top:c, bottom:c, left:c, right:c, top_left:c, top_right:c, bottom_left:c, bottom_right:c) |
134 | } |
135 | } |
136 | |
137 | impl<T: Copy> Border<&T> { |
138 | /// Copies the underlying reference to a new border. |
139 | pub fn copied(&self) -> Border<T> { |
140 | Border { |
141 | top: self.top.copied(), |
142 | bottom: self.bottom.copied(), |
143 | left: self.left.copied(), |
144 | right: self.right.copied(), |
145 | left_bottom_corner: self.left_bottom_corner.copied(), |
146 | left_top_corner: self.left_top_corner.copied(), |
147 | right_bottom_corner: self.right_bottom_corner.copied(), |
148 | right_top_corner: self.right_top_corner.copied(), |
149 | } |
150 | } |
151 | } |
152 | |
153 | impl<T: Clone> Border<&T> { |
154 | /// Copies the underlying reference to a new border. |
155 | pub fn cloned(&self) -> Border<T> { |
156 | Border { |
157 | top: self.top.cloned(), |
158 | bottom: self.bottom.cloned(), |
159 | left: self.left.cloned(), |
160 | right: self.right.cloned(), |
161 | left_bottom_corner: self.left_bottom_corner.cloned(), |
162 | left_top_corner: self.left_top_corner.cloned(), |
163 | right_bottom_corner: self.right_bottom_corner.cloned(), |
164 | right_top_corner: self.right_top_corner.cloned(), |
165 | } |
166 | } |
167 | } |
168 | |
169 | impl<T> Border<T> { |
170 | /// Convert all values on the border into another ones. |
171 | pub fn convert<B>(self) -> Border<B> |
172 | where |
173 | B: From<T>, |
174 | { |
175 | macro_rules! conv_opt { |
176 | ($opt:expr) => { |
177 | match $opt { |
178 | Some(opt) => Some(B::from(opt)), |
179 | None => None, |
180 | } |
181 | }; |
182 | } |
183 | |
184 | Border { |
185 | top: conv_opt!(self.top), |
186 | bottom: conv_opt!(self.bottom), |
187 | left: conv_opt!(self.left), |
188 | right: conv_opt!(self.right), |
189 | left_bottom_corner: conv_opt!(self.left_bottom_corner), |
190 | left_top_corner: conv_opt!(self.left_top_corner), |
191 | right_bottom_corner: conv_opt!(self.right_bottom_corner), |
192 | right_top_corner: conv_opt!(self.right_top_corner), |
193 | } |
194 | } |
195 | } |
196 | |