ferroui_base/media/
text_decoration_collection.rs1use crate::media::media_collection::media_collection_type;
2use crate::media::{MediaCollection, TextDecoration, TextDecorationLocation};
3use crate::utilities::{FormatError, SpanStringTokenizer};
4use crate::Ref;
5
6media_collection_type!(
7 TextDecorationCollection,
11 Ref<TextDecoration>
12);
13
14impl TextDecorationCollection {
15 pub fn new() -> Self {
17 Self(MediaCollection::new())
18 }
19
20 pub fn from_items(text_decorations: impl IntoIterator<Item = Ref<TextDecoration>>) -> Self {
22 Self(MediaCollection::from_items(text_decorations))
23 }
24
25 pub fn parse(s: &str) -> Result<TextDecorationCollection, FormatError> {
28 let mut locations = Vec::new();
29
30 SpanStringTokenizer::with_message(s, "Invalid text decoration.").scope(|tokenizer| {
31 while let Some(name) = tokenizer.try_read_span()? {
32 let location = Self::get_text_decoration_location(name)?;
33
34 if locations.contains(&location) {
35 return Err(FormatError::new("Text decoration already specified."));
36 }
37
38 locations.push(location);
39 }
40 Ok(())
41 })?;
42
43 let text_decorations = TextDecorationCollection::new();
44
45 for text_decoration_location in locations {
46 let text_decoration = TextDecoration::new();
47 text_decoration.set_location(text_decoration_location);
48 text_decorations.add(text_decoration);
49 }
50
51 Ok(text_decorations)
52 }
53
54 fn get_text_decoration_location(s: &str) -> Result<TextDecorationLocation, FormatError> {
56 const NAMES: [(&str, TextDecorationLocation); 4] = [
57 ("Underline", TextDecorationLocation::Underline),
58 ("Overline", TextDecorationLocation::Overline),
59 ("Strikethrough", TextDecorationLocation::Strikethrough),
60 ("Baseline", TextDecorationLocation::Baseline),
61 ];
62
63 NAMES
64 .iter()
65 .find(|(name, _)| name.eq_ignore_ascii_case(s))
66 .map(|(_, location)| *location)
67 .ok_or(FormatError::new("Could not parse text decoration."))
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn should_parse_text_decorations() {
77 let baseline = TextDecorationCollection::parse("baseline").unwrap();
78 assert_eq!(TextDecorationLocation::Baseline, baseline.get(0).location());
79
80 let underline = TextDecorationCollection::parse("underline").unwrap();
81 assert_eq!(TextDecorationLocation::Underline, underline.get(0).location());
82
83 let overline = TextDecorationCollection::parse("overline").unwrap();
84 assert_eq!(TextDecorationLocation::Overline, overline.get(0).location());
85
86 let strikethrough = TextDecorationCollection::parse("strikethrough").unwrap();
87 assert_eq!(TextDecorationLocation::Strikethrough, strikethrough.get(0).location());
88 }
89
90 #[test]
91 fn should_reject_duplicates_and_unknown_names() {
92 assert!(TextDecorationCollection::parse("underline, underline").is_err());
93 assert!(TextDecorationCollection::parse("wavy").is_err());
94 assert_eq!(TextDecorationCollection::parse("Underline, Strikethrough").unwrap().len(), 2);
95 }
96}