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(main:Some(main), intersection:None, left:None, right: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: HorizontalLine = Line::new(main:Some(main), intersection:Some(intersection), left:Some(left), right: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, intersection:main, left:main, right: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<I, (), 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: HorizontalLine = 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 top:value.line.left,
195 bottom:value.line.right,
196 )
197 }
198}
199
200const fn opt_get(opt: Option<char>) -> char {
201 match opt {
202 Some(value: char) => value,
203 None => unreachable!(),
204 }
205}
206