tabled/settings/style/
horizontal_line.rs

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