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)]
18pub 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
37impl<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
128impl<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
137impl<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
153impl<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
169impl<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