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