tabled/settings/style/
builder.rs

1//! This module contains a compile time style builder [`Style`].
2
3use core::marker::PhantomData;
4
5use crate::{
6    grid::config::{Border as GridBorder, Borders, CompactConfig, CompactMultilineConfig},
7    settings::{
8        style::{HorizontalLine, VerticalLine},
9        Border, TableOption,
10    },
11};
12
13#[cfg(feature = "std")]
14use crate::grid::config::ColoredConfig;
15
16/// Style is represents a theme of a [`Table`].
17///
18/// ```text
19/// corner top left         top intersection                    corner top right
20///                .             |                             .
21///                 .            V                            .
22///                  ╭───┬───┬───┬───┬───┬───┬────┬────┬────╮
23///                  │ i │ 0 │ 1 │ 2 │ 3 │ 4 │ 5  │ 6  │ 7  │
24///                  ├───┼───┼───┼───┼───┼───┼────┼────┼────┤ <- this horizontal line is custom 'horizontals'
25///                  │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0  │ 0  │ 0  │    other lines horizontal lines are not set they called 'horizontal'
26///                  │ 1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5  │ 6  │ 7  │
27///                  │ 2 │ 0 │ 2 │ 4 │ 6 │ 8 │ 10 │ 12 │ 14 │
28///                  ╰───┴───┴───┴───┴───┴───┴────┴────┴────╯
29///                .         ^                    ^           .
30///               .          |                    |            .
31/// corner bottom left       |         bottom intersection     corner bottom right
32///                          |
33///                          |
34///             all this vertical lines are called 'vertical'
35/// ```
36///
37///
38/// ```text
39///                     ┌───┬───┬───┬───┬───┐
40///                     │ 0 │ 1 │ 2 │ 3 │ 4 │
41/// intersection left ->├───X───X───X───X───┤ <- all this horizontal lines are called 'horizontal'
42///                     │ 1 │ 2 │ 3 │ 4 │ 5 │
43///                     ├───X───X───X───X───┤ <- intersection right
44///                     │ 2 │ 3 │ 4 │ 5 │ 6 │
45///                     └───┴───┴───┴───┴───┘
46///
47/// All 'X' positions are called 'intersection'.
48/// It's a place where 'vertical' and 'horizontal' lines intersect.
49/// ```
50///
51/// It tries to limit an controlling a valid state of it.
52/// For example, it won't allow to call method [`Style::corner_top_left`] unless [`Style::left`] and [`Style::top`] is set.
53///
54/// You can turn [`Style`] into [`Theme`] to have a precise control using [`Into`] implementation.
55///
56/// # Example
57///
58#[cfg_attr(feature = "std", doc = "```")]
59#[cfg_attr(not(feature = "std"), doc = "```ignore")]
60/// use tabled::{Table, settings::style::Style};
61///
62/// let data = vec!["Hello", "2021"];
63/// let mut table = Table::new(&data);
64///
65/// let style = Style::ascii().bottom('*').intersection(' ');
66/// table.with(style);
67///
68/// println!("{}", table);
69/// ```
70///
71/// [`Table`]: crate::Table
72/// [`Theme`]: crate::settings::themes::Theme
73/// [`Style::corner_top_left`]: Style::corner_top_left
74/// [`Style::left`]: Style.left
75/// [`Style::top`]: Style.function.top
76#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub struct Style<T, B, L, R, H, V, const HSIZE: usize, const VSIZE: usize> {
78    borders: Borders<char>,
79    horizontals: HArray<HSIZE>,
80    verticals: VArray<VSIZE>,
81    _top: PhantomData<T>,
82    _bottom: PhantomData<B>,
83    _left: PhantomData<L>,
84    _right: PhantomData<R>,
85    _horizontal: PhantomData<H>,
86    _vertical: PhantomData<V>,
87}
88
89type HLine = crate::grid::config::HorizontalLine<char>;
90type VLine = crate::grid::config::VerticalLine<char>;
91
92type HArray<const N: usize> = [(usize, HLine); N];
93type VArray<const N: usize> = [(usize, VLine); N];
94
95/// A marker struct which is used in [`Style`].
96#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Default, Hash)]
97pub struct On;
98
99impl Style<(), (), (), (), (), (), 0, 0> {
100    /// This style is a style with no styling options on,
101    ///
102    /// ```text
103    ///      id  distribution            link
104    ///      0      Fedora      https://getfedora.org/
105    ///      2     OpenSUSE    https://www.opensuse.org/
106    ///      3   Endeavouros   https://endeavouros.com/
107    /// ```
108    ///
109    /// Note: The cells in the example have 1-left and 1-right indent.
110    ///
111    /// This style can be used as a base style to build a custom one.
112    ///
113    /// ```rust,no_run
114    /// # use tabled::settings::style::Style;
115    /// let style = Style::empty()
116    ///     .top('*')
117    ///     .bottom('*')
118    ///     .vertical('#')
119    ///     .intersection_top('*');
120    /// ```
121    pub const fn empty() -> Style<(), (), (), (), (), (), 0, 0> {
122        Style::new(Borders::empty(), [], [])
123    }
124
125    /// This style is analog of `empty` but with a vertical space(' ') line.
126    ///
127    /// ```text
128    ///      id   distribution             link
129    ///      0       Fedora       https://getfedora.org/
130    ///      2      OpenSUSE     https://www.opensuse.org/
131    ///      3    Endeavouros    https://endeavouros.com/
132    /// ```
133    pub const fn blank() -> Style<(), (), (), (), (), On, 0, 0> {
134        Style::new(
135            create_borders(
136                HLine::empty(),
137                HLine::empty(),
138                HLine::empty(),
139                None,
140                None,
141                Some(' '),
142            ),
143            [],
144            [],
145        )
146    }
147
148    /// This is a style which relays only on ASCII charset.
149    ///
150    /// It has horizontal and vertical lines.
151    ///
152    /// ```text
153    ///     +----+--------------+---------------------------+
154    ///     | id | distribution |           link            |
155    ///     +----+--------------+---------------------------+
156    ///     | 0  |    Fedora    |  https://getfedora.org/   |
157    ///     +----+--------------+---------------------------+
158    ///     | 2  |   OpenSUSE   | https://www.opensuse.org/ |
159    ///     +----+--------------+---------------------------+
160    ///     | 3  | Endeavouros  | https://endeavouros.com/  |
161    ///     +----+--------------+---------------------------+
162    /// ```
163    pub const fn ascii() -> Style<On, On, On, On, On, On, 0, 0> {
164        Style::new(
165            create_borders(
166                HLine::full('-', '+', '+', '+'),
167                HLine::full('-', '+', '+', '+'),
168                HLine::full('-', '+', '+', '+'),
169                Some('|'),
170                Some('|'),
171                Some('|'),
172            ),
173            [],
174            [],
175        )
176    }
177
178    /// `psql` style looks like a table style `PostgreSQL` uses.
179    ///
180    /// It has only 1 horizontal line which splits header.
181    /// And no left and right vertical lines.
182    ///
183    /// ```text
184    ///      id | distribution |           link
185    ///     ----+--------------+---------------------------
186    ///      0  |    Fedora    |  https://getfedora.org/
187    ///      2  |   OpenSUSE   | https://www.opensuse.org/
188    ///      3  | Endeavouros  | https://endeavouros.com/
189    /// ```
190    pub const fn psql() -> Style<(), (), (), (), (), On, 1, 0> {
191        Style::new(
192            create_borders(
193                HLine::empty(),
194                HLine::empty(),
195                HLine::empty(),
196                None,
197                None,
198                Some('|'),
199            ),
200            [(1, HLine::new(Some('-'), Some('+'), None, None))],
201            [],
202        )
203    }
204
205    /// `markdown` style mimics a `Markdown` table style.
206    ///
207    /// ```text
208    ///     | id | distribution |           link            |
209    ///     |----|--------------|---------------------------|
210    ///     | 0  |    Fedora    |  https://getfedora.org/   |
211    ///     | 2  |   OpenSUSE   | https://www.opensuse.org/ |
212    ///     | 3  | Endeavouros  | https://endeavouros.com/  |
213    /// ```
214    pub const fn markdown() -> Style<(), (), On, On, (), On, 1, 0> {
215        Style::new(
216            create_borders(
217                HLine::empty(),
218                HLine::empty(),
219                HLine::empty(),
220                Some('|'),
221                Some('|'),
222                Some('|'),
223            ),
224            [(1, HLine::full('-', '|', '|', '|'))],
225            [],
226        )
227    }
228
229    /// This style is analog of [`Style::ascii`] which uses UTF-8 charset.
230    ///
231    /// It has vertical and horizontal split lines.
232    ///
233    /// ```text
234    ///     ┌────┬──────────────┬───────────────────────────┐
235    ///     │ id │ distribution │           link            │
236    ///     ├────┼──────────────┼───────────────────────────┤
237    ///     │ 0  │    Fedora    │  https://getfedora.org/   │
238    ///     ├────┼──────────────┼───────────────────────────┤
239    ///     │ 2  │   OpenSUSE   │ https://www.opensuse.org/ │
240    ///     ├────┼──────────────┼───────────────────────────┤
241    ///     │ 3  │ Endeavouros  │ https://endeavouros.com/  │
242    ///     └────┴──────────────┴───────────────────────────┘
243    /// ```
244    pub const fn modern() -> Style<On, On, On, On, On, On, 0, 0> {
245        Style::new(
246            create_borders(
247                HLine::full('─', '┬', '┌', '┐'),
248                HLine::full('─', '┴', '└', '┘'),
249                HLine::full('─', '┼', '├', '┤'),
250                Some('│'),
251                Some('│'),
252                Some('│'),
253            ),
254            [],
255            [],
256        )
257    }
258
259    /// This style looks like a [`Style::modern`] but without horozizontal lines except a header.
260    ///
261    /// Beware: It uses UTF-8 characters.
262    ///
263    /// ```text
264    ///     ┌────┬──────────────┬───────────────────────────┐
265    ///     │ id │ distribution │           link            │
266    ///     ├────┼──────────────┼───────────────────────────┤
267    ///     │ 0  │    Fedora    │  https://getfedora.org/   │
268    ///     │ 2  │   OpenSUSE   │ https://www.opensuse.org/ │
269    ///     │ 3  │ Endeavouros  │ https://endeavouros.com/  │
270    ///     └────┴──────────────┴───────────────────────────┘
271    /// ```
272    pub const fn sharp() -> Style<On, On, On, On, (), On, 1, 0> {
273        Style::new(
274            create_borders(
275                HLine::full('─', '┬', '┌', '┐'),
276                HLine::full('─', '┴', '└', '┘'),
277                HLine::empty(),
278                Some('│'),
279                Some('│'),
280                Some('│'),
281            ),
282            [(1, HLine::full('─', '┼', '├', '┤'))],
283            [],
284        )
285    }
286
287    /// This style looks like a [`Style::sharp`] but with rounded corners.
288    ///
289    /// Beware: It uses UTF-8 characters.
290    ///
291    /// ```text
292    ///     ╭────┬──────────────┬───────────────────────────╮
293    ///     │ id │ distribution │           link            │
294    ///     ├────┼──────────────┼───────────────────────────┤
295    ///     │ 0  │    Fedora    │  https://getfedora.org/   │
296    ///     │ 2  │   OpenSUSE   │ https://www.opensuse.org/ │
297    ///     │ 3  │ Endeavouros  │ https://endeavouros.com/  │
298    ///     ╰────┴──────────────┴───────────────────────────╯
299    /// ```
300    pub const fn rounded() -> Style<On, On, On, On, (), On, 1, 0> {
301        Style::new(
302            create_borders(
303                HLine::full('─', '┬', '╭', '╮'),
304                HLine::full('─', '┴', '╰', '╯'),
305                HLine::empty(),
306                Some('│'),
307                Some('│'),
308                Some('│'),
309            ),
310            [(1, HLine::full('─', '┼', '├', '┤'))],
311            [],
312        )
313    }
314
315    /// This style looks like a [`Style::rounded`] but with horizontals lines.
316    ///
317    /// Beware: It uses UTF-8 characters.
318    ///
319    /// ```text
320    ///     ╭────┬──────────────┬───────────────────────────╮
321    ///     │ id │ distribution │           link            │
322    ///     ├────┼──────────────┼───────────────────────────┤
323    ///     │ 0  │    Fedora    │  https://getfedora.org/   │
324    ///     ├────┼──────────────┼───────────────────────────┤
325    ///     │ 2  │   OpenSUSE   │ https://www.opensuse.org/ │
326    ///     ├────┼──────────────┼───────────────────────────┤
327    ///     │ 3  │ Endeavouros  │ https://endeavouros.com/  │
328    ///     ╰────┴──────────────┴───────────────────────────╯
329    /// ```
330    pub const fn modern_rounded() -> Style<On, On, On, On, On, On, 0, 0> {
331        Style::new(
332            create_borders(
333                HLine::full('─', '┬', '╭', '╮'),
334                HLine::full('─', '┴', '╰', '╯'),
335                HLine::full('─', '┼', '├', '┤'),
336                Some('│'),
337                Some('│'),
338                Some('│'),
339            ),
340            [],
341            [],
342        )
343    }
344
345    /// This style uses a chars which resembles '2 lines'.
346    ///
347    /// Beware: It uses UTF8 characters.
348    ///
349    /// ```text
350    ///     ╔════╦══════════════╦═══════════════════════════╗
351    ///     ║ id ║ distribution ║           link            ║
352    ///     ╠════╬══════════════╬═══════════════════════════╣
353    ///     ║ 0  ║    Fedora    ║  https://getfedora.org/   ║
354    ///     ╠════╬══════════════╬═══════════════════════════╣
355    ///     ║ 2  ║   OpenSUSE   ║ https://www.opensuse.org/ ║
356    ///     ╠════╬══════════════╬═══════════════════════════╣
357    ///     ║ 3  ║ Endeavouros  ║ https://endeavouros.com/  ║
358    ///     ╚════╩══════════════╩═══════════════════════════╝
359    /// ```
360    pub const fn extended() -> Style<On, On, On, On, On, On, 0, 0> {
361        Style::new(
362            create_borders(
363                HLine::full('═', '╦', '╔', '╗'),
364                HLine::full('═', '╩', '╚', '╝'),
365                HLine::full('═', '╬', '╠', '╣'),
366                Some('║'),
367                Some('║'),
368                Some('║'),
369            ),
370            [],
371            [],
372        )
373    }
374
375    /// This is a style uses only '.' and ':' chars.
376    /// It has a vertical and horizontal split lines.
377    ///
378    /// ```text
379    ///     .................................................
380    ///     : id : distribution :           link            :
381    ///     :....:..............:...........................:
382    ///     : 0  :    Fedora    :  https://getfedora.org/   :
383    ///     :....:..............:...........................:
384    ///     : 2  :   OpenSUSE   : https://www.opensuse.org/ :
385    ///     :....:..............:...........................:
386    ///     : 3  : Endeavouros  : https://endeavouros.com/  :
387    ///     :....:..............:...........................:
388    /// ```
389    pub const fn dots() -> Style<On, On, On, On, On, On, 0, 0> {
390        Style::new(
391            create_borders(
392                HLine::full('.', '.', '.', '.'),
393                HLine::full('.', ':', ':', ':'),
394                HLine::full('.', ':', ':', ':'),
395                Some(':'),
396                Some(':'),
397                Some(':'),
398            ),
399            [],
400            [],
401        )
402    }
403
404    /// This style is one of table views in `ReStructuredText`.
405    ///
406    /// ```text
407    ///     ==== ============== ===========================
408    ///      id   distribution             link            
409    ///     ==== ============== ===========================
410    ///      0       Fedora       https://getfedora.org/   
411    ///      2      OpenSUSE     https://www.opensuse.org/
412    ///      3    Endeavouros    https://endeavouros.com/  
413    ///     ==== ============== ===========================
414    /// ```
415    pub const fn re_structured_text() -> Style<On, On, (), (), (), On, 1, 0> {
416        Style::new(
417            create_borders(
418                HLine::new(Some('='), Some(' '), None, None),
419                HLine::new(Some('='), Some(' '), None, None),
420                HLine::empty(),
421                None,
422                None,
423                Some(' '),
424            ),
425            [(1, HLine::new(Some('='), Some(' '), None, None))],
426            [],
427        )
428    }
429
430    /// This is a theme analog of [`Style::rounded`], but in using ascii charset and
431    /// with no horizontal lines.
432    ///
433    /// ```text
434    ///     .-----------------------------------------------.
435    ///     | id | distribution |           link            |
436    ///     | 0  |    Fedora    |  https://getfedora.org/   |
437    ///     | 2  |   OpenSUSE   | https://www.opensuse.org/ |
438    ///     | 3  | Endeavouros  | https://endeavouros.com/  |
439    ///     '-----------------------------------------------'
440    /// ```
441    pub const fn ascii_rounded() -> Style<On, On, On, On, (), On, 0, 0> {
442        Style::new(
443            create_borders(
444                HLine::full('-', '-', '.', '.'),
445                HLine::full('-', '-', '\'', '\''),
446                HLine::empty(),
447                Some('|'),
448                Some('|'),
449                Some('|'),
450            ),
451            [],
452            [],
453        )
454    }
455}
456
457impl<T, B, L, R, H, V, const HSIZE: usize, const VSIZE: usize>
458    Style<T, B, L, R, H, V, HSIZE, VSIZE>
459{
460    pub(crate) const fn new(
461        borders: Borders<char>,
462        horizontals: HArray<HSIZE>,
463        verticals: VArray<VSIZE>,
464    ) -> Self {
465        Self {
466            borders,
467            horizontals,
468            verticals,
469            _top: PhantomData,
470            _bottom: PhantomData,
471            _left: PhantomData,
472            _right: PhantomData,
473            _horizontal: PhantomData,
474            _vertical: PhantomData,
475        }
476    }
477
478    pub(crate) const fn get_borders(&self) -> Borders<char> {
479        self.borders
480    }
481
482    #[cfg(feature = "std")]
483    pub(crate) const fn get_horizontals(&self) -> [(usize, HLine); HSIZE] {
484        self.horizontals
485    }
486}
487
488impl<T, B, L, R, H, V, const HN: usize, const VN: usize> Style<T, B, L, R, H, V, HN, VN> {
489    /// Set border horizontal lines.
490    ///
491    /// # Example
492    ///
493    #[cfg_attr(feature = "derive", doc = "```")]
494    #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
495    /// use tabled::{settings::style::{Style, HorizontalLine}, Table};
496    ///
497    /// let data = (0..3).map(|i| ("Hello", i));
498    /// let mut table = Table::new(data);
499    ///
500    /// let style = Style::rounded().horizontals([
501    ///     (1, HorizontalLine::filled('#')),
502    ///     (2, HorizontalLine::filled('&')),
503    ///     (3, HorizontalLine::filled('@')),
504    /// ]);
505    ///
506    /// table.with(style);
507    ///
508    /// assert_eq!(
509    ///     table.to_string(),
510    ///     concat!(
511    ///         "╭───────┬─────╮\n",
512    ///         "│ &str  │ i32 │\n",
513    ///         "###############\n",
514    ///         "│ Hello │ 0   │\n",
515    ///         "&&&&&&&&&&&&&&&\n",
516    ///         "│ Hello │ 1   │\n",
517    ///         "@@@@@@@@@@@@@@@\n",
518    ///         "│ Hello │ 2   │\n",
519    ///         "╰───────┴─────╯",
520    ///     )
521    /// )
522    /// ```
523    pub const fn horizontals<const SIZE: usize>(
524        self,
525        list: [(usize, HorizontalLine<L, R, V>); SIZE],
526    ) -> Style<T, B, L, R, H, V, SIZE, VN> {
527        let list = harr_convert(list);
528        Style::new(self.borders, list, self.verticals)
529    }
530
531    /// Set border vertical lines.
532    ///
533    /// # Example
534    ///
535    #[cfg_attr(feature = "derive", doc = "```")]
536    #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
537    /// use tabled::{settings::style::{Style, VerticalLine}, Table};
538    ///
539    /// let data = (0..3).map(|i| ("Hello", "World", i));
540    /// let mut table = Table::new(data);
541    ///
542    /// let style = Style::rounded().verticals([
543    ///     (1, VerticalLine::new('#').top(':').bottom('.')),
544    ///     (2, VerticalLine::new('&').top(':').bottom('.')),
545    /// ]);
546    /// let table = table.with(style).to_string();
547    ///
548    /// assert_eq!(
549    ///     table,
550    ///     concat!(
551    ///         "╭───────:───────:─────╮\n",
552    ///         "│ &str  # &str  & i32 │\n",
553    ///         "├───────┼───────┼─────┤\n",
554    ///         "│ Hello # World & 0   │\n",
555    ///         "│ Hello # World & 1   │\n",
556    ///         "│ Hello # World & 2   │\n",
557    ///         "╰───────.───────.─────╯",
558    ///     )
559    /// )
560    /// ```
561    pub const fn verticals<const SIZE: usize>(
562        self,
563        list: [(usize, VerticalLine<T, B, H>); SIZE],
564    ) -> Style<T, B, L, R, H, V, HN, SIZE> {
565        let list = varr_convert(list);
566        Style::new(self.borders, self.horizontals, list)
567    }
568
569    /// Removes all horizontal lines set by [`Style::horizontals`]
570    pub const fn remove_horizontals(self) -> Style<T, B, L, R, H, V, 0, VN> {
571        Style::new(self.borders, [], self.verticals)
572    }
573
574    /// Removes all verticals lines set by [`Style::verticals`]
575    pub const fn remove_verticals(self) -> Style<T, B, L, R, H, V, HN, 0> {
576        Style::new(self.borders, self.horizontals, [])
577    }
578
579    /// Sets a top border.
580    ///
581    /// Any corners and intersections which were set will be overridden.
582    pub const fn top(mut self, c: char) -> Style<On, B, L, R, H, V, HN, VN>
583    where
584        T: Copy,
585        B: Copy,
586        H: Copy,
587    {
588        self.borders.top = Some(c);
589
590        if self.borders.has_left() {
591            self.borders.top_left = Some(c);
592        }
593
594        if self.borders.has_right() {
595            self.borders.top_right = Some(c);
596        }
597
598        if self.borders.has_vertical() {
599            self.borders.top_intersection = Some(c);
600        }
601
602        let verticals = varr_set(self.verticals, VLine::new(None, None, Some(c), None));
603
604        Style::new(self.borders, self.horizontals, verticals)
605    }
606
607    /// Sets a bottom border.
608    ///
609    /// Any corners and intersections which were set will be overridden.
610    pub const fn bottom(mut self, c: char) -> Style<T, On, L, R, H, V, HN, VN>
611    where
612        T: Copy,
613        B: Copy,
614        H: Copy,
615    {
616        self.borders.bottom = Some(c);
617
618        if self.borders.has_left() {
619            self.borders.bottom_left = Some(c);
620        }
621
622        if self.borders.has_right() {
623            self.borders.bottom_right = Some(c);
624        }
625
626        if self.borders.has_vertical() {
627            self.borders.bottom_intersection = Some(c);
628        }
629
630        let verticals = varr_set(self.verticals, VLine::new(None, None, None, Some(c)));
631
632        Style::new(self.borders, self.horizontals, verticals)
633    }
634
635    /// Sets a left border.
636    ///
637    /// Any corners and intersections which were set will be overridden.
638    pub const fn left(mut self, c: char) -> Style<T, B, On, R, H, V, HN, VN>
639    where
640        L: Copy,
641        R: Copy,
642        V: Copy,
643    {
644        self.borders.left = Some(c);
645
646        if self.borders.has_top() {
647            self.borders.top_left = Some(c);
648        }
649
650        if self.borders.has_bottom() {
651            self.borders.bottom_left = Some(c);
652        }
653
654        if self.borders.has_horizontal() {
655            self.borders.left_intersection = Some(c);
656        }
657
658        let horizontals = harr_set(self.horizontals, HLine::new(None, None, Some(c), None));
659
660        Style::new(self.borders, horizontals, self.verticals)
661    }
662
663    /// Sets a right border.
664    ///
665    /// Any corners and intersections which were set will be overridden.
666    pub const fn right(mut self, c: char) -> Style<T, B, L, On, H, V, HN, VN>
667    where
668        L: Copy,
669        R: Copy,
670        V: Copy,
671    {
672        self.borders.right = Some(c);
673
674        if self.borders.has_top() {
675            self.borders.top_right = Some(c);
676        }
677
678        if self.borders.has_bottom() {
679            self.borders.bottom_right = Some(c);
680        }
681
682        if self.borders.has_horizontal() {
683            self.borders.right_intersection = Some(c);
684        }
685
686        let horizontals = harr_set(self.horizontals, HLine::new(None, None, None, Some(c)));
687
688        Style::new(self.borders, horizontals, self.verticals)
689    }
690
691    /// Sets a horizontal split line.
692    ///
693    /// Any corners and intersections which were set will be overridden.
694    pub const fn horizontal(mut self, c: char) -> Style<T, B, L, R, On, V, HN, VN>
695    where
696        T: Copy,
697        B: Copy,
698        H: Copy,
699    {
700        self.borders.horizontal = Some(c);
701
702        if self.borders.has_vertical() {
703            self.borders.intersection = Some(c);
704        }
705
706        if self.borders.has_left() {
707            self.borders.left_intersection = Some(c);
708        }
709
710        if self.borders.has_right() {
711            self.borders.right_intersection = Some(c);
712        }
713
714        let verticals = varr_set(self.verticals, VLine::new(None, Some(c), None, None));
715
716        Style::new(self.borders, self.horizontals, verticals)
717    }
718
719    /// Sets a vertical split line.
720    ///
721    /// Any corners and intersections which were set will be overridden.
722    pub const fn vertical(mut self, c: char) -> Style<T, B, L, R, H, On, HN, VN>
723    where
724        L: Copy,
725        R: Copy,
726        V: Copy,
727    {
728        self.borders.vertical = Some(c);
729
730        if self.borders.has_horizontal() {
731            self.borders.intersection = Some(c);
732        }
733
734        if self.borders.has_top() {
735            self.borders.top_intersection = Some(c);
736        }
737
738        if self.borders.has_bottom() {
739            self.borders.bottom_intersection = Some(c);
740        }
741
742        let horizontals = harr_set(self.horizontals, HLine::new(None, Some(c), None, None));
743
744        Style::new(self.borders, horizontals, self.verticals)
745    }
746
747    /// Set a vertical line.
748    /// An equivalent of calling vertical+top_intersection+bottom_intersection+intersion.
749    ///
750    /// Notice, that it will clear everything that is outdated, meaning
751    /// If your style has a top border line and but the given vertical line has not got it then it will be removed.
752    pub const fn line_vertical<Top, Bottom, Intersection>(
753        mut self,
754        line: VerticalLine<Top, Bottom, Intersection>,
755    ) -> Style<Top, Bottom, L, R, Intersection, On, HN, VN>
756    where
757        L: Copy,
758        R: Copy,
759        Top: Copy,
760        Bottom: Copy,
761        Intersection: Copy,
762    {
763        let line = line.into_inner();
764
765        self.borders.vertical = line.main;
766        self.borders.intersection = line.intersection;
767        self.borders.top_intersection = line.top;
768        self.borders.bottom_intersection = line.bottom;
769
770        if line.intersection.is_none() {
771            self.borders.horizontal = None;
772            self.borders.left_intersection = None;
773            self.borders.right_intersection = None;
774            self.borders.intersection = None;
775        } else {
776            if self.borders.has_left() && self.borders.left_intersection.is_none() {
777                self.borders.left_intersection = Some(' ');
778            }
779
780            if self.borders.has_right() && self.borders.right_intersection.is_none() {
781                self.borders.right_intersection = Some(' ');
782            }
783
784            if self.borders.horizontal.is_none() {
785                self.borders.horizontal = Some(' ');
786            }
787        }
788
789        if line.top.is_none() {
790            self.borders.top = None;
791            self.borders.top_left = None;
792            self.borders.top_right = None;
793            self.borders.top_intersection = None;
794        }
795
796        if line.bottom.is_none() {
797            self.borders.bottom = None;
798            self.borders.bottom_left = None;
799            self.borders.bottom_right = None;
800            self.borders.bottom_intersection = None;
801        }
802
803        let horizontals = harr_set(
804            self.horizontals,
805            HLine::new(None, line.intersection, None, None),
806        );
807        let verticals = varr_set(
808            self.verticals,
809            VLine::new(None, line.intersection, line.top, line.bottom),
810        );
811
812        Style::new(self.borders, horizontals, verticals)
813    }
814
815    /// Set a horizontal line.
816    /// An equivalent of calling horizontal+left_intersection+right_intersection+intersion.
817    ///
818    /// Notice, that it will clear everything that is outdated, meaning
819    /// If your style has a left border line and but the given vertical line has not got it then it will be removed.
820    pub const fn line_horizontal<Left, Right, Intersection>(
821        mut self,
822        line: HorizontalLine<Left, Right, Intersection>,
823    ) -> Style<T, B, Left, Right, On, Intersection, HN, VN>
824    where
825        L: Copy,
826        R: Copy,
827        Left: Copy,
828        Right: Copy,
829        Intersection: Copy,
830    {
831        let line = line.into_inner();
832
833        self.borders.horizontal = line.main;
834        self.borders.intersection = line.intersection;
835        self.borders.left_intersection = line.left;
836        self.borders.right_intersection = line.right;
837
838        if line.intersection.is_none() {
839            self.borders.vertical = None;
840            self.borders.top_intersection = None;
841            self.borders.bottom_intersection = None;
842            self.borders.intersection = None;
843        } else {
844            if self.borders.has_top() && self.borders.top_intersection.is_none() {
845                self.borders.top_intersection = Some(' ');
846            }
847
848            if self.borders.has_bottom() && self.borders.bottom_intersection.is_none() {
849                self.borders.bottom_intersection = Some(' ');
850            }
851
852            if self.borders.vertical.is_none() {
853                self.borders.vertical = Some(' ');
854            }
855        }
856
857        if line.left.is_none() {
858            self.borders.left = None;
859            self.borders.top_left = None;
860            self.borders.bottom_left = None;
861            self.borders.left_intersection = None;
862        }
863
864        if line.right.is_none() {
865            self.borders.right = None;
866            self.borders.top_right = None;
867            self.borders.bottom_right = None;
868            self.borders.right_intersection = None;
869        }
870
871        let horizontals = harr_set(
872            self.horizontals,
873            HLine::new(None, line.intersection, line.left, line.right),
874        );
875        let verticals = varr_set(
876            self.verticals,
877            VLine::new(None, line.intersection, None, None),
878        );
879
880        Style::new(self.borders, horizontals, verticals)
881    }
882
883    /// Set a horizontal line.
884    /// An equivalent of calling top+cornet_top_right+cornet_top_left+top_intersection.
885    ///
886    /// Notice, that it will clear everything that is outdated, meaning
887    /// If your style has a left border line and but the given vertical line has not got it then it will be removed.
888    pub const fn line_top<Left, Right, Intersection>(
889        mut self,
890        line: HorizontalLine<Left, Right, Intersection>,
891    ) -> Style<On, B, Left, Right, H, Intersection, HN, VN>
892    where
893        L: Copy,
894        R: Copy,
895        Left: Copy,
896        Right: Copy,
897        Intersection: Copy,
898    {
899        let line = line.into_inner();
900
901        self.borders.top = line.main;
902        self.borders.top_intersection = line.intersection;
903        self.borders.top_left = line.left;
904        self.borders.top_right = line.right;
905
906        if line.intersection.is_none() {
907            self.borders.vertical = None;
908            self.borders.top_intersection = None;
909            self.borders.bottom_intersection = None;
910            self.borders.intersection = None;
911        } else {
912            if self.borders.has_top() && self.borders.top_intersection.is_none() {
913                self.borders.top_intersection = Some(' ');
914            }
915
916            if self.borders.has_bottom() && self.borders.bottom_intersection.is_none() {
917                self.borders.bottom_intersection = Some(' ');
918            }
919
920            if self.borders.vertical.is_none() {
921                self.borders.vertical = Some(' ');
922            }
923        }
924
925        if line.left.is_none() {
926            self.borders.left = None;
927            self.borders.top_left = None;
928            self.borders.bottom_left = None;
929            self.borders.left_intersection = None;
930        }
931
932        if line.right.is_none() {
933            self.borders.right = None;
934            self.borders.top_right = None;
935            self.borders.bottom_right = None;
936            self.borders.right_intersection = None;
937        }
938
939        let horizontals = harr_set(
940            self.horizontals,
941            HLine::new(None, line.intersection, line.left, line.right),
942        );
943        let verticals = varr_set(
944            self.verticals,
945            VLine::new(None, line.intersection, None, None),
946        );
947
948        Style::new(self.borders, horizontals, verticals)
949    }
950
951    /// Set a horizontal line.
952    /// An equivalent of calling bottom+cornet_bottom_right+cornet_bottom_left+bottom_intersection.
953    ///
954    /// Notice, that it will clear everything that is outdated, meaning
955    /// If your style has a left border line and but the given vertical line has not got it then it will be removed.
956    pub const fn line_bottom<Left, Right, Intersection>(
957        mut self,
958        line: HorizontalLine<Left, Right, Intersection>,
959    ) -> Style<T, On, Left, Right, H, Intersection, HN, VN>
960    where
961        L: Copy,
962        R: Copy,
963        Left: Copy,
964        Right: Copy,
965        Intersection: Copy,
966    {
967        let line = line.into_inner();
968
969        self.borders.bottom = line.main;
970        self.borders.bottom_intersection = line.intersection;
971        self.borders.bottom_left = line.left;
972        self.borders.bottom_right = line.right;
973
974        if line.intersection.is_none() {
975            self.borders.vertical = None;
976            self.borders.top_intersection = None;
977            self.borders.bottom_intersection = None;
978            self.borders.intersection = None;
979        } else {
980            if self.borders.has_top() && self.borders.top_intersection.is_none() {
981                self.borders.top_intersection = Some(' ');
982            }
983
984            if self.borders.has_bottom() && self.borders.bottom_intersection.is_none() {
985                self.borders.bottom_intersection = Some(' ');
986            }
987
988            if self.borders.vertical.is_none() {
989                self.borders.vertical = Some(' ');
990            }
991        }
992
993        if line.left.is_none() {
994            self.borders.left = None;
995            self.borders.top_left = None;
996            self.borders.bottom_left = None;
997            self.borders.left_intersection = None;
998        }
999
1000        if line.right.is_none() {
1001            self.borders.right = None;
1002            self.borders.top_right = None;
1003            self.borders.bottom_right = None;
1004            self.borders.right_intersection = None;
1005        }
1006
1007        let horizontals = harr_set(
1008            self.horizontals,
1009            HLine::new(None, line.intersection, line.left, line.right),
1010        );
1011        let verticals = varr_set(
1012            self.verticals,
1013            VLine::new(None, line.intersection, None, None),
1014        );
1015
1016        Style::new(self.borders, horizontals, verticals)
1017    }
1018
1019    /// Set a vertical line.
1020    /// An equivalent of calling left+corner_top_left+corner_bottom_left+left_intersection.
1021    ///
1022    /// Notice, that it will clear everything that is outdated, meaning
1023    /// If your style has a top border line and but the given vertical line has not got it then it will be removed.
1024    pub const fn line_left<Top, Bottom, Intersection>(
1025        mut self,
1026        line: VerticalLine<Top, Bottom, Intersection>,
1027    ) -> Style<Top, Bottom, On, R, Intersection, V, HN, VN>
1028    where
1029        L: Copy,
1030        R: Copy,
1031        Top: Copy,
1032        Bottom: Copy,
1033        Intersection: Copy,
1034    {
1035        let line = line.into_inner();
1036
1037        self.borders.left = line.main;
1038        self.borders.left_intersection = line.intersection;
1039        self.borders.top_left = line.top;
1040        self.borders.bottom_left = line.bottom;
1041
1042        if line.intersection.is_none() {
1043            self.borders.horizontal = None;
1044            self.borders.left_intersection = None;
1045            self.borders.right_intersection = None;
1046            self.borders.intersection = None;
1047        } else {
1048            if self.borders.has_left() && self.borders.left_intersection.is_none() {
1049                self.borders.left_intersection = Some(' ');
1050            }
1051
1052            if self.borders.has_right() && self.borders.right_intersection.is_none() {
1053                self.borders.right_intersection = Some(' ');
1054            }
1055
1056            if self.borders.horizontal.is_none() {
1057                self.borders.horizontal = Some(' ');
1058            }
1059        }
1060
1061        if line.top.is_none() {
1062            self.borders.top = None;
1063            self.borders.top_left = None;
1064            self.borders.top_right = None;
1065            self.borders.top_intersection = None;
1066        }
1067
1068        if line.bottom.is_none() {
1069            self.borders.bottom = None;
1070            self.borders.bottom_left = None;
1071            self.borders.bottom_right = None;
1072            self.borders.bottom_intersection = None;
1073        }
1074
1075        let horizontals = harr_set(
1076            self.horizontals,
1077            HLine::new(None, line.intersection, None, None),
1078        );
1079        let verticals = varr_set(
1080            self.verticals,
1081            VLine::new(None, line.intersection, line.top, line.bottom),
1082        );
1083
1084        Style::new(self.borders, horizontals, verticals)
1085    }
1086
1087    /// Set a vertical line.
1088    /// An equivalent of calling right+corner_top_right+corner_bottom_right+right_intersection.
1089    ///
1090    /// Notice, that it will clear everything that is outdated, meaning
1091    /// If your style has a top border line and but the given vertical line has not got it then it will be removed.
1092    pub const fn line_right<Top, Bottom, Intersection>(
1093        mut self,
1094        line: VerticalLine<Top, Bottom, Intersection>,
1095    ) -> Style<Top, Bottom, L, On, Intersection, V, HN, VN>
1096    where
1097        L: Copy,
1098        R: Copy,
1099        Top: Copy,
1100        Bottom: Copy,
1101        Intersection: Copy,
1102    {
1103        let line = line.into_inner();
1104
1105        self.borders.right = line.main;
1106        self.borders.right_intersection = line.intersection;
1107        self.borders.top_right = line.top;
1108        self.borders.bottom_right = line.bottom;
1109
1110        if line.intersection.is_none() {
1111            self.borders.horizontal = None;
1112            self.borders.left_intersection = None;
1113            self.borders.right_intersection = None;
1114            self.borders.intersection = None;
1115        } else {
1116            if self.borders.has_left() && self.borders.left_intersection.is_none() {
1117                self.borders.left_intersection = Some(' ');
1118            }
1119
1120            if self.borders.has_right() && self.borders.right_intersection.is_none() {
1121                self.borders.right_intersection = Some(' ');
1122            }
1123
1124            if self.borders.horizontal.is_none() {
1125                self.borders.horizontal = Some(' ');
1126            }
1127        }
1128
1129        if line.top.is_none() {
1130            self.borders.top = None;
1131            self.borders.top_left = None;
1132            self.borders.top_right = None;
1133            self.borders.top_intersection = None;
1134        }
1135
1136        if line.bottom.is_none() {
1137            self.borders.bottom = None;
1138            self.borders.bottom_left = None;
1139            self.borders.bottom_right = None;
1140            self.borders.bottom_intersection = None;
1141        }
1142
1143        let horizontals = harr_set(
1144            self.horizontals,
1145            HLine::new(None, line.intersection, None, None),
1146        );
1147        let verticals = varr_set(
1148            self.verticals,
1149            VLine::new(None, line.intersection, line.top, line.bottom),
1150        );
1151
1152        Style::new(self.borders, horizontals, verticals)
1153    }
1154
1155    /// Set a frame for a style.
1156    ///
1157    /// It makes assumptions that a full frame will be set, but it may not be.
1158    ///
1159    /// # Example
1160    ///
1161    /// ```
1162    /// use tabled::{Table, settings::style::{Style, Border}};
1163    ///
1164    /// let data = [["10:52:19", "Hello"], ["10:52:20", "World"]];
1165    /// let table = Table::new(data)
1166    ///     .with(Style::ascii().frame(Border::inherit(Style::modern())))
1167    ///     .to_string();
1168    ///
1169    /// assert_eq!(
1170    ///     table,
1171    ///     concat!(
1172    ///         "┌──────────+───────┐\n",
1173    ///         "│ 0        | 1     │\n",
1174    ///         "+----------+-------+\n",
1175    ///         "│ 10:52:19 | Hello │\n",
1176    ///         "+----------+-------+\n",
1177    ///         "│ 10:52:20 | World │\n",
1178    ///         "└──────────+───────┘",
1179    ///     )
1180    /// );
1181    /// ```
1182    pub const fn frame<Top, Bottom, Left, Right>(
1183        mut self,
1184        border: Border<Top, Bottom, Left, Right>,
1185    ) -> Style<Top, Bottom, Left, Right, H, V, HN, VN>
1186    where
1187        T: Copy,
1188        B: Copy,
1189        L: Copy,
1190        R: Copy,
1191        H: Copy,
1192        V: Copy,
1193        Left: Copy,
1194        Right: Copy,
1195        Top: Copy,
1196        Bottom: Copy,
1197    {
1198        let border = border.into_inner();
1199        let border = correct_border(border);
1200
1201        let horizontals = harr_set(
1202            self.horizontals,
1203            HLine::new(None, None, border.left, border.right),
1204        );
1205        let verticals = varr_set(
1206            self.verticals,
1207            VLine::new(None, None, border.top, border.bottom),
1208        );
1209
1210        self.borders.top = border.top;
1211        self.borders.bottom = border.bottom;
1212        self.borders.left = border.left;
1213        self.borders.top_left = border.left_top_corner;
1214        self.borders.bottom_left = border.left_bottom_corner;
1215        self.borders.right = border.right;
1216        self.borders.top_right = border.right_top_corner;
1217        self.borders.bottom_right = border.right_bottom_corner;
1218
1219        Style::new(self.borders, horizontals, verticals)
1220    }
1221}
1222
1223impl<B, R, H, V, const HN: usize, const VN: usize> Style<On, B, On, R, H, V, HN, VN> {
1224    /// Sets a top left corner.
1225    pub const fn corner_top_left(mut self, c: char) -> Self {
1226        self.borders.top_left = Some(c);
1227
1228        Style::new(self.borders, self.horizontals, self.verticals)
1229    }
1230}
1231
1232impl<B, L, H, V, const HN: usize, const VN: usize> Style<On, B, L, On, H, V, HN, VN> {
1233    /// Sets a top right corner.
1234    pub const fn corner_top_right(mut self, c: char) -> Self {
1235        self.borders.top_right = Some(c);
1236
1237        Style::new(self.borders, self.horizontals, self.verticals)
1238    }
1239}
1240
1241impl<T, L, H, V, const HN: usize, const VN: usize> Style<T, On, L, On, H, V, HN, VN> {
1242    /// Sets a bottom right corner.
1243    pub const fn corner_bottom_right(mut self, c: char) -> Self {
1244        self.borders.bottom_right = Some(c);
1245
1246        Style::new(self.borders, self.horizontals, self.verticals)
1247    }
1248}
1249
1250impl<T, R, H, V, const HN: usize, const VN: usize> Style<T, On, On, R, H, V, HN, VN> {
1251    /// Sets a bottom left corner.
1252    pub const fn corner_bottom_left(mut self, c: char) -> Self {
1253        self.borders.bottom_left = Some(c);
1254
1255        Style::new(self.borders, self.horizontals, self.verticals)
1256    }
1257}
1258
1259impl<T, B, R, V, const HN: usize, const VN: usize> Style<T, B, On, R, On, V, HN, VN> {
1260    /// Sets a left intersection char.
1261    pub const fn intersection_left(mut self, c: char) -> Self {
1262        self.borders.left_intersection = Some(c);
1263
1264        Style::new(self.borders, self.horizontals, self.verticals)
1265    }
1266}
1267
1268impl<T, B, L, V, const HN: usize, const VN: usize> Style<T, B, L, On, On, V, HN, VN> {
1269    /// Sets a right intersection char.
1270    pub const fn intersection_right(mut self, c: char) -> Self {
1271        self.borders.right_intersection = Some(c);
1272
1273        Style::new(self.borders, self.horizontals, self.verticals)
1274    }
1275}
1276
1277impl<B, L, R, H, const HN: usize, const VN: usize> Style<On, B, L, R, H, On, HN, VN> {
1278    /// Sets a top intersection char.
1279    pub const fn intersection_top(mut self, c: char) -> Self {
1280        self.borders.top_intersection = Some(c);
1281
1282        Style::new(self.borders, self.horizontals, self.verticals)
1283    }
1284}
1285
1286impl<T, L, R, H, const HN: usize, const VN: usize> Style<T, On, L, R, H, On, HN, VN> {
1287    /// Sets a bottom intersection char.
1288    pub const fn intersection_bottom(mut self, c: char) -> Self {
1289        self.borders.bottom_intersection = Some(c);
1290
1291        Style::new(self.borders, self.horizontals, self.verticals)
1292    }
1293}
1294
1295impl<T, B, L, R, const HN: usize, const VN: usize> Style<T, B, L, R, On, On, HN, VN> {
1296    /// Sets an inner intersection char.
1297    /// A char between horizontal and vertical split lines.
1298    pub const fn intersection(mut self, c: char) -> Self
1299    where
1300        T: Copy,
1301        B: Copy,
1302        R: Copy,
1303        L: Copy,
1304    {
1305        self.borders.intersection = Some(c);
1306
1307        let horizontals = harr_set(self.horizontals, HLine::new(None, Some(c), None, None));
1308        let verticals = varr_set(self.verticals, VLine::new(None, Some(c), None, None));
1309
1310        Style::new(self.borders, horizontals, verticals)
1311    }
1312}
1313
1314impl<B, L, R, H, V, const HN: usize, const VN: usize> Style<On, B, L, R, H, V, HN, VN> {
1315    /// Removes top border.
1316    pub const fn remove_top(mut self) -> Style<(), B, L, R, H, V, HN, VN>
1317    where
1318        B: Copy,
1319        H: Copy,
1320    {
1321        self.borders.top = None;
1322        self.borders.top_intersection = None;
1323        self.borders.top_left = None;
1324        self.borders.top_right = None;
1325
1326        let verticals = varr_unset(self.verticals, VLine::new(None, None, Some(' '), None));
1327
1328        Style::new(self.borders, self.horizontals, verticals)
1329    }
1330}
1331
1332impl<T, L, R, H, V, const HN: usize, const VN: usize> Style<T, On, L, R, H, V, HN, VN> {
1333    /// Removes bottom border.
1334    pub const fn remove_bottom(mut self) -> Style<T, (), L, R, H, V, HN, VN>
1335    where
1336        T: Copy,
1337        H: Copy,
1338    {
1339        self.borders.bottom = None;
1340        self.borders.bottom_intersection = None;
1341        self.borders.bottom_left = None;
1342        self.borders.bottom_right = None;
1343
1344        let verticals = varr_unset(self.verticals, VLine::new(None, None, None, Some(' ')));
1345
1346        Style::new(self.borders, self.horizontals, verticals)
1347    }
1348}
1349
1350impl<T, B, R, H, V, const HN: usize, const VN: usize> Style<T, B, On, R, H, V, HN, VN> {
1351    /// Removes left border.
1352    pub const fn remove_left(mut self) -> Style<T, B, (), R, H, V, HN, VN>
1353    where
1354        R: Copy,
1355        V: Copy,
1356    {
1357        self.borders.left = None;
1358        self.borders.left_intersection = None;
1359        self.borders.top_left = None;
1360        self.borders.bottom_left = None;
1361
1362        let horizontals = harr_unset(self.horizontals, HLine::new(None, None, Some(' '), None));
1363
1364        Style::new(self.borders, horizontals, self.verticals)
1365    }
1366}
1367
1368impl<T, B, L, H, V, const HN: usize, const VN: usize> Style<T, B, L, On, H, V, HN, VN> {
1369    /// Removes right border.
1370    pub const fn remove_right(mut self) -> Style<T, B, L, (), H, V, HN, VN>
1371    where
1372        L: Copy,
1373        V: Copy,
1374    {
1375        self.borders.right = None;
1376        self.borders.right_intersection = None;
1377        self.borders.top_right = None;
1378        self.borders.bottom_right = None;
1379
1380        let horizontals = harr_unset(self.horizontals, HLine::new(None, None, None, Some(' ')));
1381
1382        Style::new(self.borders, horizontals, self.verticals)
1383    }
1384}
1385
1386impl<T, B, L, R, V, const HN: usize, const VN: usize> Style<T, B, L, R, On, V, HN, VN> {
1387    /// Removes horizontal split lines.
1388    ///
1389    /// Not including custom split lines.
1390    pub const fn remove_horizontal(mut self) -> Style<T, B, L, R, (), V, HN, VN>
1391    where
1392        T: Copy,
1393        B: Copy,
1394        V: Copy,
1395    {
1396        self.borders.horizontal = None;
1397        self.borders.left_intersection = None;
1398        self.borders.right_intersection = None;
1399        self.borders.intersection = None;
1400
1401        // let lines = linearr_unset(lines, Line::new(None, Some(' '), None, None));
1402        let verticals = self.verticals;
1403
1404        Style::new(self.borders, self.horizontals, verticals)
1405    }
1406}
1407
1408impl<T, B, L, R, H, const HN: usize, const VN: usize> Style<T, B, L, R, H, On, HN, VN> {
1409    /// Removes vertical split lines.
1410    pub const fn remove_vertical(mut self) -> Style<T, B, L, R, H, (), HN, VN>
1411    where
1412        R: Copy,
1413        L: Copy,
1414    {
1415        self.borders.vertical = None;
1416        self.borders.top_intersection = None;
1417        self.borders.bottom_intersection = None;
1418        self.borders.intersection = None;
1419
1420        // let lines = linearr_unset(lines, Line::new(None, Some(' '), None, None));
1421        let horizontals = self.horizontals;
1422
1423        Style::new(self.borders, horizontals, self.verticals)
1424    }
1425}
1426
1427impl<H, V, const HN: usize, const VN: usize> Style<On, On, On, On, H, V, HN, VN> {
1428    /// Removes frame.
1429    pub const fn remove_frame(self) -> Style<(), (), (), (), H, V, HN, VN>
1430    where
1431        V: Copy,
1432        H: Copy,
1433    {
1434        self.remove_bottom()
1435            .remove_top()
1436            .remove_left()
1437            .remove_right()
1438    }
1439}
1440
1441#[cfg(feature = "std")]
1442impl<T, B, L, R, H, V, Data, Dims, const HSIZE: usize, const VSIZE: usize>
1443    TableOption<Data, ColoredConfig, Dims> for Style<T, B, L, R, H, V, HSIZE, VSIZE>
1444{
1445    fn change(self, _: &mut Data, cfg: &mut ColoredConfig, _: &mut Dims) {
1446        cfg_clear_borders(cfg);
1447        cfg_set_custom_lines(cfg, &self.horizontals, &self.verticals);
1448        cfg.set_borders(self.borders);
1449    }
1450
1451    fn hint_change(&self) -> Option<papergrid::config::Entity> {
1452        None
1453    }
1454}
1455
1456impl<T, B, L, R, H, V, Data, Dims, const HSIZE: usize, const VSIZE: usize>
1457    TableOption<Data, CompactConfig, Dims> for Style<T, B, L, R, H, V, HSIZE, VSIZE>
1458{
1459    fn change(self, _: &mut Data, cfg: &mut CompactConfig, _: &mut Dims) {
1460        *cfg = cfg.set_borders(self.borders);
1461    }
1462
1463    fn hint_change(&self) -> Option<papergrid::config::Entity> {
1464        None
1465    }
1466}
1467
1468impl<T, B, L, R, H, V, Data, Dims, const HSIZE: usize, const VSIZE: usize>
1469    TableOption<Data, CompactMultilineConfig, Dims> for Style<T, B, L, R, H, V, HSIZE, VSIZE>
1470{
1471    fn change(self, _: &mut Data, cfg: &mut CompactMultilineConfig, _: &mut Dims) {
1472        cfg.set_borders(self.borders);
1473    }
1474
1475    fn hint_change(&self) -> Option<papergrid::config::Entity> {
1476        None
1477    }
1478}
1479
1480impl<T, B, L, R, H, V, const HSIZE: usize, const VSIZE: usize>
1481    From<Style<T, B, L, R, H, V, HSIZE, VSIZE>> for Borders<char>
1482{
1483    fn from(value: Style<T, B, L, R, H, V, HSIZE, VSIZE>) -> Self {
1484        value.borders
1485    }
1486}
1487
1488const fn correct_border(mut border: GridBorder<char>) -> GridBorder<char> {
1489    if border.has_top() && border.top.is_none() {
1490        border.top = Some(' ');
1491    }
1492
1493    if border.has_bottom() && border.bottom.is_none() {
1494        border.bottom = Some(' ');
1495    }
1496
1497    if border.has_left() && border.left.is_none() {
1498        border.left = Some(' ');
1499    }
1500
1501    if border.has_right() && border.right.is_none() {
1502        border.right = Some(' ');
1503    }
1504
1505    if border.has_top() && border.has_left() && border.left_top_corner.is_none() {
1506        border.left_top_corner = Some(' ');
1507    }
1508
1509    if border.has_top() && border.has_right() && border.right_top_corner.is_none() {
1510        border.right_top_corner = Some(' ');
1511    }
1512
1513    if border.has_bottom() && border.has_left() && border.left_top_corner.is_none() {
1514        border.left_bottom_corner = Some(' ');
1515    }
1516
1517    if border.has_bottom() && border.has_right() && border.right_bottom_corner.is_none() {
1518        border.right_bottom_corner = Some(' ');
1519    }
1520
1521    border
1522}
1523
1524const fn varr_convert<T, B, I, const N: usize>(
1525    lines: [(usize, VerticalLine<T, B, I>); N],
1526) -> VArray<N> {
1527    let mut buf = [(0, VLine::empty()); N];
1528    let mut i = 0;
1529    while i < N {
1530        let (index, line) = &lines[i];
1531        let index = *index;
1532        let line = line.into_inner();
1533
1534        buf[i].0 = index;
1535        buf[i].1 = line;
1536
1537        i += 1;
1538    }
1539
1540    buf
1541}
1542
1543const fn harr_convert<L, R, I, const N: usize>(
1544    lines: [(usize, HorizontalLine<L, R, I>); N],
1545) -> HArray<N> {
1546    let mut buf = [(0, HLine::empty()); N];
1547    let mut i = 0;
1548    while i < N {
1549        let (index, line) = &lines[i];
1550        let index = *index;
1551        let line = line.into_inner();
1552
1553        buf[i].0 = index;
1554        buf[i].1 = line;
1555
1556        i += 1;
1557    }
1558
1559    buf
1560}
1561
1562const fn harr_set<const N: usize>(lines: HArray<N>, set: HLine) -> HArray<N> {
1563    let mut buf = [(0, HLine::empty()); N];
1564    let mut i = 0;
1565    while i < N {
1566        let (index, mut line) = lines[i];
1567
1568        if set.left.is_some() {
1569            line.left = set.left;
1570        }
1571
1572        if set.right.is_some() {
1573            line.right = set.right;
1574        }
1575
1576        if set.intersection.is_some() {
1577            line.intersection = set.intersection;
1578        }
1579
1580        if set.main.is_some() {
1581            line.main = set.main;
1582        }
1583
1584        buf[i].0 = index;
1585        buf[i].1 = line;
1586
1587        i += 1;
1588    }
1589
1590    buf
1591}
1592
1593const fn harr_unset<const N: usize>(lines: HArray<N>, set: HLine) -> HArray<N> {
1594    let mut buf = [(0, HLine::empty()); N];
1595    let mut i = 0;
1596    while i < N {
1597        let (index, mut line) = lines[i];
1598
1599        if set.left.is_some() {
1600            line.left = None;
1601        }
1602
1603        if set.right.is_some() {
1604            line.right = None;
1605        }
1606
1607        if set.intersection.is_some() {
1608            line.intersection = None;
1609        }
1610
1611        if set.main.is_some() {
1612            line.main = None;
1613        }
1614
1615        buf[i].0 = index;
1616        buf[i].1 = line;
1617
1618        i += 1;
1619    }
1620
1621    buf
1622}
1623
1624const fn varr_set<const N: usize>(lines: VArray<N>, set: VLine) -> VArray<N> {
1625    let mut buf = [(0, VLine::empty()); N];
1626    let mut i = 0;
1627    while i < N {
1628        let (index, mut line) = lines[i];
1629
1630        if set.top.is_some() {
1631            line.top = set.top;
1632        }
1633
1634        if set.bottom.is_some() {
1635            line.bottom = set.bottom;
1636        }
1637
1638        if set.intersection.is_some() {
1639            line.intersection = set.intersection;
1640        }
1641
1642        if set.main.is_some() {
1643            line.main = set.main;
1644        }
1645
1646        buf[i].0 = index;
1647        buf[i].1 = line;
1648
1649        i += 1;
1650    }
1651
1652    buf
1653}
1654
1655const fn varr_unset<const N: usize>(lines: VArray<N>, set: VLine) -> VArray<N> {
1656    let mut buf = [(0, VLine::empty()); N];
1657    let mut i = 0;
1658    while i < N {
1659        let (index, mut line) = lines[i];
1660
1661        if set.top.is_some() {
1662            line.top = None;
1663        }
1664
1665        if set.bottom.is_some() {
1666            line.bottom = None;
1667        }
1668
1669        if set.intersection.is_some() {
1670            line.intersection = None;
1671        }
1672
1673        if set.main.is_some() {
1674            line.main = None;
1675        }
1676
1677        buf[i].0 = index;
1678        buf[i].1 = line;
1679
1680        i += 1;
1681    }
1682
1683    buf
1684}
1685
1686const fn create_borders(
1687    top: HLine,
1688    bottom: HLine,
1689    horizontal: HLine,
1690    left: Option<char>,
1691    right: Option<char>,
1692    vertical: Option<char>,
1693) -> Borders<char> {
1694    Borders {
1695        top: top.main,
1696        top_left: top.left,
1697        top_right: top.right,
1698        top_intersection: top.intersection,
1699        bottom: bottom.main,
1700        bottom_left: bottom.left,
1701        bottom_right: bottom.right,
1702        bottom_intersection: bottom.intersection,
1703        left_intersection: horizontal.left,
1704        right_intersection: horizontal.right,
1705        horizontal: horizontal.main,
1706        intersection: horizontal.intersection,
1707        left,
1708        right,
1709        vertical,
1710    }
1711}
1712
1713#[cfg(feature = "std")]
1714fn cfg_set_custom_lines(
1715    cfg: &mut ColoredConfig,
1716    hlines: &[(usize, HLine)],
1717    vlines: &[(usize, VLine)],
1718) {
1719    for &(row, line) in hlines {
1720        cfg.insert_horizontal_line(row, line);
1721    }
1722
1723    for &(col, line) in vlines {
1724        cfg.insert_vertical_line(col, line);
1725    }
1726}
1727
1728#[cfg(feature = "std")]
1729fn cfg_clear_borders(cfg: &mut ColoredConfig) {
1730    cfg.remove_borders();
1731    cfg.remove_vertical_chars();
1732    cfg.remove_horizontal_chars();
1733    cfg.remove_borders_colors();
1734    cfg.remove_color_line_horizontal();
1735    cfg.remove_color_line_vertical();
1736}