1use std::borrow::Cow;
2use std::str::FromStr;
3
4use crate::error::{BinaryError, Result};
5use crate::jid::Jid;
6use crate::node::{Attrs, Node, NodeRef, NodeValue, ValueRef};
7
8pub struct AttrParser<'a> {
9 pub attrs: &'a Attrs,
10 pub errors: Vec<BinaryError>,
11}
12
13pub struct AttrParserRef<'a> {
14 pub attrs: &'a [(Cow<'a, str>, ValueRef<'a>)],
15 pub errors: Vec<BinaryError>,
16}
17
18impl<'a> AttrParserRef<'a> {
19 pub fn new(node: &'a NodeRef<'a>) -> Self {
20 Self {
21 attrs: node.attrs.as_slice(),
22 errors: Vec::new(),
23 }
24 }
25
26 pub fn ok(&self) -> bool {
27 self.errors.is_empty()
28 }
29
30 pub fn finish(&self) -> Result<()> {
31 if self.ok() {
32 Ok(())
33 } else {
34 Err(BinaryError::AttrList(self.errors.clone()))
35 }
36 }
37
38 fn get_raw(&mut self, key: &str, require: bool) -> Option<&'a ValueRef<'a>> {
39 let val = self
40 .attrs
41 .iter()
42 .find(|(k, _)| k.as_ref() == key)
43 .map(|(_, v)| v);
44
45 if require && val.is_none() {
46 self.errors.push(BinaryError::AttrParse(format!(
47 "Required attribute '{key}' not found"
48 )));
49 }
50
51 val
52 }
53
54 pub fn optional_string(&mut self, key: &str) -> Option<Cow<'a, str>> {
58 self.get_raw(key, false).map(|v| v.to_string_cow())
59 }
60
61 pub fn required_string(&mut self, key: &str) -> Result<Cow<'a, str>> {
66 self.optional_string(key)
67 .ok_or_else(|| BinaryError::MissingAttr(key.to_string()))
68 }
69
70 pub fn optional_jid(&mut self, key: &str) -> Option<Jid> {
74 self.get_raw(key, false).and_then(|v| match v.to_jid() {
75 Some(jid) => Some(jid),
76 None => {
77 if let ValueRef::String(s) = v {
79 self.errors
80 .push(BinaryError::AttrParse(format!("Invalid JID: {s}")));
81 }
82 None
83 }
84 })
85 }
86
87 pub fn jid(&mut self, key: &str) -> Jid {
88 self.get_raw(key, true);
89 self.optional_jid(key).unwrap_or_default()
90 }
91
92 pub fn non_ad_jid(&mut self, key: &str) -> Jid {
93 self.jid(key).to_non_ad()
94 }
95
96 fn get_string_value(&mut self, key: &str, require: bool) -> Option<Cow<'a, str>> {
97 self.get_raw(key, require).map(|v| v.to_string_cow())
98 }
99
100 fn get_bool(&mut self, key: &str, require: bool) -> Option<bool> {
101 self.get_string_value(key, require)
102 .and_then(|s| match s.parse::<bool>() {
103 Ok(val) => Some(val),
104 Err(e) => {
105 self.errors.push(BinaryError::AttrParse(format!(
106 "Failed to parse bool from '{s}' for key '{key}': {e}"
107 )));
108 None
109 }
110 })
111 }
112
113 pub fn optional_bool(&mut self, key: &str) -> bool {
114 self.get_bool(key, false).unwrap_or(false)
115 }
116
117 pub fn bool(&mut self, key: &str) -> bool {
118 self.get_bool(key, true).unwrap_or(false)
119 }
120
121 pub fn optional_u64(&mut self, key: &str) -> Option<u64> {
122 self.get_string_value(key, false)
123 .and_then(|s| match s.parse::<u64>() {
124 Ok(val) => Some(val),
125 Err(e) => {
126 self.errors.push(BinaryError::AttrParse(format!(
127 "Failed to parse u64 from '{s}' for key '{key}': {e}"
128 )));
129 None
130 }
131 })
132 }
133
134 pub fn unix_time(&mut self, key: &str) -> i64 {
135 self.get_raw(key, true);
136 self.optional_unix_time(key).unwrap_or_default()
137 }
138
139 pub fn optional_unix_time(&mut self, key: &str) -> Option<i64> {
140 self.get_i64(key, false)
141 }
142
143 pub fn unix_milli(&mut self, key: &str) -> i64 {
144 self.get_raw(key, true);
145 self.optional_unix_milli(key).unwrap_or_default()
146 }
147
148 pub fn optional_unix_milli(&mut self, key: &str) -> Option<i64> {
149 self.get_i64(key, false)
150 }
151
152 fn get_i64(&mut self, key: &str, require: bool) -> Option<i64> {
153 self.get_string_value(key, require)
154 .and_then(|s| match s.parse::<i64>() {
155 Ok(val) => Some(val),
156 Err(e) => {
157 self.errors.push(BinaryError::AttrParse(format!(
158 "Failed to parse i64 from '{s}' for key '{key}': {e}"
159 )));
160 None
161 }
162 })
163 }
164}
165
166impl<'a> AttrParser<'a> {
167 pub fn new(node: &'a Node) -> Self {
168 Self {
169 attrs: &node.attrs,
170 errors: Vec::new(),
171 }
172 }
173
174 pub fn ok(&self) -> bool {
175 self.errors.is_empty()
176 }
177
178 pub fn finish(&self) -> Result<()> {
179 if self.ok() {
180 Ok(())
181 } else {
182 Err(BinaryError::AttrList(self.errors.clone()))
183 }
184 }
185
186 fn get_raw(&mut self, key: &str, require: bool) -> Option<&'a NodeValue> {
187 let val = self.attrs.get(key);
188 if require && val.is_none() {
189 self.errors.push(BinaryError::AttrParse(format!(
190 "Required attribute '{key}' not found"
191 )));
192 }
193 val
194 }
195
196 fn get_string_value(&mut self, key: &str, require: bool) -> Option<Cow<'a, str>> {
198 self.get_raw(key, require).map(|v| match v {
199 NodeValue::String(s) => Cow::Borrowed(s.as_str()),
200 NodeValue::Jid(j) => Cow::Owned(j.to_string()),
201 })
202 }
203
204 pub fn optional_string(&mut self, key: &str) -> Option<Cow<'a, str>> {
209 self.get_raw(key, false).map(|v| v.as_str())
210 }
211
212 pub fn required_string(&mut self, key: &str) -> Result<Cow<'a, str>> {
217 self.optional_string(key)
218 .ok_or_else(|| BinaryError::MissingAttr(key.to_string()))
219 }
220
221 pub fn optional_jid(&mut self, key: &str) -> Option<Jid> {
226 self.get_raw(key, false).and_then(|v| match v {
227 NodeValue::Jid(j) => Some(j.clone()),
228 NodeValue::String(s) => match Jid::from_str(s) {
229 Ok(jid) => Some(jid),
230 Err(e) => {
231 self.errors.push(BinaryError::from(e));
232 None
233 }
234 },
235 })
236 }
237
238 pub fn jid(&mut self, key: &str) -> Jid {
239 self.get_raw(key, true); self.optional_jid(key).unwrap_or_default()
241 }
242
243 pub fn non_ad_jid(&mut self, key: &str) -> Jid {
244 self.jid(key).to_non_ad()
245 }
246
247 fn get_bool(&mut self, key: &str, require: bool) -> Option<bool> {
249 self.get_string_value(key, require)
250 .and_then(|s| match s.parse::<bool>() {
251 Ok(val) => Some(val),
252 Err(e) => {
253 self.errors.push(BinaryError::AttrParse(format!(
254 "Failed to parse bool from '{s}' for key '{key}': {e}"
255 )));
256 None
257 }
258 })
259 }
260
261 pub fn optional_bool(&mut self, key: &str) -> bool {
262 self.get_bool(key, false).unwrap_or(false)
263 }
264
265 pub fn bool(&mut self, key: &str) -> bool {
266 self.get_bool(key, true).unwrap_or(false)
267 }
268
269 pub fn optional_u64(&mut self, key: &str) -> Option<u64> {
271 self.get_string_value(key, false)
272 .and_then(|s| match s.parse::<u64>() {
273 Ok(val) => Some(val),
274 Err(e) => {
275 self.errors.push(BinaryError::AttrParse(format!(
276 "Failed to parse u64 from '{s}' for key '{key}': {e}"
277 )));
278 None
279 }
280 })
281 }
282
283 pub fn unix_time(&mut self, key: &str) -> i64 {
284 self.get_raw(key, true);
285 self.optional_unix_time(key).unwrap_or_default()
286 }
287
288 pub fn optional_unix_time(&mut self, key: &str) -> Option<i64> {
289 self.get_i64(key, false)
290 }
291
292 pub fn unix_milli(&mut self, key: &str) -> i64 {
293 self.get_raw(key, true);
294 self.optional_unix_milli(key).unwrap_or_default()
295 }
296
297 pub fn optional_unix_milli(&mut self, key: &str) -> Option<i64> {
298 self.get_i64(key, false)
299 }
300
301 fn get_i64(&mut self, key: &str, require: bool) -> Option<i64> {
302 self.get_string_value(key, require)
303 .and_then(|s| match s.parse::<i64>() {
304 Ok(val) => Some(val),
305 Err(e) => {
306 self.errors.push(BinaryError::AttrParse(format!(
307 "Failed to parse i64 from '{s}' for key '{key}': {e}"
308 )));
309 None
310 }
311 })
312 }
313}