1 | use core::marker::PhantomData; |
2 | |
3 | use crate::grid::config::HorizontalLine; |
4 | use crate::grid::config::VerticalLine as Line; |
5 | use crate::settings::style::On; |
6 | use 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)] |
10 | pub struct VerticalLine<T, B, I> { |
11 | line: Line<char>, |
12 | _top: PhantomData<T>, |
13 | _bottom: PhantomData<B>, |
14 | _intersection: PhantomData<I>, |
15 | } |
16 | |
17 | impl 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 | |
24 | impl<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 | |
76 | impl 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 | |
93 | impl<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 | |
119 | impl<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 | |
143 | impl<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 | |
159 | impl<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 | |
172 | impl<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 | |
185 | impl<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 | |
191 | impl<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 | |
202 | impl<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 | |
210 | const fn opt_get(opt: Option<char>) -> char { |
211 | match opt { |
212 | Some(value: char) => value, |
213 | None => unreachable!(), |
214 | } |
215 | } |
216 | |