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<&'a str> {
57 self.get_raw(key, false).and_then(|v| v.as_str())
58 }
59
60 pub fn required_string(&mut self, key: &str) -> Result<&'a str> {
65 self.optional_string(key)
66 .ok_or_else(|| BinaryError::MissingAttr(key.to_string()))
67 }
68
69 #[deprecated(
77 since = "0.2.0",
78 note = "Use optional_string() with explicit handling or required_string() instead"
79 )]
80 pub fn string(&mut self, key: &str) -> String {
81 self.get_raw(key, true)
82 .map(|v| v.to_string_cow().into_owned())
83 .unwrap_or_default()
84 }
85
86 pub fn optional_jid(&mut self, key: &str) -> Option<Jid> {
90 self.get_raw(key, false).and_then(|v| match v.to_jid() {
91 Some(jid) => Some(jid),
92 None => {
93 if let ValueRef::String(s) = v {
95 self.errors
96 .push(BinaryError::AttrParse(format!("Invalid JID: {s}")));
97 }
98 None
99 }
100 })
101 }
102
103 pub fn jid(&mut self, key: &str) -> Jid {
104 self.get_raw(key, true);
105 self.optional_jid(key).unwrap_or_default()
106 }
107
108 pub fn non_ad_jid(&mut self, key: &str) -> Jid {
109 self.jid(key).to_non_ad()
110 }
111
112 fn get_string_value(&mut self, key: &str, require: bool) -> Option<Cow<'a, str>> {
113 self.get_raw(key, require).map(|v| v.to_string_cow())
114 }
115
116 fn get_bool(&mut self, key: &str, require: bool) -> Option<bool> {
117 self.get_string_value(key, require)
118 .and_then(|s| match s.parse::<bool>() {
119 Ok(val) => Some(val),
120 Err(e) => {
121 self.errors.push(BinaryError::AttrParse(format!(
122 "Failed to parse bool from '{s}' for key '{key}': {e}"
123 )));
124 None
125 }
126 })
127 }
128
129 pub fn optional_bool(&mut self, key: &str) -> bool {
130 self.get_bool(key, false).unwrap_or(false)
131 }
132
133 pub fn bool(&mut self, key: &str) -> bool {
134 self.get_bool(key, true).unwrap_or(false)
135 }
136
137 pub fn optional_u64(&mut self, key: &str) -> Option<u64> {
138 self.get_string_value(key, false)
139 .and_then(|s| match s.parse::<u64>() {
140 Ok(val) => Some(val),
141 Err(e) => {
142 self.errors.push(BinaryError::AttrParse(format!(
143 "Failed to parse u64 from '{s}' for key '{key}': {e}"
144 )));
145 None
146 }
147 })
148 }
149
150 pub fn unix_time(&mut self, key: &str) -> i64 {
151 self.get_raw(key, true);
152 self.optional_unix_time(key).unwrap_or_default()
153 }
154
155 pub fn optional_unix_time(&mut self, key: &str) -> Option<i64> {
156 self.get_i64(key, false)
157 }
158
159 pub fn unix_milli(&mut self, key: &str) -> i64 {
160 self.get_raw(key, true);
161 self.optional_unix_milli(key).unwrap_or_default()
162 }
163
164 pub fn optional_unix_milli(&mut self, key: &str) -> Option<i64> {
165 self.get_i64(key, false)
166 }
167
168 fn get_i64(&mut self, key: &str, require: bool) -> Option<i64> {
169 self.get_string_value(key, require)
170 .and_then(|s| match s.parse::<i64>() {
171 Ok(val) => Some(val),
172 Err(e) => {
173 self.errors.push(BinaryError::AttrParse(format!(
174 "Failed to parse i64 from '{s}' for key '{key}': {e}"
175 )));
176 None
177 }
178 })
179 }
180}
181
182impl<'a> AttrParser<'a> {
183 pub fn new(node: &'a Node) -> Self {
184 Self {
185 attrs: &node.attrs,
186 errors: Vec::new(),
187 }
188 }
189
190 pub fn ok(&self) -> bool {
191 self.errors.is_empty()
192 }
193
194 pub fn finish(&self) -> Result<()> {
195 if self.ok() {
196 Ok(())
197 } else {
198 Err(BinaryError::AttrList(self.errors.clone()))
199 }
200 }
201
202 fn get_raw(&mut self, key: &str, require: bool) -> Option<&'a NodeValue> {
203 let val = self.attrs.get(key);
204 if require && val.is_none() {
205 self.errors.push(BinaryError::AttrParse(format!(
206 "Required attribute '{key}' not found"
207 )));
208 }
209 val
210 }
211
212 fn get_string_value(&mut self, key: &str, require: bool) -> Option<Cow<'a, str>> {
214 self.get_raw(key, require).map(|v| match v {
215 NodeValue::String(s) => Cow::Borrowed(s.as_str()),
216 NodeValue::Jid(j) => Cow::Owned(j.to_string()),
217 })
218 }
219
220 pub fn optional_string(&mut self, key: &str) -> Option<&'a str> {
222 self.get_raw(key, false).and_then(|v| v.as_str())
223 }
224
225 pub fn required_string(&mut self, key: &str) -> Result<&'a str> {
230 self.optional_string(key)
231 .ok_or_else(|| BinaryError::MissingAttr(key.to_string()))
232 }
233
234 #[deprecated(
242 since = "0.2.0",
243 note = "Use optional_string() with explicit handling or required_string() instead"
244 )]
245 pub fn string(&mut self, key: &str) -> String {
246 self.get_raw(key, true)
247 .map(|v| v.to_string_value())
248 .unwrap_or_default()
249 }
250
251 pub fn optional_jid(&mut self, key: &str) -> Option<Jid> {
256 self.get_raw(key, false).and_then(|v| match v {
257 NodeValue::Jid(j) => Some(j.clone()),
258 NodeValue::String(s) => match Jid::from_str(s) {
259 Ok(jid) => Some(jid),
260 Err(e) => {
261 self.errors.push(BinaryError::from(e));
262 None
263 }
264 },
265 })
266 }
267
268 pub fn jid(&mut self, key: &str) -> Jid {
269 self.get_raw(key, true); self.optional_jid(key).unwrap_or_default()
271 }
272
273 pub fn non_ad_jid(&mut self, key: &str) -> Jid {
274 self.jid(key).to_non_ad()
275 }
276
277 fn get_bool(&mut self, key: &str, require: bool) -> Option<bool> {
279 self.get_string_value(key, require)
280 .and_then(|s| match s.parse::<bool>() {
281 Ok(val) => Some(val),
282 Err(e) => {
283 self.errors.push(BinaryError::AttrParse(format!(
284 "Failed to parse bool from '{s}' for key '{key}': {e}"
285 )));
286 None
287 }
288 })
289 }
290
291 pub fn optional_bool(&mut self, key: &str) -> bool {
292 self.get_bool(key, false).unwrap_or(false)
293 }
294
295 pub fn bool(&mut self, key: &str) -> bool {
296 self.get_bool(key, true).unwrap_or(false)
297 }
298
299 pub fn optional_u64(&mut self, key: &str) -> Option<u64> {
301 self.get_string_value(key, false)
302 .and_then(|s| match s.parse::<u64>() {
303 Ok(val) => Some(val),
304 Err(e) => {
305 self.errors.push(BinaryError::AttrParse(format!(
306 "Failed to parse u64 from '{s}' for key '{key}': {e}"
307 )));
308 None
309 }
310 })
311 }
312
313 pub fn unix_time(&mut self, key: &str) -> i64 {
314 self.get_raw(key, true);
315 self.optional_unix_time(key).unwrap_or_default()
316 }
317
318 pub fn optional_unix_time(&mut self, key: &str) -> Option<i64> {
319 self.get_i64(key, false)
320 }
321
322 pub fn unix_milli(&mut self, key: &str) -> i64 {
323 self.get_raw(key, true);
324 self.optional_unix_milli(key).unwrap_or_default()
325 }
326
327 pub fn optional_unix_milli(&mut self, key: &str) -> Option<i64> {
328 self.get_i64(key, false)
329 }
330
331 fn get_i64(&mut self, key: &str, require: bool) -> Option<i64> {
332 self.get_string_value(key, require)
333 .and_then(|s| match s.parse::<i64>() {
334 Ok(val) => Some(val),
335 Err(e) => {
336 self.errors.push(BinaryError::AttrParse(format!(
337 "Failed to parse i64 from '{s}' for key '{key}': {e}"
338 )));
339 None
340 }
341 })
342 }
343}