wacore_binary/
attrs.rs

1use std::borrow::Cow;
2use std::str::FromStr;
3
4use crate::error::{BinaryError, Result};
5use crate::jid::Jid;
6use crate::node::{Attrs, Node, NodeRef};
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>, Cow<'a, str>)],
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 Cow<'a, str>> {
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> {
55        self.get_raw(key, false).map(|s| s.as_ref())
56    }
57
58    pub fn string(&mut self, key: &str) -> String {
59        self.get_raw(key, true)
60            .map(|s| s.as_ref().to_string())
61            .unwrap_or_default()
62    }
63
64    pub fn optional_jid(&mut self, key: &str) -> Option<Jid> {
65        self.get_raw(key, false)
66            .and_then(|s| match Jid::from_str(s.as_ref()) {
67                Ok(jid) => Some(jid),
68                Err(e) => {
69                    self.errors.push(BinaryError::from(e));
70                    None
71                }
72            })
73    }
74
75    pub fn jid(&mut self, key: &str) -> Jid {
76        self.get_raw(key, true);
77        self.optional_jid(key).unwrap_or_default()
78    }
79
80    pub fn non_ad_jid(&mut self, key: &str) -> Jid {
81        self.jid(key).to_non_ad()
82    }
83
84    fn get_bool(&mut self, key: &str, require: bool) -> Option<bool> {
85        self.get_raw(key, require)
86            .and_then(|s| match s.as_ref().parse::<bool>() {
87                Ok(val) => Some(val),
88                Err(e) => {
89                    self.errors.push(BinaryError::AttrParse(format!(
90                        "Failed to parse bool from '{s}' for key '{key}': {e}"
91                    )));
92                    None
93                }
94            })
95    }
96
97    pub fn optional_bool(&mut self, key: &str) -> bool {
98        self.get_bool(key, false).unwrap_or(false)
99    }
100
101    pub fn bool(&mut self, key: &str) -> bool {
102        self.get_bool(key, true).unwrap_or(false)
103    }
104
105    pub fn optional_u64(&mut self, key: &str) -> Option<u64> {
106        self.get_raw(key, false)
107            .and_then(|s| match s.as_ref().parse::<u64>() {
108                Ok(val) => Some(val),
109                Err(e) => {
110                    self.errors.push(BinaryError::AttrParse(format!(
111                        "Failed to parse u64 from '{s}' for key '{key}': {e}"
112                    )));
113                    None
114                }
115            })
116    }
117
118    pub fn unix_time(&mut self, key: &str) -> i64 {
119        self.get_raw(key, true);
120        self.optional_unix_time(key).unwrap_or_default()
121    }
122
123    pub fn optional_unix_time(&mut self, key: &str) -> Option<i64> {
124        self.get_i64(key, false)
125    }
126
127    pub fn unix_milli(&mut self, key: &str) -> i64 {
128        self.get_raw(key, true);
129        self.optional_unix_milli(key).unwrap_or_default()
130    }
131
132    pub fn optional_unix_milli(&mut self, key: &str) -> Option<i64> {
133        self.get_i64(key, false)
134    }
135
136    fn get_i64(&mut self, key: &str, require: bool) -> Option<i64> {
137        self.get_raw(key, require)
138            .and_then(|s| match s.as_ref().parse::<i64>() {
139                Ok(val) => Some(val),
140                Err(e) => {
141                    self.errors.push(BinaryError::AttrParse(format!(
142                        "Failed to parse i64 from '{s}' for key '{key}': {e}"
143                    )));
144                    None
145                }
146            })
147    }
148}
149
150impl<'a> AttrParser<'a> {
151    pub fn new(node: &'a Node) -> Self {
152        Self {
153            attrs: &node.attrs,
154            errors: Vec::new(),
155        }
156    }
157
158    pub fn ok(&self) -> bool {
159        self.errors.is_empty()
160    }
161
162    pub fn finish(&self) -> Result<()> {
163        if self.ok() {
164            Ok(())
165        } else {
166            Err(BinaryError::AttrList(self.errors.clone()))
167        }
168    }
169
170    fn get_raw(&mut self, key: &str, require: bool) -> Option<&'a String> {
171        let val = self.attrs.get(key);
172        if require && val.is_none() {
173            self.errors.push(BinaryError::AttrParse(format!(
174                "Required attribute '{key}' not found"
175            )));
176        }
177        val
178    }
179
180    // --- String ---
181    pub fn optional_string(&mut self, key: &str) -> Option<&'a str> {
182        self.get_raw(key, false).map(|s| s.as_str())
183    }
184
185    pub fn string(&mut self, key: &str) -> String {
186        self.get_raw(key, true).cloned().unwrap_or_default()
187    }
188
189    // --- JID ---
190    pub fn optional_jid(&mut self, key: &str) -> Option<Jid> {
191        self.get_raw(key, false)
192            .and_then(|s| match Jid::from_str(s) {
193                Ok(jid) => Some(jid),
194                Err(e) => {
195                    self.errors.push(BinaryError::from(e));
196                    None
197                }
198            })
199    }
200
201    pub fn jid(&mut self, key: &str) -> Jid {
202        self.get_raw(key, true); // Push "not found" error if needed.
203        self.optional_jid(key).unwrap_or_default()
204    }
205
206    pub fn non_ad_jid(&mut self, key: &str) -> Jid {
207        self.jid(key).to_non_ad()
208    }
209
210    // --- Boolean ---
211    fn get_bool(&mut self, key: &str, require: bool) -> Option<bool> {
212        self.get_raw(key, require)
213            .and_then(|s| match s.parse::<bool>() {
214                Ok(val) => Some(val),
215                Err(e) => {
216                    self.errors.push(BinaryError::AttrParse(format!(
217                        "Failed to parse bool from '{s}' for key '{key}': {e}"
218                    )));
219                    None
220                }
221            })
222    }
223
224    pub fn optional_bool(&mut self, key: &str) -> bool {
225        self.get_bool(key, false).unwrap_or(false)
226    }
227
228    pub fn bool(&mut self, key: &str) -> bool {
229        self.get_bool(key, true).unwrap_or(false)
230    }
231
232    // --- u64 ---
233    pub fn optional_u64(&mut self, key: &str) -> Option<u64> {
234        self.get_raw(key, false)
235            .and_then(|s| match s.parse::<u64>() {
236                Ok(val) => Some(val),
237                Err(e) => {
238                    self.errors.push(BinaryError::AttrParse(format!(
239                        "Failed to parse u64 from '{s}' for key '{key}': {e}"
240                    )));
241                    None
242                }
243            })
244    }
245
246    pub fn unix_time(&mut self, key: &str) -> i64 {
247        self.get_raw(key, true);
248        self.optional_unix_time(key).unwrap_or_default()
249    }
250
251    pub fn optional_unix_time(&mut self, key: &str) -> Option<i64> {
252        self.get_i64(key, false)
253    }
254
255    pub fn unix_milli(&mut self, key: &str) -> i64 {
256        self.get_raw(key, true);
257        self.optional_unix_milli(key).unwrap_or_default()
258    }
259
260    pub fn optional_unix_milli(&mut self, key: &str) -> Option<i64> {
261        self.get_i64(key, false)
262    }
263
264    fn get_i64(&mut self, key: &str, require: bool) -> Option<i64> {
265        self.get_raw(key, require)
266            .and_then(|s| match s.parse::<i64>() {
267                Ok(val) => Some(val),
268                Err(e) => {
269                    self.errors.push(BinaryError::AttrParse(format!(
270                        "Failed to parse i64 from '{s}' for key '{key}': {e}"
271                    )));
272                    None
273                }
274            })
275    }
276}