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 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 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); 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 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 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}