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(main:Some(main), intersection:None, top:None, bottom: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 main:Some(main),
81 intersection:Some(intersection),
82 top:Some(top),
83 bottom:Some(bottom),
84 ))
85 }
86
87 /// Creates a new vertical split line.
88 pub const fn filled(main: char) -> Self {
89 Self::full(main, intersection:main, top:main, bottom: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: char) => 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: char) => 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 left:value.line.top,
197 right: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: VerticalLine = 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: char) => value,
213 None => unreachable!(),
214 }
215}
216