1use core::marker::PhantomData;
2
3use crate::{
4 grid::config::Border as GridBorder,
5 settings::{style::On, style::Style},
6};
7
8#[cfg(feature = "std")]
9use crate::{
10 grid::config::{ColoredConfig, Entity},
11 grid::records::{ExactRecords, Records},
12 settings::CellOption,
13};
14
15/// Border represents a border of a Cell.
16///
17/// ```text
18/// top border
19/// |
20/// V
21/// corner top left ------> +_______+ <---- corner top left
22/// | |
23/// left border ----------> | cell | <---- right border
24/// | |
25/// corner bottom right --> +_______+ <---- corner bottom right
26/// ^
27/// |
28/// bottom border
29/// ```
30///
31/// ```rust,no_run
32/// # use tabled::{Table, settings::{style::{Style, Border}, object::Rows}};
33/// # let data: Vec<&'static str> = Vec::new();
34/// let table = Table::new(&data)
35/// .with(Style::ascii())
36/// .modify(Rows::single(0), Border::new().set_top('x'));
37/// ```
38#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
39pub struct Border<T, B, L, R> {
40 inner: GridBorder<char>,
41 _top: PhantomData<T>,
42 _bottom: PhantomData<B>,
43 _left: PhantomData<L>,
44 _right: PhantomData<R>,
45}
46
47impl<T, B, L, R> Border<T, B, L, R> {
48 pub(crate) const fn from_border(inner: GridBorder<char>) -> Border<T, B, L, R> {
49 Border {
50 inner,
51 _top: PhantomData,
52 _bottom: PhantomData,
53 _left: PhantomData,
54 _right: PhantomData,
55 }
56 }
57}
58
59impl Border<(), (), (), ()> {
60 /// Creates an empty border.
61 pub const fn new() -> Self {
62 Self::from_border(inner:GridBorder::empty())
63 }
64}
65
66impl Border<On, On, On, On> {
67 /// This function constructs a cell borders with all sides set.
68 #[allow(clippy::too_many_arguments)]
69 pub const fn full(
70 top: char,
71 bottom: char,
72 left: char,
73 right: char,
74 top_left: char,
75 top_right: char,
76 bottom_left: char,
77 bottom_right: char,
78 ) -> Self {
79 Border::from_border(GridBorder::full(
80 top,
81 bottom,
82 left,
83 right,
84 top_left,
85 top_right,
86 bottom_left,
87 bottom_right,
88 ))
89 }
90
91 /// This function constructs a cell borders with all sides's char set to a given character.
92 /// It behaves like [`Border::full`] with the same character set to each side.
93 pub const fn filled(c: char) -> Self {
94 Self::full(c, c, c, c, c, c, c, c)
95 }
96
97 /// Using this function you deconstruct the existing borders.
98 pub const fn empty() -> EmptyBorder {
99 EmptyBorder
100 }
101}
102
103impl<T, B, L, R> Border<T, B, L, R> {
104 /// Fetches outer border from a style.
105 pub const fn inherit<H, V, const HSIZE: usize, const VSIZE: usize>(
106 style: Style<T, B, L, R, H, V, HSIZE, VSIZE>,
107 ) -> Self {
108 let borders: Borders = style.get_borders();
109 let line: Border = GridBorder::new(
110 borders.top,
111 borders.bottom,
112 borders.left,
113 borders.right,
114 left_top_corner:borders.top_left,
115 left_bottom_corner:borders.bottom_left,
116 right_top_corner:borders.top_right,
117 right_bottom_corner:borders.bottom_right,
118 );
119
120 Self::from_border(inner:line)
121 }
122}
123
124impl<T, B, L, R> Border<T, B, L, R> {
125 /// Set a top border character.
126 pub const fn set_top(mut self, c: char) -> Border<On, B, L, R> {
127 self.inner.top = Some(c);
128 Border::from_border(self.inner)
129 }
130
131 /// Set a bottom border character.
132 pub const fn set_bottom(mut self, c: char) -> Border<T, On, L, R> {
133 self.inner.bottom = Some(c);
134 Border::from_border(self.inner)
135 }
136
137 /// Set a left border character.
138 pub const fn set_left(mut self, c: char) -> Border<T, B, On, R> {
139 self.inner.left = Some(c);
140 Border::from_border(self.inner)
141 }
142
143 /// Set a right border character.
144 pub const fn set_right(mut self, c: char) -> Border<T, B, L, On> {
145 self.inner.right = Some(c);
146 Border::from_border(self.inner)
147 }
148
149 /// Converts a border into a general data structure.
150 pub const fn into_inner(self) -> GridBorder<char> {
151 self.inner
152 }
153}
154
155impl<T, B, L> Border<T, B, L, On> {
156 /// Get a right character.
157 pub const fn get_right(&self) -> char {
158 get_char(self.inner.right)
159 }
160}
161
162impl<T, B, R> Border<T, B, On, R> {
163 /// Get a left character.
164 pub const fn get_left(&self) -> char {
165 get_char(self.inner.left)
166 }
167}
168
169impl<B, L, R> Border<On, B, L, R> {
170 /// Get a top character.
171 pub const fn get_top(&self) -> char {
172 get_char(self.inner.top)
173 }
174}
175
176impl<T, L, R> Border<T, On, L, R> {
177 /// Get a bottom character.
178 pub const fn get_bottom(&self) -> char {
179 get_char(self.inner.bottom)
180 }
181}
182
183impl<B, R> Border<On, B, On, R> {
184 /// Set a top left intersection character.
185 pub const fn set_corner_top_left(mut self, c: char) -> Self {
186 self.inner.left_top_corner = Some(c);
187 self
188 }
189
190 /// Get a top left intersection character.
191 pub const fn get_corner_top_left(&self) -> char {
192 get_char(self.inner.left_top_corner)
193 }
194}
195
196impl<B, L> Border<On, B, L, On> {
197 /// Set a top right intersection character.
198 pub const fn set_corner_top_right(mut self, c: char) -> Self {
199 self.inner.right_top_corner = Some(c);
200 self
201 }
202
203 /// Get a top right intersection character.
204 pub const fn get_corner_top_right(&self) -> char {
205 get_char(self.inner.right_top_corner)
206 }
207}
208
209impl<T, R> Border<T, On, On, R> {
210 /// Set a bottom left intersection character.
211 pub const fn set_corner_bottom_left(mut self, c: char) -> Self {
212 self.inner.left_bottom_corner = Some(c);
213 self
214 }
215
216 /// Get a bottom left intersection character.
217 pub const fn get_corner_bottom_left(&self) -> char {
218 get_char(self.inner.left_bottom_corner)
219 }
220}
221
222impl<T, L> Border<T, On, L, On> {
223 /// Set a bottom right intersection character.
224 pub const fn set_corner_bottom_right(mut self, c: char) -> Self {
225 self.inner.right_bottom_corner = Some(c);
226 self
227 }
228
229 /// Get a bottom left intersection character.
230 pub const fn get_corner_bottom_right(&self) -> char {
231 get_char(self.inner.right_bottom_corner)
232 }
233}
234
235impl<T, B, L, R> From<Border<T, B, L, R>> for GridBorder<char> {
236 fn from(value: Border<T, B, L, R>) -> Self {
237 value.inner
238 }
239}
240
241#[cfg(feature = "std")]
242
243impl<T, B, L, R, Data> CellOption<Data, ColoredConfig> for Border<T, B, L, R>
244where
245 Data: Records + ExactRecords,
246{
247 fn change(self, records: &mut Data, cfg: &mut ColoredConfig, entity: Entity) {
248 CellOption::change(self.inner, records, cfg, entity)
249 }
250}
251
252#[cfg(feature = "std")]
253impl<R> CellOption<R, ColoredConfig> for GridBorder<char>
254where
255 R: Records + ExactRecords,
256{
257 fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
258 let shape: (usize, usize) = (records.count_rows(), records.count_columns());
259
260 for pos: (usize, usize) in entity.iter(count_rows:shape.0, count_cols:shape.1) {
261 cfg.set_border(pos, self);
262 }
263 }
264}
265
266#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
267pub struct EmptyBorder;
268
269#[cfg(feature = "std")]
270impl<R> CellOption<R, ColoredConfig> for EmptyBorder
271where
272 R: Records + ExactRecords,
273{
274 fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
275 let shape: (usize, usize) = (records.count_rows(), records.count_columns());
276
277 for pos: (usize, usize) in entity.iter(count_rows:shape.0, count_cols:shape.1) {
278 cfg.remove_border(pos, shape);
279 }
280 }
281}
282
283const fn get_char(c: Option<char>) -> char {
284 match c {
285 Some(c: char) => c,
286 None => unreachable!(),
287 }
288}
289