tabled/settings/style/
vertical_line.rs

1use core::marker::PhantomData;
2
3use crate::grid::config::HorizontalLine;
4use crate::grid::config::VerticalLine as Line;
5use crate::settings::style::On;
6use crate::settings::Style;
7
8/// A vertical split line which can be used to set a border.
9#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
10pub struct VerticalLine<T, B, I> {
11    line: Line<char>,
12    _top: PhantomData<T>,
13    _bottom: PhantomData<B>,
14    _intersection: PhantomData<I>,
15}
16
17impl VerticalLine<(), (), ()> {
18    /// Creates a new vertical split line.
19    pub const fn new(main: char) -> Self {
20        Self::update(Line::new(Some(main), None, None, None))
21    }
22}
23
24impl<T, B, I> VerticalLine<T, B, I> {
25    /// Creates a stub horizontal line.
26    pub const fn empty() -> Self {
27        Self::update(Line::empty())
28    }
29
30    /// Fetches vertical line from a style.
31    pub const fn inherit<L, R, const HSIZE: usize, const VSIZE: usize>(
32        style: Style<T, B, L, R, I, On, HSIZE, VSIZE>,
33    ) -> Self {
34        let borders = style.get_borders();
35        let line = Line::new(
36            borders.vertical,
37            borders.intersection,
38            borders.top_intersection,
39            borders.bottom_intersection,
40        );
41
42        Self::update(line)
43    }
44
45    /// Fetches left vertical line from a style.
46    pub const fn inherit_left<R, V, const HSIZE: usize, const VSIZE: usize>(
47        style: Style<T, B, On, R, I, V, HSIZE, VSIZE>,
48    ) -> Self {
49        let borders = style.get_borders();
50        let line = Line::new(
51            borders.left,
52            borders.left_intersection,
53            borders.top_left,
54            borders.bottom_left,
55        );
56
57        Self::update(line)
58    }
59
60    /// Fetches right vertical line from a style.
61    pub const fn inherit_right<L, V, const HSIZE: usize, const VSIZE: usize>(
62        style: Style<T, B, L, On, I, V, HSIZE, VSIZE>,
63    ) -> Self {
64        let borders = style.get_borders();
65        let line = Line::new(
66            borders.right,
67            borders.right_intersection,
68            borders.top_right,
69            borders.bottom_right,
70        );
71
72        Self::update(line)
73    }
74}
75
76impl VerticalLine<On, On, On> {
77    /// Creates a new vertical split line.
78    pub const fn full(main: char, intersection: char, top: char, bottom: char) -> Self {
79        Self::update(Line::new(
80            Some(main),
81            Some(intersection),
82            Some(top),
83            Some(bottom),
84        ))
85    }
86
87    /// Creates a new vertical split line.
88    pub const fn filled(main: char) -> Self {
89        Self::full(main, main, main, main)
90    }
91}
92
93impl<T, B, I> VerticalLine<T, B, I> {
94    /// Set a vertical character.
95    pub const fn vertical(mut self, c: char) -> VerticalLine<T, B, I> {
96        self.line.main = Some(c);
97        VerticalLine::update(self.line)
98    }
99
100    /// Set a vertical intersection character.
101    pub const fn intersection(mut self, c: char) -> VerticalLine<T, B, On> {
102        self.line.intersection = Some(c);
103        VerticalLine::update(self.line)
104    }
105
106    /// Set a top character.
107    pub const fn top(mut self, c: char) -> VerticalLine<On, B, I> {
108        self.line.top = Some(c);
109        VerticalLine::update(self.line)
110    }
111
112    /// Set a bottom character.
113    pub const fn bottom(mut self, c: char) -> VerticalLine<T, On, I> {
114        self.line.bottom = Some(c);
115        VerticalLine::update(self.line)
116    }
117}
118
119impl<T, B, I> VerticalLine<T, B, I> {
120    pub(crate) const fn update(line: Line<char>) -> VerticalLine<T, B, I> {
121        Self {
122            line,
123            _top: PhantomData,
124            _bottom: PhantomData,
125            _intersection: PhantomData,
126        }
127    }
128
129    /// Get a vertical character.
130    pub const fn get_vertical(&self) -> char {
131        match self.line.main {
132            Some(c) => c,
133            None => unreachable!(),
134        }
135    }
136
137    /// Get a general structure of line.
138    pub const fn into_inner(&self) -> Line<char> {
139        self.line
140    }
141}
142
143impl<T, B> VerticalLine<T, B, On> {
144    /// Set a horizontal intersection character.
145    pub const fn get_intersection(&self) -> char {
146        match self.line.intersection {
147            Some(c) => c,
148            None => unreachable!(),
149        }
150    }
151
152    /// Remove a horizontal intersection character.
153    pub const fn remove_intersection(mut self) -> VerticalLine<T, B, ()> {
154        self.line.intersection = None;
155        VerticalLine::update(self.line)
156    }
157}
158
159impl<B, I> VerticalLine<On, B, I> {
160    /// Get a top character.
161    pub const fn get_top(&self) -> char {
162        opt_get(self.line.top)
163    }
164
165    /// Remove a vertical top character.
166    pub const fn remove_top(mut self) -> VerticalLine<(), B, I> {
167        self.line.top = None;
168        VerticalLine::update(self.line)
169    }
170}
171
172impl<T, I> VerticalLine<T, On, I> {
173    /// Get a bottom character.
174    pub const fn get_bottom(&self) -> char {
175        opt_get(self.line.bottom)
176    }
177
178    /// Remove a vertical bottom character.
179    pub const fn remove_bottom(mut self) -> VerticalLine<T, (), I> {
180        self.line.bottom = None;
181        VerticalLine::update(self.line)
182    }
183}
184
185impl<T, B, I> From<VerticalLine<T, B, I>> for Line<char> {
186    fn from(value: VerticalLine<T, B, I>) -> Self {
187        value.line
188    }
189}
190
191impl<T, B, I> From<VerticalLine<T, B, I>> for HorizontalLine<char> {
192    fn from(value: VerticalLine<T, B, I>) -> Self {
193        HorizontalLine::new(
194            value.line.main,
195            value.line.intersection,
196            value.line.top,
197            value.line.bottom,
198        )
199    }
200}
201
202impl<T, B, I> From<Line<char>> for VerticalLine<T, B, I> {
203    fn from(value: Line<char>) -> Self {
204        let mut line = Self::empty();
205        line.line = value;
206        line
207    }
208}
209
210const fn opt_get(opt: Option<char>) -> char {
211    match opt {
212        Some(value) => value,
213        None => unreachable!(),
214    }
215}