1use crate::attrs::{AttrParser, AttrParserRef};
2use crate::jid::{Jid, JidRef};
3use crate::token;
4use std::borrow::Cow;
5
6#[inline]
10fn intern_cow(s: &str) -> Cow<'static, str> {
11 if let Some(idx) = token::index_of_single_token(s)
12 && let Some(token) = token::get_single_token(idx)
13 {
14 return Cow::Borrowed(token);
15 } else if let Some((dict, idx)) = token::index_of_double_byte_token(s)
16 && let Some(token) = token::get_double_token(dict, idx)
17 {
18 return Cow::Borrowed(token);
19 }
20 Cow::Owned(s.to_string())
21}
22
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27#[derive(Debug, Clone, PartialEq)]
28pub enum NodeValue {
29 String(String),
30 Jid(Jid),
31}
32
33impl Default for NodeValue {
34 fn default() -> Self {
35 NodeValue::String(String::new())
36 }
37}
38
39impl NodeValue {
40 #[inline]
44 pub fn as_str(&self) -> Cow<'_, str> {
45 match self {
46 NodeValue::String(s) => Cow::Borrowed(s.as_str()),
47 NodeValue::Jid(j) => Cow::Owned(j.to_string()),
48 }
49 }
50
51 #[inline]
53 pub fn to_jid(&self) -> Option<Jid> {
54 match self {
55 NodeValue::Jid(j) => Some(j.clone()),
56 NodeValue::String(s) => s.parse().ok(),
57 }
58 }
59}
60
61use std::fmt;
62
63impl fmt::Display for NodeValue {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 match self {
66 NodeValue::String(s) => write!(f, "{}", s),
67 NodeValue::Jid(j) => write!(f, "{}", j),
68 }
69 }
70}
71
72impl PartialEq<str> for NodeValue {
73 fn eq(&self, other: &str) -> bool {
74 match self {
75 NodeValue::String(s) => s == other,
76 NodeValue::Jid(j) => {
79 use std::fmt::Write;
80 struct EqCheck<'a> {
81 target: &'a [u8],
82 pos: usize,
83 matches: bool,
84 }
85 impl fmt::Write for EqCheck<'_> {
86 fn write_str(&mut self, s: &str) -> fmt::Result {
87 if !self.matches {
88 return Ok(());
89 }
90 let bytes = s.as_bytes();
91 let end = self.pos + bytes.len();
92 if end > self.target.len() || self.target[self.pos..end] != *bytes {
93 self.matches = false;
94 }
95 self.pos = end;
96 Ok(())
97 }
98 }
99 let mut check = EqCheck {
100 target: other.as_bytes(),
101 pos: 0,
102 matches: true,
103 };
104 let _ = write!(check, "{}", j);
105 check.matches && check.pos == other.len()
106 }
107 }
108 }
109}
110
111impl PartialEq<&str> for NodeValue {
112 fn eq(&self, other: &&str) -> bool {
113 self == *other
114 }
115}
116
117impl PartialEq<String> for NodeValue {
118 fn eq(&self, other: &String) -> bool {
119 self == other.as_str()
120 }
121}
122
123impl From<String> for NodeValue {
124 #[inline]
125 fn from(s: String) -> Self {
126 NodeValue::String(s)
127 }
128}
129
130impl From<&str> for NodeValue {
131 #[inline]
132 fn from(s: &str) -> Self {
133 NodeValue::String(s.to_string())
134 }
135}
136
137impl From<&String> for NodeValue {
138 #[inline]
139 fn from(s: &String) -> Self {
140 NodeValue::String(s.clone())
141 }
142}
143
144impl From<Jid> for NodeValue {
145 #[inline]
146 fn from(jid: Jid) -> Self {
147 NodeValue::Jid(jid)
148 }
149}
150
151#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
157#[derive(Debug, Clone, PartialEq, Default)]
158pub struct Attrs(pub Vec<(Cow<'static, str>, NodeValue)>);
159
160impl Attrs {
161 #[inline]
162 pub fn new() -> Self {
163 Self(Vec::new())
164 }
165
166 #[inline]
167 pub fn with_capacity(capacity: usize) -> Self {
168 Self(Vec::with_capacity(capacity))
169 }
170
171 #[inline]
174 pub fn get(&self, key: &str) -> Option<&NodeValue> {
175 self.0.iter().find(|(k, _)| k == key).map(|(_, v)| v)
176 }
177
178 #[inline]
180 pub fn contains_key(&self, key: &str) -> bool {
181 self.0.iter().any(|(k, _)| k == key)
182 }
183
184 #[inline]
186 pub fn insert(&mut self, key: impl Into<Cow<'static, str>>, value: impl Into<NodeValue>) {
187 let key = key.into();
188 let value = value.into();
189 if let Some(pos) = self.0.iter().position(|(k, _)| k == &key) {
190 self.0[pos].1 = value;
191 } else {
192 self.0.push((key, value));
193 }
194 }
195
196 #[inline]
197 pub fn len(&self) -> usize {
198 self.0.len()
199 }
200
201 #[inline]
202 pub fn is_empty(&self) -> bool {
203 self.0.is_empty()
204 }
205
206 #[inline]
208 pub fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &NodeValue)> {
209 self.0.iter().map(|(k, v)| (k, v))
210 }
211
212 #[inline]
215 pub fn push(&mut self, key: impl Into<Cow<'static, str>>, value: impl Into<NodeValue>) {
216 self.0.push((key.into(), value.into()));
217 }
218
219 #[inline]
222 pub fn push_value(&mut self, key: impl Into<Cow<'static, str>>, value: NodeValue) {
223 self.0.push((key.into(), value));
224 }
225
226 #[inline]
228 pub fn keys(&self) -> impl Iterator<Item = &Cow<'static, str>> {
229 self.0.iter().map(|(k, _)| k)
230 }
231}
232
233impl IntoIterator for Attrs {
235 type Item = (Cow<'static, str>, NodeValue);
236 type IntoIter = std::vec::IntoIter<(Cow<'static, str>, NodeValue)>;
237
238 fn into_iter(self) -> Self::IntoIter {
239 self.0.into_iter()
240 }
241}
242
243impl<'a> IntoIterator for &'a Attrs {
245 type Item = (&'a Cow<'static, str>, &'a NodeValue);
246 type IntoIter = std::iter::Map<
247 std::slice::Iter<'a, (Cow<'static, str>, NodeValue)>,
248 fn(&'a (Cow<'static, str>, NodeValue)) -> (&'a Cow<'static, str>, &'a NodeValue),
249 >;
250
251 fn into_iter(self) -> Self::IntoIter {
252 self.0.iter().map(|(k, v)| (k, v))
253 }
254}
255
256impl FromIterator<(Cow<'static, str>, NodeValue)> for Attrs {
257 fn from_iter<I: IntoIterator<Item = (Cow<'static, str>, NodeValue)>>(iter: I) -> Self {
258 Self(iter.into_iter().collect())
259 }
260}
261pub type AttrsRef<'a> = Vec<(Cow<'a, str>, ValueRef<'a>)>;
262
263#[derive(Debug, Clone, PartialEq)]
267pub enum ValueRef<'a> {
268 String(Cow<'a, str>),
269 Jid(JidRef<'a>),
270}
271
272impl<'a> ValueRef<'a> {
273 pub fn as_str(&self) -> Option<&str> {
275 match self {
276 ValueRef::String(s) => Some(s.as_ref()),
277 ValueRef::Jid(_) => None,
278 }
279 }
280
281 pub fn as_jid(&self) -> Option<&JidRef<'a>> {
283 match self {
284 ValueRef::Jid(j) => Some(j),
285 ValueRef::String(_) => None,
286 }
287 }
288
289 pub fn to_jid(&self) -> Option<Jid> {
291 match self {
292 ValueRef::Jid(j) => Some(j.to_owned()),
293 ValueRef::String(s) => Jid::from_str(s.as_ref()).ok(),
294 }
295 }
296
297 pub fn to_string_cow(&self) -> Cow<'a, str> {
300 match self {
301 ValueRef::String(s) => s.clone(),
302 ValueRef::Jid(j) => Cow::Owned(j.to_string()),
303 }
304 }
305}
306
307use std::str::FromStr;
308
309impl<'a> fmt::Display for ValueRef<'a> {
310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311 match self {
312 ValueRef::String(s) => write!(f, "{}", s),
313 ValueRef::Jid(j) => write!(f, "{}", j),
314 }
315 }
316}
317
318pub type NodeVec<'a> = Vec<NodeRef<'a>>;
319
320#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
321#[derive(Debug, Clone, PartialEq)]
322pub enum NodeContent {
323 Bytes(Vec<u8>),
324 String(String),
325 Nodes(Vec<Node>),
326}
327
328#[derive(Debug, Clone, PartialEq)]
329pub enum NodeContentRef<'a> {
330 Bytes(Cow<'a, [u8]>),
331 String(Cow<'a, str>),
332 Nodes(Box<NodeVec<'a>>),
333}
334
335impl NodeContent {
336 pub fn as_content_ref(&self) -> NodeContentRef<'_> {
338 match self {
339 NodeContent::Bytes(b) => NodeContentRef::Bytes(Cow::Borrowed(b)),
340 NodeContent::String(s) => NodeContentRef::String(Cow::Borrowed(s)),
341 NodeContent::Nodes(nodes) => {
342 NodeContentRef::Nodes(Box::new(nodes.iter().map(|n| n.as_node_ref()).collect()))
343 }
344 }
345 }
346}
347
348#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
349#[derive(Debug, Clone, PartialEq, Default)]
350pub struct Node {
351 pub tag: Cow<'static, str>,
352 pub attrs: Attrs,
353 pub content: Option<NodeContent>,
354}
355
356#[derive(Debug, Clone, PartialEq)]
357pub struct NodeRef<'a> {
358 pub tag: Cow<'a, str>,
359 pub attrs: AttrsRef<'a>,
360 pub content: Option<Box<NodeContentRef<'a>>>,
361}
362
363impl Node {
364 pub fn new(
365 tag: impl Into<Cow<'static, str>>,
366 attrs: Attrs,
367 content: Option<NodeContent>,
368 ) -> Self {
369 Self {
370 tag: tag.into(),
371 attrs,
372 content,
373 }
374 }
375
376 pub fn as_node_ref(&self) -> NodeRef<'_> {
379 NodeRef {
380 tag: Cow::Borrowed(self.tag.as_ref()),
381 attrs: self
382 .attrs
383 .iter()
384 .map(|(k, v)| {
385 let value_ref = match v {
386 NodeValue::String(s) => ValueRef::String(Cow::Borrowed(s.as_str())),
387 NodeValue::Jid(j) => ValueRef::Jid(JidRef {
388 user: Cow::Borrowed(&j.user),
389 server: Cow::Borrowed(&j.server),
390 agent: j.agent,
391 device: j.device,
392 integrator: j.integrator,
393 }),
394 };
395 (Cow::Borrowed(k.as_ref()), value_ref)
396 })
397 .collect(),
398 content: self.content.as_ref().map(|c| Box::new(c.as_content_ref())),
399 }
400 }
401
402 pub fn children(&self) -> Option<&[Node]> {
403 match &self.content {
404 Some(NodeContent::Nodes(nodes)) => Some(nodes),
405 _ => None,
406 }
407 }
408
409 pub fn attrs(&self) -> AttrParser<'_> {
410 AttrParser::new(self)
411 }
412
413 pub fn get_optional_child_by_tag<'a>(&'a self, tags: &[&str]) -> Option<&'a Node> {
414 let mut current_node = self;
415 for &tag in tags {
416 if let Some(children) = current_node.children() {
417 if let Some(found) = children.iter().find(|c| c.tag == tag) {
418 current_node = found;
419 } else {
420 return None;
421 }
422 } else {
423 return None;
424 }
425 }
426 Some(current_node)
427 }
428
429 pub fn get_children_by_tag<'a>(&'a self, tag: &'a str) -> impl Iterator<Item = &'a Node> {
430 self.children()
431 .into_iter()
432 .flatten()
433 .filter(move |c| c.tag == tag)
434 }
435
436 pub fn get_optional_child(&self, tag: &str) -> Option<&Node> {
437 self.children()
438 .and_then(|nodes| nodes.iter().find(|node| node.tag == tag))
439 }
440}
441
442impl<'a> NodeRef<'a> {
443 pub fn new(
444 tag: Cow<'a, str>,
445 attrs: AttrsRef<'a>,
446 content: Option<NodeContentRef<'a>>,
447 ) -> Self {
448 Self {
449 tag,
450 attrs,
451 content: content.map(Box::new),
452 }
453 }
454
455 pub fn attr_parser(&'a self) -> AttrParserRef<'a> {
456 AttrParserRef::new(self)
457 }
458
459 pub fn children(&self) -> Option<&[NodeRef<'a>]> {
460 match self.content.as_deref() {
461 Some(NodeContentRef::Nodes(nodes)) => Some(nodes.as_slice()),
462 _ => None,
463 }
464 }
465
466 pub fn get_attr(&self, key: &str) -> Option<&ValueRef<'a>> {
467 self.attrs.iter().find(|(k, _)| k == key).map(|(_, v)| v)
468 }
469
470 pub fn attrs_iter(&self) -> impl Iterator<Item = (&Cow<'a, str>, &ValueRef<'a>)> {
471 self.attrs.iter().map(|(k, v)| (k, v))
472 }
473
474 pub fn get_optional_child_by_tag(&self, tags: &[&str]) -> Option<&NodeRef<'a>> {
475 let mut current_node = self;
476 for &tag in tags {
477 if let Some(children) = current_node.children() {
478 if let Some(found) = children.iter().find(|c| c.tag == tag) {
479 current_node = found;
480 } else {
481 return None;
482 }
483 } else {
484 return None;
485 }
486 }
487 Some(current_node)
488 }
489
490 pub fn get_children_by_tag<'b>(&'b self, tag: &'b str) -> impl Iterator<Item = &'b NodeRef<'a>>
491 where
492 'a: 'b,
493 {
494 self.children()
495 .into_iter()
496 .flatten()
497 .filter(move |c| c.tag == tag)
498 }
499
500 pub fn get_optional_child(&self, tag: &str) -> Option<&NodeRef<'a>> {
501 self.children()
502 .and_then(|nodes| nodes.iter().find(|node| node.tag == tag))
503 }
504
505 pub fn to_owned(&self) -> Node {
506 Node {
507 tag: intern_cow(&self.tag),
508 attrs: self
509 .attrs
510 .iter()
511 .map(|(k, v)| {
512 let value = match v {
513 ValueRef::String(s) => NodeValue::String(s.to_string()),
514 ValueRef::Jid(j) => NodeValue::Jid(j.to_owned()),
515 };
516 (intern_cow(k), value)
517 })
518 .collect::<Attrs>(),
519 content: self.content.as_deref().map(|c| match c {
520 NodeContentRef::Bytes(b) => NodeContent::Bytes(b.to_vec()),
521 NodeContentRef::String(s) => NodeContent::String(s.to_string()),
522 NodeContentRef::Nodes(nodes) => {
523 NodeContent::Nodes(nodes.iter().map(|n| n.to_owned()).collect())
524 }
525 }),
526 }
527 }
528}