1use std::borrow::Cow;
2use std::iter::FusedIterator;
3use std::slice;
4
5use super::action::Action;
6use super::element::Element;
7use super::item::ElementItem;
8use crate::arguments::Arguments;
9use crate::element::AttributeList;
10use crate::entity::DecodedEntity;
11use crate::parse::Decoder;
12
13#[derive(Copy, Clone, Debug)]
16pub struct ElementDecoder<'a, D: Decoder> {
17 decoder: D,
18 attributes: &'a AttributeList,
19 args: &'a Arguments<'a>,
20}
21
22impl<'a, D: Decoder> ElementDecoder<'a, D> {
23 pub(super) fn new(decoder: D, attributes: &'a AttributeList, args: &'a Arguments<'a>) -> Self {
24 Self {
25 decoder,
26 attributes,
27 args,
28 }
29 }
30}
31
32impl<'a, D: Decoder> ElementDecoder<'a, D> {
33 fn find(&self, name: &str) -> Option<&'a str> {
34 self.attributes.find(name, self.args)
35 }
36}
37
38impl<D: Decoder> Decoder for ElementDecoder<'_, D> {
39 fn get_entity(&self, name: &str) -> Option<&str> {
40 self.find(name).or_else(|| self.decoder.get_entity(name))
41 }
42
43 fn decode_entity(&self, name: &str) -> crate::Result<DecodedEntity<'_>> {
44 match self.find(name) {
45 Some(attr) => Ok(self.decoder.decode_string(attr)?.into()),
46 None => self.decoder.decode_entity(name),
47 }
48 }
49}
50
51#[must_use = "iterators are lazy and do nothing unless consumed"]
54#[derive(Clone)]
55pub struct ElementDecodeIter<'a, D: Decoder + Copy> {
56 decoder: ElementDecoder<'a, D>,
57 items: slice::Iter<'a, ElementItem>,
58}
59
60impl<'a, D: Decoder + Copy> ElementDecodeIter<'a, D> {
61 pub(super) fn new(element: &'a Element, args: &'a Arguments<&'a str>, decoder: D) -> Self {
62 Self {
63 decoder: ElementDecoder {
64 decoder,
65 attributes: &element.attributes,
66 args,
67 },
68 items: element.items.iter(),
69 }
70 }
71}
72
73impl<'a, D: Decoder + Copy> Iterator for ElementDecodeIter<'a, D> {
74 type Item = crate::Result<Action<Cow<'a, str>>>;
75
76 fn next(&mut self) -> Option<Self::Item> {
77 Some(self.items.next()?.decode(self.decoder))
78 }
79
80 fn size_hint(&self) -> (usize, Option<usize>) {
81 let exact = self.len();
82 (exact, Some(exact))
83 }
84}
85
86impl<D> ExactSizeIterator for ElementDecodeIter<'_, D>
87where
88 D: Decoder + Copy,
89{
90 fn len(&self) -> usize {
91 self.items.len()
92 }
93}
94
95impl<D> FusedIterator for ElementDecodeIter<'_, D> where D: Decoder + Copy {}
96
97#[cfg(test)]
98mod tests {
99 use crate::color::RgbColor;
100 use crate::element::Action;
101 use crate::elements::Color;
102 use crate::test_utils::{decode_actions, try_from_node};
103
104 fn color(name: &str) -> RgbColor {
105 RgbColor::named(name).unwrap()
106 }
107
108 fn foreground(name: &str) -> Color {
109 Color {
110 fore: Some(color(name)),
111 ..Default::default()
112 }
113 }
114
115 #[test]
116 fn custom_args() {
117 let mut state = crate::State::default();
118 let definition = try_from_node("<!ELEMENT mycolor '<COLOR &col;>' ATT='col=red'>");
119 state.define(definition).unwrap();
120 let red = decode_actions("<mycolor>", &state).unwrap();
121 assert_eq!(red, &[Action::Color(foreground("red"))]);
122 let blue = decode_actions("<mycolor col=blue>", &state).unwrap();
123 assert_eq!(blue, &[Action::Color(foreground("blue"))]);
124 let reset = decode_actions("<mycolor col=\"\">", &state).unwrap();
125 assert_eq!(reset, &[Action::Color(Color::default())]);
126
127 let definition = try_from_node("<!ELEMENT mycolors '<COLOR &col; &bg;>' ATT='bg col=red'>");
128 state.define(definition).unwrap();
129 let positional = decode_actions("<mycolors col=blue green>", &state).unwrap();
130 assert_eq!(
131 positional,
132 &[Action::Color(Color {
133 fore: Some(color("blue")),
134 back: Some(color("green")),
135 })]
136 );
137 }
138}