svgbob/buffer/cell_buffer/
span.rs1use crate::{
2 buffer::{
3 cell_buffer::{Contacts, Endorse},
4 fragment_buffer::FragmentSpan,
5 FragmentBuffer, Property, PropertyBuffer, StringBuffer,
6 },
7 fragment,
8 fragment::Circle,
9 map::{circle_map, UNICODE_FRAGMENTS},
10 Cell, Fragment, Merge, Point, Settings,
11};
12use itertools::Itertools;
13use std::{
14 fmt,
15 ops::{Deref, DerefMut},
16};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Span(pub Vec<(Cell, char)>);
22
23impl Deref for Span {
24 type Target = Vec<(Cell, char)>;
25
26 fn deref(&self) -> &Self::Target {
27 &self.0
28 }
29}
30
31pub struct Bounds {
32 top_left: Cell,
33 bottom_right: Cell,
34}
35
36impl DerefMut for Span {
37 fn deref_mut(&mut self) -> &mut Self::Target {
38 &mut self.0
39 }
40}
41
42impl From<Vec<(Cell, char)>> for Span {
43 fn from(cell_chars: Vec<(Cell, char)>) -> Self {
44 Span(cell_chars)
45 }
46}
47
48impl Span {
49 pub(crate) fn new(cell: Cell, ch: char) -> Self {
50 Span(vec![(cell, ch)])
51 }
52
53 pub(super) fn is_adjacent(&self, cell: &Cell) -> bool {
54 self.iter()
55 .rev()
56 .any(|(ex_cell, _)| ex_cell.is_adjacent(cell))
57 }
58
59 pub(super) fn can_merge(&self, other: &Self) -> bool {
63 self.iter().rev().any(|(cell, _)| {
64 other
65 .iter()
66 .any(|(other_cell, _)| cell.is_adjacent(other_cell))
67 })
68 }
69
70 pub fn paste_at(&self, loc: Cell, other: &Self) -> Self {
72 let mut this = self.clone();
73 for (cell, ch) in other.deref() {
74 this.push((*cell + loc, *ch));
75 }
76 this.sort();
77 this.dedup();
78 this
79 }
80
81 fn top_left(&self) -> Cell {
82 let bounds = self.bounds().expect("must have bounds");
83 bounds.0
84 }
85
86 pub fn localize_point(&self, point: Point) -> Point {
87 self.top_left().localize_point(point)
88 }
89
90 pub(crate) fn bounds(&self) -> Option<(Cell, Cell)> {
92 if let Some((min_y, max_y)) =
93 self.iter().map(|(cell, _)| cell.y).minmax().into_option()
94 {
95 if let Some((min_x, max_x)) =
96 self.iter().map(|(cell, _)| cell.x).minmax().into_option()
97 {
98 Some((Cell::new(min_x, min_y), Cell::new(max_x, max_y)))
99 } else {
100 None
101 }
102 } else {
103 None
104 }
105 }
106
107 pub fn cell_bounds(&self) -> Option<Bounds> {
108 if let Some((top_left, top_right)) = self.bounds() {
109 Some(Bounds::new(top_left, top_right))
110 } else {
111 None
112 }
113 }
114
115 pub(crate) fn localize(self) -> Self {
117 if let Some((tl, _br)) = self.bounds() {
118 let mut new_self = Span(vec![]);
119 for (cell, ch) in self.iter() {
120 let local_cell = tl.localize_cell(*cell);
121 new_self.push((local_cell, *ch));
122 }
123 new_self
124 } else {
125 self
126 }
127 }
128
129 pub(crate) fn endorse(self) -> Endorse<FragmentSpan, Span> {
135 let (mut accepted, un_endorsed_span): (Vec<FragmentSpan>, Span) =
137 self.endorse_to_arcs_and_circles();
138
139 let un_endorsed_contacts: Vec<Contacts> = un_endorsed_span.into();
141 let rect_endorsed: Endorse<FragmentSpan, Contacts> =
142 Contacts::endorse_rects(un_endorsed_contacts);
143
144 accepted.extend(rect_endorsed.accepted);
145
146 let re_endorsed = Self::re_endorse(rect_endorsed.rejects);
147
148 let mut endorsed = Endorse {
149 accepted,
150 rejects: vec![],
151 };
152 endorsed.extend(re_endorsed);
153 endorsed
154 }
155
156 fn re_endorse(rect_rejects: Vec<Contacts>) -> Endorse<FragmentSpan, Span> {
158 let span_rejects: Vec<Span> = rect_rejects
160 .into_iter()
161 .map(|contact| contact.span())
162 .collect();
163
164 let span_rejects: Vec<Span> = Span::merge_recursive(span_rejects);
165
166 let (accepted, rejects): (Vec<Vec<FragmentSpan>>, Vec<Span>) =
168 span_rejects
169 .into_iter()
170 .map(|span| span.endorse_to_arcs_and_circles())
171 .unzip();
172
173 Endorse {
174 accepted: accepted.into_iter().flatten().collect(),
175 rejects,
176 }
177 }
178
179 fn endorse_to_arcs_and_circles(self) -> (Vec<FragmentSpan>, Span) {
181 let mut accepted = vec![];
182 let (top_left, _) = self.bounds().expect("must have bounds");
183 let un_endorsed_span: Span = if let Some((circle, un_endorsed_span)) =
184 circle_map::endorse_circle_span(&self)
185 {
186 let circle = circle.absolute_position(top_left);
187 let circle_frag_span =
188 FragmentSpan::new(self.clone(), circle.into());
189 accepted.push(circle_frag_span);
190 un_endorsed_span
191 } else if let Some((three_quarters_arc, un_endorsed_span)) =
192 circle_map::endorse_three_quarters_arc_span(&self)
193 {
194 let three_quarters_arc =
195 three_quarters_arc.absolute_position(top_left);
196 let three_quarters_arc_frag_span =
197 FragmentSpan::new(self.clone(), three_quarters_arc.into());
198 accepted.push(three_quarters_arc_frag_span);
199 un_endorsed_span
200 } else if let Some((half_arc, un_endorsed_span)) =
201 circle_map::endorse_half_arc_span(&self)
202 {
203 let half_arc = half_arc.absolute_position(top_left);
204 let half_arc_frag_span =
205 FragmentSpan::new(self.clone(), half_arc.into());
206 accepted.push(half_arc_frag_span);
207 un_endorsed_span
208 } else if let Some((arc, un_endorsed_span)) =
209 circle_map::endorse_quarter_arc_span(&self)
210 {
211 let arc = arc.absolute_position(top_left);
212 let arc_frag_span = FragmentSpan::new(self.clone(), arc.into());
213 accepted.push(arc_frag_span);
214 un_endorsed_span
215 } else {
216 self
217 };
218 (accepted, un_endorsed_span)
219 }
220
221 pub(crate) fn extract(&self, bound1: Cell, bound2: Cell) -> Self {
223 Span(
224 self.iter()
225 .map(|(cell, ch)| (*cell, *ch))
226 .filter(|(cell, _ch)| cell.is_bounded(bound1, bound2))
227 .collect(),
228 )
229 }
230
231 pub fn is_bounded(&self, bound1: Cell, bound2: Cell) -> bool {
234 self.iter()
235 .all(|(cell, ch)| cell.is_bounded(bound1, bound2))
236 }
237
238 pub fn hit_cell(&self, needle: Cell) -> bool {
239 self.iter().any(|(cell, ch)| *cell == needle)
240 }
241
242 pub fn merge_no_check(&self, other: &Self) -> Self {
244 let mut cells = self.0.clone();
245 cells.extend(&other.0);
246 Span(cells)
247 }
248}
249
250impl Merge for Span {
251 fn merge(&self, other: &Self) -> Option<Self> {
252 if self.can_merge(other) {
253 Some(self.merge_no_check(other))
254 } else {
255 None
256 }
257 }
258}
259
260impl Bounds {
261 pub fn new(cell1: Cell, cell2: Cell) -> Self {
262 let (top_left, bottom_right) = Cell::rearrange_bound(cell1, cell2);
263 Self {
264 top_left,
265 bottom_right,
266 }
267 }
268
269 pub fn top_left(&self) -> Cell {
270 self.top_left
271 }
272
273 pub fn bottom_right(&self) -> Cell {
274 self.bottom_right
275 }
276
277 pub fn top_right(&self) -> Cell {
278 Cell::new(self.bottom_right.x, self.top_left.y)
279 }
280
281 pub fn bottom_left(&self) -> Cell {
282 Cell::new(self.top_left.x, self.bottom_right.y)
283 }
284}
285
286impl<'p> From<Span> for PropertyBuffer<'p> {
288 fn from(span: Span) -> Self {
289 let mut pb = PropertyBuffer::new();
290 for (cell, ch) in span.iter() {
291 if let Some(property) = Property::from_char(*ch) {
292 pb.as_mut().insert(*cell, property);
293 }
294 }
295 pb
296 }
297}
298
299impl From<Span> for Vec<Contacts> {
309 fn from(span: Span) -> Vec<Contacts> {
310 let fb = FragmentBuffer::from(span);
311 let merged_fragments: Vec<FragmentSpan> = fb.merge_fragment_spans();
312 let contacts: Vec<Contacts> = merged_fragments
313 .into_iter()
314 .map(|frag| Contacts::new(frag))
315 .collect();
316 Contacts::merge_recursive(contacts)
317 }
318}
319
320impl From<Span> for FragmentBuffer {
326 fn from(span: Span) -> FragmentBuffer {
327 let pb = PropertyBuffer::from(span.clone());
328 let mut fb = FragmentBuffer::from(pb.clone());
329 for (cell, ch) in span.iter() {
330 if pb.as_ref().get(cell).is_none() {
331 if let Some(fragments) = UNICODE_FRAGMENTS.get(ch) {
332 fb.add_fragments_to_cell(*cell, *ch, fragments.clone());
333 } else {
334 fb.add_fragment_to_cell(
335 *cell,
336 *ch,
337 fragment::cell_text(*ch),
338 );
339 }
340 }
341 }
342 fb
343 }
344}
345
346impl fmt::Display for Span {
347 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348 let mut buffer = StringBuffer::new();
349 if let Some((tl, _br)) = self.bounds() {
350 for (cell, ch) in self.iter() {
351 if *ch != '\0' && !ch.is_whitespace() {
352 let local = tl.localize_cell(*cell);
353 buffer.add_char(local.x, local.y, *ch);
354 }
355 }
356 }
357 write!(f, "{}", buffer.to_string())
358 }
359}
360
361#[cfg(test)]
362mod test_span;