1use crate::parser::{Parser, ParserError};
2use crate::reader::XmlReader;
3use crate::shared::Image;
4use crate::util::get_attr_id;
5use log::debug;
6use quick_xml::events::Event;
7use std::fmt;
8use std::mem::take;
9
10#[derive(Clone, Debug, Default)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Label {
13 pub id: u32,
14 pub name: String,
15 pub contactinfo: Option<String>,
16 pub profile: Option<String>,
17 pub parent_label: Option<LabelInfo>,
18 pub sublabels: Vec<LabelInfo>,
19 pub urls: Vec<String>,
20 pub data_quality: String,
21 pub images: Vec<Image>,
22}
23
24#[derive(Clone, Debug, Default)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct LabelInfo {
27 pub id: u32,
28 pub name: String,
29}
30
31impl fmt::Display for Label {
32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 write!(f, "{}", self.name)
34 }
35}
36
37pub struct LabelsReader {
38 buf: Vec<u8>,
39 reader: XmlReader,
40 parser: LabelParser,
41}
42
43impl LabelsReader {
44 pub fn new(reader: XmlReader, buf: Vec<u8>) -> Self {
45 Self {
46 buf,
47 reader,
48 parser: LabelParser::new(),
49 }
50 }
51}
52
53impl Iterator for LabelsReader {
54 type Item = Label;
55 fn next(&mut self) -> Option<Self::Item> {
56 loop {
57 match self.reader.read_event_into(&mut self.buf).unwrap() {
58 Event::Eof => {
59 return None;
60 }
61 ev => self.parser.process(ev).unwrap(),
62 };
63 if self.parser.item_ready {
64 return Some(self.parser.take());
65 }
66 self.buf.clear();
67 }
68 }
69}
70
71#[derive(Debug, Default)]
72enum ParserState {
73 #[default]
74 Label,
75 Name,
76 Id,
77 Images,
78 Contactinfo,
79 Profile,
80 ParentLabel,
81 Sublabels,
82 Sublabel,
83 Urls,
84 DataQuality,
85}
86
87#[derive(Debug, Default)]
88pub struct LabelParser {
89 state: ParserState,
90 current_item: Label,
91 current_sublabel_id: Option<u32>,
92 current_parent_id: Option<u32>,
93 item_ready: bool,
94}
95
96impl Parser for LabelParser {
97 type Item = Label;
98 fn new() -> Self {
99 Self::default()
100 }
101 fn take(&mut self) -> Self::Item {
102 self.item_ready = false;
103 take(&mut self.current_item)
104 }
105
106 fn process(&mut self, ev: Event) -> Result<(), ParserError> {
107 self.state = match self.state {
108 ParserState::Label => match ev {
109 Event::Start(e) if e.local_name().as_ref() == b"label" => ParserState::Label,
110
111 Event::Start(e) => match e.local_name().as_ref() {
112 b"name" => ParserState::Name,
113 b"id" => ParserState::Id,
114 b"contactinfo" => ParserState::Contactinfo,
115 b"profile" => ParserState::Profile,
116 b"parentLabel" => {
117 self.current_parent_id = Some(get_attr_id(e));
118 ParserState::ParentLabel
119 }
120 b"sublabels" => ParserState::Sublabels,
121 b"urls" => ParserState::Urls,
122 b"images" => ParserState::Images,
123 b"data_quality" => ParserState::DataQuality,
124 _ => ParserState::Label,
125 },
126 Event::End(e) if e.local_name().as_ref() == b"label" => {
127 self.item_ready = true;
128 ParserState::Label
129 }
130
131 _ => ParserState::Label,
132 },
133
134 ParserState::Id => match ev {
135 Event::Text(e) => {
136 self.current_item.id = e.unescape()?.parse()?;
137 debug!("Began parsing Label {}", self.current_item.id);
138 ParserState::Id
139 }
140 _ => ParserState::Label,
141 },
142
143 ParserState::Name => match ev {
144 Event::Text(e) => {
145 self.current_item.name = e.unescape()?.to_string();
146 ParserState::Name
147 }
148 _ => ParserState::Label,
149 },
150
151 ParserState::Images => match ev {
152 Event::Empty(e) if e.local_name().as_ref() == b"image" => {
153 let image = Image::from_event(e);
154 self.current_item.images.push(image);
155 ParserState::Images
156 }
157 Event::End(e) if e.local_name().as_ref() == b"images" => ParserState::Label,
158
159 _ => ParserState::Images,
160 },
161
162 ParserState::Contactinfo => match ev {
163 Event::Text(e) => {
164 self.current_item.contactinfo = Some(e.unescape()?.to_string());
165 ParserState::Contactinfo
166 }
167 _ => ParserState::Label,
168 },
169
170 ParserState::Profile => match ev {
171 Event::Text(e) => {
172 self.current_item.profile = Some(e.unescape()?.to_string());
173 ParserState::Profile
174 }
175 _ => ParserState::Label,
176 },
177
178 ParserState::ParentLabel => match ev {
179 Event::Text(e) => {
180 let parent_label = LabelInfo {
181 id: self.current_parent_id.unwrap(),
182 name: e.unescape()?.to_string(),
183 };
184 self.current_item.parent_label = Some(parent_label);
185 self.current_parent_id = None;
186 ParserState::ParentLabel
187 }
188 _ => ParserState::Label,
189 },
190
191 ParserState::Sublabels => match ev {
192 Event::Start(e) if e.local_name().as_ref() == b"label" => {
193 self.current_sublabel_id = Some(get_attr_id(e));
194 ParserState::Sublabel
195 }
196 Event::End(e) if e.local_name().as_ref() == b"sublabels" => ParserState::Label,
197
198 _ => ParserState::Sublabels,
199 },
200
201 ParserState::Sublabel => match ev {
202 Event::Text(e) => {
203 let sublabel = LabelInfo {
204 id: self.current_sublabel_id.unwrap(),
205 name: e.unescape()?.to_string(),
206 };
207 self.current_item.sublabels.push(sublabel);
208 self.current_sublabel_id = None;
209 ParserState::Sublabels
210 }
211 _ => ParserState::Sublabels,
212 },
213
214 ParserState::Urls => match ev {
215 Event::Text(e) => {
216 self.current_item.urls.push(e.unescape()?.to_string());
217 ParserState::Urls
218 }
219 Event::End(e) if e.local_name().as_ref() == b"urls" => ParserState::Label,
220
221 _ => ParserState::Urls,
222 },
223
224 ParserState::DataQuality => match ev {
225 Event::Text(e) => {
226 self.current_item.data_quality = e.unescape()?.to_string();
227 ParserState::DataQuality
228 }
229 _ => ParserState::Label,
230 },
231 };
232
233 Ok(())
234 }
235}