svgbob/buffer/cell_buffer/
contacts.rs

1use super::{endorse, endorse::Endorse};
2use crate::{
3    buffer::{fragment::Fragment, fragment_buffer::FragmentSpan, Cell, Span},
4    Merge,
5};
6use std::fmt;
7
8/// Contains a group of fragments that are touching each other
9/// The purpose of Contacts is to group fragments together
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Contacts(pub Vec<FragmentSpan>);
12
13impl AsRef<Vec<FragmentSpan>> for Contacts {
14    fn as_ref(&self) -> &Vec<FragmentSpan> {
15        &self.0
16    }
17}
18
19impl AsMut<Vec<FragmentSpan>> for Contacts {
20    fn as_mut(&mut self) -> &mut Vec<FragmentSpan> {
21        &mut self.0
22    }
23}
24
25impl Contacts {
26    pub(crate) fn new(fragment: FragmentSpan) -> Self {
27        Contacts(vec![fragment])
28    }
29
30    pub fn fragments(&self) -> Vec<&Fragment> {
31        self.0.iter().map(|fs| &fs.fragment).collect()
32    }
33
34    pub fn cells(&self) -> Vec<Cell> {
35        self.0.iter().flat_map(|fs| fs.cells()).collect()
36    }
37
38    pub fn span(&self) -> Span {
39        let cell_chars: Vec<(Cell, char)> =
40            self.0.iter().flat_map(|fs| fs.span.0.clone()).collect();
41        cell_chars.into()
42    }
43
44    /// Check if any fragment can be group with any of the other fragment
45    /// We use `.rev()` on this list of fragment since it has a high change of matching at the last
46    /// added fragment of the next fragments to be checked.
47    pub(crate) fn is_contacting_frag(&self, other_frag: &FragmentSpan) -> bool {
48        self.as_ref()
49            .iter()
50            .rev()
51            .any(|frag| frag.is_contacting(other_frag))
52    }
53
54    pub(crate) fn is_contacting(&self, other: &Self) -> bool {
55        other
56            .as_ref()
57            .iter()
58            .any(|other_frag| self.is_contacting_frag(other_frag))
59    }
60
61    ///TODO: return the FragmentSpan
62    /// Endorse if the fragments in this group
63    /// can be:
64    ///  - rect
65    ///  - rounded_rect
66    pub(crate) fn endorse_rect(&self) -> Option<Fragment> {
67        let fragments = self.fragments();
68        if let Some(rect) = endorse::endorse_rect(&fragments) {
69            Some(rect.into())
70        } else {
71            endorse::endorse_rounded_rect(&fragments)
72                .map(|rounded_rect| rounded_rect.into())
73        }
74    }
75
76    /// First phase of endorsing to shapes, in this case, rects and rounded_rects
77    ///
78    /// This function is calling on endorse methods that is applicable
79    /// to fragments that are touching, to be promoted to a shape.
80    /// These includes: rect, roundedrect,
81    pub(crate) fn endorse_rects(
82        contacts: Vec<Contacts>,
83    ) -> Endorse<FragmentSpan, Contacts> {
84        let mut accepted = vec![];
85        let mut rejects: Vec<Contacts> = vec![];
86        for contact in contacts {
87            if let Some(fragment) = contact.endorse_rect() {
88                let span = contact.span();
89                let fragment_span = FragmentSpan::new(span, fragment);
90                accepted.push(fragment_span);
91            } else {
92                rejects.push(contact);
93            }
94        }
95        Endorse { accepted, rejects }
96    }
97
98    pub(crate) fn absolute_position(&self, cell: Cell) -> Self {
99        Contacts(
100            self.as_ref()
101                .iter()
102                .map(|frag| frag.absolute_position(cell))
103                .collect(),
104        )
105    }
106
107    pub fn is_bounded(&self, bound1: Cell, bound2: Cell) -> bool {
108        self.cells()
109            .iter()
110            .all(|cell| cell.is_bounded(bound1, bound2))
111    }
112
113    pub fn hit_cell(&self, needle: Cell) -> bool {
114        self.cells().iter().any(|cell| *cell == needle)
115    }
116}
117
118impl Merge for Contacts {
119    fn merge(&self, other: &Self) -> Option<Self> {
120        if self.is_contacting(&other) {
121            let mut fragment_spans: Vec<FragmentSpan> = self.0.clone();
122            fragment_spans.extend_from_slice(&other.0);
123            Some(Contacts(fragment_spans))
124        } else {
125            None
126        }
127    }
128}
129
130impl fmt::Display for Contacts {
131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132        for frag in self.as_ref().iter() {
133            writeln!(f, "\t{}", frag)?;
134        }
135        Ok(())
136    }
137}