stylish_stringlike/text/
tag.rs1use crate::text::Paintable;
2use std::borrow::Borrow;
3
4#[derive(Clone, Debug, Default, PartialEq)]
6pub struct Tag {
7 opening: String,
8 closing: String,
9}
10
11impl Tag {
12 pub fn new(opening: &str, closing: &str) -> Self {
13 Self {
14 opening: opening.to_string(),
15 closing: closing.to_string(),
16 }
17 }
18}
19
20impl Paintable for Tag {
21 fn paint(&self, target: &str) -> String {
22 [self.opening.as_str(), target, self.closing.as_str()]
23 .iter()
24 .copied()
25 .collect()
26 }
27 fn paint_many<'a, T, U, V>(groups: T) -> String
28 where
29 T: IntoIterator<Item = (U, V)> + 'a,
30 U: Borrow<Self> + 'a,
31 V: Borrow<str> + 'a,
32 {
33 let mut result = String::new();
34 let mut previous_span = String::new();
35 let mut previous_tag: Option<Self> = None;
36 for (painter, s) in groups {
37 match previous_tag {
38 Some(ref p) if painter.borrow() != p => {
39 result += &p.paint(&previous_span);
40 previous_span = String::from(s.borrow());
41 previous_tag = Some(painter.borrow().clone());
42 }
43 Some(ref _p) => {
44 previous_span.push_str(s.borrow());
45 }
46 None => {
47 previous_span.push_str(s.borrow());
48 previous_tag = Some(painter.borrow().clone());
49 }
50 }
51 }
52 if let Some(p) = previous_tag {
53 if !previous_span.is_empty() {
54 result += &p.paint(&previous_span);
55 }
56 }
57 result
58 }
59}
60
61#[cfg(test)]
62mod test {
63 use super::*;
64 #[test]
65 fn tag_text() {
66 let fmt_1 = Tag::new("<1>", "</1>");
67 let fmt_2 = Tag::new("<2>", "</2>");
68 let texts = vec![(&fmt_1, "foo"), (&fmt_2, "bar"), (&fmt_2, "baz")];
69 assert_eq!(
70 Tag::paint_many(texts),
71 String::from("<1>foo</1><2>barbaz</2>")
72 );
73 }
74 #[test]
75 fn tag_empty() {
76 let texts: Vec<(&Tag, &str)> = vec![];
77 assert_eq!(Tag::paint_many(texts), String::new());
78 }
79}