1use crate::attrs::{AttrParser, AttrParserRef};
2use crate::jid::{Jid, JidRef};
3use crate::token;
4use bytes::Bytes;
5use compact_str::CompactString;
6use stable_deref_trait::StableDeref;
7use std::borrow::Cow;
8
9#[derive(Clone, yoke::Yokeable)]
12pub enum NodeStr<'a> {
13 Borrowed(&'a str),
14 Owned(CompactString),
15}
16
17impl NodeStr<'_> {
18 #[inline]
21 pub fn to_compact_string(&self) -> CompactString {
22 match self {
23 NodeStr::Borrowed(s) => CompactString::from(*s),
24 NodeStr::Owned(cs) => cs.clone(),
25 }
26 }
27}
28
29impl Default for NodeStr<'_> {
30 #[inline]
31 fn default() -> Self {
32 NodeStr::Borrowed("")
33 }
34}
35
36impl std::ops::Deref for NodeStr<'_> {
37 type Target = str;
38 #[inline(always)]
39 fn deref(&self) -> &str {
40 match self {
41 NodeStr::Borrowed(s) => s,
42 NodeStr::Owned(cs) => cs.as_str(),
43 }
44 }
45}
46
47impl AsRef<str> for NodeStr<'_> {
48 #[inline(always)]
49 fn as_ref(&self) -> &str {
50 self
51 }
52}
53
54impl fmt::Debug for NodeStr<'_> {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 fmt::Debug::fmt(&**self, f)
57 }
58}
59
60impl fmt::Display for NodeStr<'_> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.write_str(self)
63 }
64}
65
66#[cfg(feature = "serde")]
67impl serde::Serialize for NodeStr<'_> {
68 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
69 serializer.serialize_str(self)
70 }
71}
72
73impl PartialEq for NodeStr<'_> {
74 #[inline]
75 fn eq(&self, other: &Self) -> bool {
76 **self == **other
77 }
78}
79
80impl Eq for NodeStr<'_> {}
81
82impl std::hash::Hash for NodeStr<'_> {
83 #[inline]
84 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
85 (**self).hash(state)
86 }
87}
88
89impl PartialEq<str> for NodeStr<'_> {
90 #[inline]
91 fn eq(&self, other: &str) -> bool {
92 &**self == other
93 }
94}
95
96impl PartialEq<&str> for NodeStr<'_> {
97 #[inline]
98 fn eq(&self, other: &&str) -> bool {
99 &**self == *other
100 }
101}
102
103impl<'a> From<&'a str> for NodeStr<'a> {
104 #[inline]
105 fn from(s: &'a str) -> Self {
106 NodeStr::Borrowed(s)
107 }
108}
109
110impl From<CompactString> for NodeStr<'_> {
111 #[inline]
112 fn from(s: CompactString) -> Self {
113 NodeStr::Owned(s)
114 }
115}
116
117#[inline]
121fn intern_cow(s: &str) -> Cow<'static, str> {
122 if let Some(kind) = token::index_of_token(s) {
123 let interned = match kind {
124 token::TokenKind::Single(idx) => token::get_single_token(idx),
125 token::TokenKind::Double(dict, idx) => token::get_double_token(dict, idx),
126 };
127 if let Some(token) = interned {
128 return Cow::Borrowed(token);
129 }
130 }
131 Cow::Owned(s.to_string())
132}
133
134#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
138#[derive(Debug, Clone, PartialEq)]
139pub enum NodeValue {
140 String(CompactString),
141 Jid(Jid),
142}
143
144impl Default for NodeValue {
145 fn default() -> Self {
146 NodeValue::String(CompactString::default())
147 }
148}
149
150impl NodeValue {
151 #[inline]
155 pub fn as_str(&self) -> Cow<'_, str> {
156 match self {
157 NodeValue::String(s) => Cow::Borrowed(s.as_str()),
158 NodeValue::Jid(j) => Cow::Owned(j.to_string()),
159 }
160 }
161
162 #[inline]
164 pub fn to_jid(&self) -> Option<Jid> {
165 match self {
166 NodeValue::Jid(j) => Some(j.clone()),
167 NodeValue::String(s) => s.parse().ok(),
168 }
169 }
170}
171
172use std::fmt;
173
174impl fmt::Display for NodeValue {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 match self {
177 NodeValue::String(s) => write!(f, "{}", s),
178 NodeValue::Jid(j) => write!(f, "{}", j),
179 }
180 }
181}
182
183impl PartialEq<str> for NodeValue {
184 fn eq(&self, other: &str) -> bool {
185 match self {
186 NodeValue::String(s) => s == other,
187 NodeValue::Jid(j) => j.display_eq(other),
188 }
189 }
190}
191
192impl PartialEq<&str> for NodeValue {
193 fn eq(&self, other: &&str) -> bool {
194 self == *other
195 }
196}
197
198impl PartialEq<String> for NodeValue {
199 fn eq(&self, other: &String) -> bool {
200 self == other.as_str()
201 }
202}
203
204impl From<String> for NodeValue {
205 #[inline]
206 fn from(s: String) -> Self {
207 NodeValue::String(CompactString::from(s))
208 }
209}
210
211impl From<&str> for NodeValue {
212 #[inline]
213 fn from(s: &str) -> Self {
214 NodeValue::String(CompactString::from(s))
215 }
216}
217
218impl From<&String> for NodeValue {
219 #[inline]
220 fn from(s: &String) -> Self {
221 NodeValue::String(CompactString::from(s.as_str()))
222 }
223}
224
225impl From<CompactString> for NodeValue {
226 #[inline]
227 fn from(s: CompactString) -> Self {
228 NodeValue::String(s)
229 }
230}
231
232impl From<Jid> for NodeValue {
233 #[inline]
234 fn from(jid: Jid) -> Self {
235 NodeValue::Jid(jid)
236 }
237}
238
239impl From<&Jid> for NodeValue {
240 #[inline]
241 fn from(jid: &Jid) -> Self {
242 NodeValue::Jid(jid.clone())
243 }
244}
245
246macro_rules! impl_from_integer_for_nodevalue {
247 ($($t:ty),* $(,)?) => {
248 $(
249 impl From<$t> for NodeValue {
250 #[inline]
251 fn from(n: $t) -> Self {
252 let mut buf = itoa::Buffer::new();
253 NodeValue::String(CompactString::from(buf.format(n)))
254 }
255 }
256 )*
257 };
258}
259
260impl_from_integer_for_nodevalue!(
261 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
262);
263
264impl From<bool> for NodeValue {
265 #[inline]
266 fn from(b: bool) -> Self {
267 NodeValue::String(CompactString::from(if b { "true" } else { "false" }))
268 }
269}
270
271pub type AttrsVec = smallvec::SmallVec<[(Cow<'static, str>, NodeValue); 2]>;
278
279#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
286#[derive(Debug, Clone, PartialEq, Default)]
287pub struct Attrs(pub AttrsVec);
288
289impl Attrs {
290 #[inline]
291 pub fn new() -> Self {
292 Self(AttrsVec::new())
293 }
294
295 #[inline]
296 pub fn with_capacity(capacity: usize) -> Self {
297 Self(AttrsVec::with_capacity(capacity))
298 }
299
300 #[inline]
303 pub fn get(&self, key: &str) -> Option<&NodeValue> {
304 self.0.iter().find(|(k, _)| k == key).map(|(_, v)| v)
305 }
306
307 #[inline]
309 pub fn contains_key(&self, key: &str) -> bool {
310 self.0.iter().any(|(k, _)| k == key)
311 }
312
313 #[inline]
315 pub fn insert(&mut self, key: impl Into<Cow<'static, str>>, value: impl Into<NodeValue>) {
316 let key = key.into();
317 let value = value.into();
318 if let Some(pos) = self.0.iter().position(|(k, _)| k == &key) {
319 self.0[pos].1 = value;
320 } else {
321 self.0.push((key, value));
322 }
323 }
324
325 #[inline]
326 pub fn len(&self) -> usize {
327 self.0.len()
328 }
329
330 #[inline]
331 pub fn is_empty(&self) -> bool {
332 self.0.is_empty()
333 }
334
335 #[inline]
337 pub fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &NodeValue)> {
338 self.0.iter().map(|(k, v)| (k, v))
339 }
340
341 #[inline]
344 pub fn push(&mut self, key: impl Into<Cow<'static, str>>, value: impl Into<NodeValue>) {
345 self.0.push((key.into(), value.into()));
346 }
347
348 #[inline]
351 pub fn push_value(&mut self, key: impl Into<Cow<'static, str>>, value: NodeValue) {
352 self.0.push((key.into(), value));
353 }
354
355 #[inline]
357 pub fn keys(&self) -> impl Iterator<Item = &Cow<'static, str>> {
358 self.0.iter().map(|(k, _)| k)
359 }
360}
361
362impl IntoIterator for Attrs {
364 type Item = (Cow<'static, str>, NodeValue);
365 type IntoIter = smallvec::IntoIter<[(Cow<'static, str>, NodeValue); 2]>;
366
367 fn into_iter(self) -> Self::IntoIter {
368 self.0.into_iter()
369 }
370}
371
372impl<'a> IntoIterator for &'a Attrs {
374 type Item = (&'a Cow<'static, str>, &'a NodeValue);
375 type IntoIter = std::iter::Map<
376 std::slice::Iter<'a, (Cow<'static, str>, NodeValue)>,
377 fn(&'a (Cow<'static, str>, NodeValue)) -> (&'a Cow<'static, str>, &'a NodeValue),
378 >;
379
380 fn into_iter(self) -> Self::IntoIter {
381 self.0.iter().map(|(k, v)| (k, v))
382 }
383}
384
385impl FromIterator<(Cow<'static, str>, NodeValue)> for Attrs {
386 fn from_iter<I: IntoIterator<Item = (Cow<'static, str>, NodeValue)>>(iter: I) -> Self {
387 Self(iter.into_iter().collect())
388 }
389}
390#[derive(Debug, Clone)]
398pub enum AttrsRef<'a> {
399 Empty,
400 Slice(Box<[(NodeStr<'a>, ValueRef<'a>)]>),
401}
402
403impl PartialEq for AttrsRef<'_> {
404 fn eq(&self, other: &Self) -> bool {
405 self.as_slice() == other.as_slice()
406 }
407}
408
409impl<'a> AttrsRef<'a> {
410 pub fn from_vec(v: Vec<(NodeStr<'a>, ValueRef<'a>)>) -> Self {
413 if v.is_empty() {
414 Self::Empty
415 } else {
416 Self::Slice(v.into_boxed_slice())
417 }
418 }
419
420 #[inline]
421 pub fn len(&self) -> usize {
422 match self {
423 Self::Empty => 0,
424 Self::Slice(s) => s.len(),
425 }
426 }
427
428 #[inline]
429 pub fn is_empty(&self) -> bool {
430 self.as_slice().is_empty()
431 }
432
433 #[inline]
434 pub fn as_slice(&self) -> &[(NodeStr<'a>, ValueRef<'a>)] {
435 match self {
436 Self::Empty => &[],
437 Self::Slice(s) => s,
438 }
439 }
440
441 #[inline]
442 pub fn iter(&self) -> impl Iterator<Item = &(NodeStr<'a>, ValueRef<'a>)> {
443 self.as_slice().iter()
444 }
445}
446
447impl<'a> FromIterator<(NodeStr<'a>, ValueRef<'a>)> for AttrsRef<'a> {
448 fn from_iter<I: IntoIterator<Item = (NodeStr<'a>, ValueRef<'a>)>>(iter: I) -> Self {
449 Self::from_vec(iter.into_iter().collect())
450 }
451}
452
453fn _assert_attrs_ref_covariant<'short, 'long: 'short>(x: AttrsRef<'long>) -> AttrsRef<'short> {
456 x
457}
458
459unsafe impl<'a> yoke::Yokeable<'a> for AttrsRef<'static> {
465 type Output = AttrsRef<'a>;
466
467 fn transform(&'a self) -> &'a Self::Output {
468 self
469 }
470
471 fn transform_owned(self) -> Self::Output {
472 self
473 }
474
475 unsafe fn make(from: Self::Output) -> Self {
476 unsafe { std::mem::transmute(from) }
477 }
478
479 fn transform_mut<F>(&'a mut self, f: F)
480 where
481 F: 'static + for<'b> FnOnce(&'b mut Self::Output),
482 {
483 unsafe { f(std::mem::transmute::<&mut Self, &mut Self::Output>(self)) }
484 }
485}
486
487#[derive(Debug, Clone, PartialEq, yoke::Yokeable)]
491pub enum ValueRef<'a> {
492 String(NodeStr<'a>),
493 Jid(JidRef<'a>),
494}
495
496#[cfg(feature = "serde")]
497impl serde::Serialize for ValueRef<'_> {
498 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
499 match self {
500 ValueRef::String(s) => {
501 serializer.serialize_newtype_variant("NodeValue", 0, "String", &**s)
502 }
503 ValueRef::Jid(j) => serializer.serialize_newtype_variant("NodeValue", 1, "Jid", j),
504 }
505 }
506}
507
508impl<'a> ValueRef<'a> {
509 pub fn encode_value<W: crate::encoder::ByteWriter>(
511 &self,
512 encoder: &mut crate::encoder::Encoder<'_, W>,
513 ) -> crate::error::Result<()> {
514 match self {
515 ValueRef::String(s) => encoder.write_string(s),
516 ValueRef::Jid(jid) => encoder.write_jid_ref(jid),
517 }
518 }
519
520 pub fn as_str(&self) -> Cow<'_, str> {
524 match self {
525 ValueRef::String(s) => Cow::Borrowed(s),
526 ValueRef::Jid(j) => Cow::Owned(j.to_string()),
527 }
528 }
529
530 pub fn as_jid(&self) -> Option<&JidRef<'a>> {
532 match self {
533 ValueRef::Jid(j) => Some(j),
534 ValueRef::String(_) => None,
535 }
536 }
537
538 pub fn to_jid(&self) -> Option<Jid> {
540 match self {
541 ValueRef::Jid(j) => Some(j.to_owned()),
542 ValueRef::String(s) => Jid::from_str(s.as_ref()).ok(),
543 }
544 }
545
546 pub fn to_node_value(&self) -> NodeValue {
548 match self {
549 ValueRef::String(s) => NodeValue::String(s.to_compact_string()),
550 ValueRef::Jid(j) => NodeValue::Jid(j.to_owned()),
551 }
552 }
553}
554
555impl PartialEq<str> for ValueRef<'_> {
556 #[inline]
557 fn eq(&self, other: &str) -> bool {
558 match self {
559 ValueRef::String(value) => value == other,
560 ValueRef::Jid(value) => value.display_eq(other),
561 }
562 }
563}
564
565impl PartialEq<&str> for ValueRef<'_> {
566 #[inline]
567 fn eq(&self, other: &&str) -> bool {
568 self == *other
569 }
570}
571
572impl PartialEq<String> for ValueRef<'_> {
573 #[inline]
574 fn eq(&self, other: &String) -> bool {
575 self == other.as_str()
576 }
577}
578
579use std::str::FromStr;
580
581impl<'a> fmt::Display for ValueRef<'a> {
582 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583 match self {
584 ValueRef::String(s) => write!(f, "{}", s),
585 ValueRef::Jid(j) => write!(f, "{}", j),
586 }
587 }
588}
589
590pub type NodeVec<'a> = Vec<NodeRef<'a>>;
591
592#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
593#[derive(Debug, Clone, PartialEq)]
594pub enum NodeContent {
595 Bytes(Vec<u8>),
596 String(CompactString),
597 Nodes(Vec<Node>),
598}
599
600#[derive(Debug, Clone, PartialEq, yoke::Yokeable)]
601pub enum NodeContentRef<'a> {
602 Bytes(Cow<'a, [u8]>),
603 String(NodeStr<'a>),
604 Nodes(Box<[NodeRef<'a>]>),
605}
606
607#[cfg(feature = "serde")]
608impl serde::Serialize for NodeContentRef<'_> {
609 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
610 match self {
611 NodeContentRef::Bytes(b) => {
612 serializer.serialize_newtype_variant("NodeContent", 0, "Bytes", b.as_ref())
613 }
614 NodeContentRef::String(s) => {
615 serializer.serialize_newtype_variant("NodeContent", 1, "String", &**s)
616 }
617 NodeContentRef::Nodes(nodes) => {
618 serializer.serialize_newtype_variant("NodeContent", 2, "Nodes", &**nodes)
619 }
620 }
621 }
622}
623
624impl NodeContent {
625 pub fn as_content_ref(&self) -> NodeContentRef<'_> {
627 match self {
628 NodeContent::Bytes(b) => NodeContentRef::Bytes(Cow::Borrowed(b)),
629 NodeContent::String(s) => NodeContentRef::String(NodeStr::Borrowed(s.as_str())),
630 NodeContent::Nodes(nodes) => {
631 let v: Vec<_> = nodes.iter().map(|n| n.as_node_ref()).collect();
632 NodeContentRef::Nodes(v.into_boxed_slice())
633 }
634 }
635 }
636}
637
638#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
639#[derive(Debug, Clone, PartialEq, Default)]
640pub struct Node {
641 pub tag: Cow<'static, str>,
642 pub attrs: Attrs,
643 pub content: Option<NodeContent>,
644}
645
646#[derive(Debug, Clone, PartialEq, yoke::Yokeable)]
647pub struct NodeRef<'a> {
648 pub tag: NodeStr<'a>,
649 pub attrs: AttrsRef<'a>,
650 pub content: Option<NodeContentRef<'a>>,
651}
652
653impl Node {
654 pub fn new(
655 tag: impl Into<Cow<'static, str>>,
656 attrs: Attrs,
657 content: Option<NodeContent>,
658 ) -> Self {
659 Self {
660 tag: tag.into(),
661 attrs,
662 content,
663 }
664 }
665
666 pub fn as_node_ref(&self) -> NodeRef<'_> {
669 NodeRef {
670 tag: NodeStr::Borrowed(self.tag.as_ref()),
671 attrs: self
672 .attrs
673 .iter()
674 .map(|(k, v)| {
675 let value_ref = match v {
676 NodeValue::String(s) => ValueRef::String(NodeStr::Borrowed(s.as_str())),
677 NodeValue::Jid(j) => ValueRef::Jid(JidRef {
678 user: NodeStr::Borrowed(&j.user),
679 server: j.server,
680 agent: j.agent,
681 device: j.device,
682 integrator: j.integrator,
683 }),
684 };
685 (NodeStr::Borrowed(k.as_ref()), value_ref)
686 })
687 .collect(),
688 content: self.content.as_ref().map(|c| c.as_content_ref()),
689 }
690 }
691
692 pub fn children(&self) -> Option<&[Node]> {
693 match &self.content {
694 Some(NodeContent::Nodes(nodes)) => Some(nodes),
695 _ => None,
696 }
697 }
698
699 pub fn attrs(&self) -> AttrParser<'_> {
700 AttrParser::new(self)
701 }
702
703 pub fn get_optional_child_by_tag<'a>(&'a self, tags: &[&str]) -> Option<&'a Node> {
704 let mut current_node = self;
705 for &tag in tags {
706 let children = current_node.children()?;
707 current_node = children.iter().find(|c| c.tag == tag)?;
708 }
709 Some(current_node)
710 }
711
712 pub fn get_children_by_tag<'a>(&'a self, tag: &'a str) -> impl Iterator<Item = &'a Node> {
713 self.children()
717 .unwrap_or_default()
718 .iter()
719 .filter(move |c| c.tag == tag)
720 }
721
722 pub fn get_optional_child(&self, tag: &str) -> Option<&Node> {
723 self.children()
724 .and_then(|nodes| nodes.iter().find(|node| node.tag == tag))
725 }
726
727 pub fn content_as_string(&self) -> Option<CompactString> {
729 match &self.content {
730 Some(NodeContent::String(s)) => Some(s.clone()),
731 Some(NodeContent::Bytes(b)) => {
732 Some(CompactString::from(String::from_utf8_lossy(b).as_ref()))
733 }
734 _ => None,
735 }
736 }
737}
738
739#[cfg(feature = "serde")]
744struct AttrsRefWrapper<'a, 'b>(&'b AttrsRef<'a>);
745
746#[cfg(feature = "serde")]
747impl serde::Serialize for AttrsRefWrapper<'_, '_> {
748 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
749 serializer.serialize_newtype_struct("Attrs", self.0.as_slice())
750 }
751}
752
753#[cfg(feature = "serde")]
754impl serde::Serialize for NodeRef<'_> {
755 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
756 use serde::ser::SerializeStruct;
757 let mut s = serializer.serialize_struct("Node", 3)?;
758 s.serialize_field("tag", &*self.tag)?;
759 s.serialize_field("attrs", &AttrsRefWrapper(&self.attrs))?;
760 s.serialize_field("content", &self.content)?;
761 s.end()
762 }
763}
764
765impl<'a> NodeRef<'a> {
766 pub fn new(tag: NodeStr<'a>, attrs: AttrsRef<'a>, content: Option<NodeContentRef<'a>>) -> Self {
767 Self {
768 tag,
769 attrs,
770 content,
771 }
772 }
773
774 pub fn attrs(&self) -> AttrParserRef<'_> {
775 AttrParserRef::new(self)
776 }
777
778 pub fn children(&self) -> Option<&[NodeRef<'a>]> {
779 match self.content.as_ref() {
780 Some(NodeContentRef::Nodes(nodes)) => Some(nodes),
781 _ => None,
782 }
783 }
784
785 pub fn get_attr(&self, key: &str) -> Option<&ValueRef<'a>> {
786 self.attrs.iter().find(|(k, _)| k == key).map(|(_, v)| v)
787 }
788
789 pub fn attrs_iter(&self) -> impl Iterator<Item = (&NodeStr<'a>, &ValueRef<'a>)> {
790 self.attrs.iter().map(|(k, v)| (k, v))
791 }
792
793 pub fn get_optional_child_by_tag(&self, tags: &[&str]) -> Option<&NodeRef<'a>> {
794 let mut current_node = self;
795 for &tag in tags {
796 let children = current_node.children()?;
797 current_node = children.iter().find(|c| c.tag == tag)?;
798 }
799 Some(current_node)
800 }
801
802 pub fn get_children_by_tag<'b>(&'b self, tag: &'b str) -> impl Iterator<Item = &'b NodeRef<'a>>
803 where
804 'a: 'b,
805 {
806 self.children()
807 .unwrap_or_default()
808 .iter()
809 .filter(move |c| c.tag == tag)
810 }
811
812 pub fn get_optional_child(&self, tag: &str) -> Option<&NodeRef<'a>> {
813 self.children()
814 .and_then(|nodes| nodes.iter().find(|node| node.tag == tag))
815 }
816
817 pub fn content_as_string(&self) -> Option<CompactString> {
819 match self.content.as_ref() {
820 Some(NodeContentRef::String(s)) => Some(s.to_compact_string()),
821 Some(NodeContentRef::Bytes(b)) => Some(CompactString::from(
822 String::from_utf8_lossy(b.as_ref()).as_ref(),
823 )),
824 _ => None,
825 }
826 }
827
828 pub fn content_bytes(&self) -> Option<&[u8]> {
830 match self.content.as_ref() {
831 Some(NodeContentRef::Bytes(b)) => Some(b.as_ref()),
832 _ => None,
833 }
834 }
835
836 pub fn content_str(&self) -> Option<&str> {
838 match self.content.as_ref() {
839 Some(NodeContentRef::String(s)) => Some(s.as_ref()),
840 _ => None,
841 }
842 }
843
844 #[inline]
847 pub fn content_nodes(&self) -> Option<&[NodeRef<'a>]> {
848 self.children()
849 }
850
851 pub fn to_owned(&self) -> Node {
852 Node {
853 tag: intern_cow(&self.tag),
854 attrs: self
855 .attrs
856 .iter()
857 .map(|(k, v)| {
858 let value = match v {
859 ValueRef::String(s) => NodeValue::String(s.to_compact_string()),
860 ValueRef::Jid(j) => NodeValue::Jid(j.to_owned()),
861 };
862 (intern_cow(k), value)
863 })
864 .collect::<Attrs>(),
865 content: self.content.as_ref().map(|c| match c {
866 NodeContentRef::Bytes(b) => NodeContent::Bytes(b.to_vec()),
867 NodeContentRef::String(s) => NodeContent::String(s.to_compact_string()),
868 NodeContentRef::Nodes(nodes) => {
869 NodeContent::Nodes(nodes.iter().map(|n| n.to_owned()).collect())
870 }
871 }),
872 }
873 }
874}
875
876use yoke::Yoke;
881
882#[derive(Clone)]
883struct BytesCart(Bytes);
884
885impl std::ops::Deref for BytesCart {
886 type Target = [u8];
887
888 fn deref(&self) -> &Self::Target {
889 self.0.as_ref()
890 }
891}
892
893unsafe impl StableDeref for BytesCart {}
896
897pub struct OwnedNodeRef {
903 inner: Yoke<NodeRef<'static>, BytesCart>,
904}
905
906impl OwnedNodeRef {
907 pub fn new(buffer: impl Into<Bytes>) -> crate::error::Result<Self> {
911 let inner = Yoke::try_attach_to_cart(BytesCart(buffer.into()), |buf| {
912 crate::marshal::unmarshal_ref(buf)
913 })?;
914 Ok(Self { inner })
915 }
916
917 #[inline]
919 pub fn get(&self) -> &NodeRef<'_> {
920 self.inner.get()
921 }
922
923 pub fn to_owned_node(&self) -> Node {
926 self.inner.get().to_owned()
927 }
928
929 pub fn slice_bytes(&self, slice: &[u8]) -> Bytes {
932 let cart = &self.inner.backing_cart().0;
933 let base = cart.as_ptr() as usize;
934 let end = base + cart.len();
935 let ptr = slice.as_ptr() as usize;
936 assert!(
937 ptr >= base && ptr + slice.len() <= end,
938 "slice is not within the backing buffer"
939 );
940 let offset = ptr - base;
941 cart.slice(offset..offset + slice.len())
942 }
943
944 #[inline]
946 pub fn tag(&self) -> &str {
947 &self.get().tag
948 }
949
950 #[inline]
952 pub fn attrs(&self) -> AttrParserRef<'_> {
953 self.get().attrs()
954 }
955
956 #[inline]
958 pub fn get_attr(&self, key: &str) -> Option<&ValueRef<'_>> {
959 self.get().get_attr(key)
960 }
961
962 #[inline]
964 pub fn children(&self) -> Option<&[NodeRef<'_>]> {
965 self.get().children()
966 }
967
968 #[inline]
970 pub fn get_optional_child(&self, tag: &str) -> Option<&NodeRef<'_>> {
971 self.get().get_optional_child(tag)
972 }
973
974 #[inline]
976 pub fn get_optional_child_by_tag(&self, tags: &[&str]) -> Option<&NodeRef<'_>> {
977 self.get().get_optional_child_by_tag(tags)
978 }
979
980 #[inline]
982 pub fn get_children_by_tag<'b>(
983 &'b self,
984 tag: &'b str,
985 ) -> impl Iterator<Item = &'b NodeRef<'b>> {
986 self.get().get_children_by_tag(tag)
987 }
988
989 #[inline]
991 pub fn content_bytes(&self) -> Option<&[u8]> {
992 self.get().content_bytes()
993 }
994
995 #[inline]
997 pub fn content_str(&self) -> Option<&str> {
998 self.get().content_str()
999 }
1000
1001 #[inline]
1003 pub fn content_nodes(&self) -> Option<&[NodeRef<'_>]> {
1004 self.get().content_nodes()
1005 }
1006
1007 #[inline]
1009 pub fn content_as_string(&self) -> Option<CompactString> {
1010 self.get().content_as_string()
1011 }
1012}
1013
1014#[cfg(test)]
1015mod value_ref_compare_tests {
1016 use super::*;
1017 use crate::jid::Server;
1018 use std::str::FromStr;
1019
1020 #[test]
1025 fn comparing_a_jid_value_matches_comparing_its_rendered_form() {
1026 let jids = [
1027 "s.whatsapp.net",
1028 "5511999998888@s.whatsapp.net",
1029 "5511999998888:7@s.whatsapp.net",
1030 "5511999998888.2@s.whatsapp.net",
1031 "120363012345678901@g.us",
1032 "123456789012345@lid",
1033 "123456789012345:9@lid",
1034 "123456789.4:17@interop",
1035 "status@broadcast",
1036 "12345.6@hosted.lid",
1037 ];
1038 let needles = [
1039 "s.whatsapp.net",
1040 "5511999998888@s.whatsapp.net",
1041 "5511999998888:7@s.whatsapp.net",
1042 "123456789012345@lid",
1043 "",
1044 "not-a-jid",
1045 ];
1046
1047 for raw in jids {
1048 let owned = Jid::from_str(raw).unwrap_or_else(|e| panic!("{raw}: {e}"));
1049 let borrowed = ValueRef::Jid(JidRef {
1050 user: NodeStr::Borrowed(&owned.user),
1051 server: owned.server,
1052 agent: owned.agent,
1053 device: owned.device,
1054 integrator: owned.integrator,
1055 });
1056 let as_string = ValueRef::String(NodeStr::Borrowed(raw));
1057
1058 for needle in needles {
1059 assert_eq!(
1060 borrowed.as_str() == needle,
1061 borrowed == needle,
1062 "jid value {raw:?} vs {needle:?}"
1063 );
1064 assert_eq!(
1065 as_string.as_str() == needle,
1066 as_string == needle,
1067 "string value {raw:?} vs {needle:?}"
1068 );
1069 }
1070 }
1071
1072 let server_only = ValueRef::Jid(JidRef {
1074 user: NodeStr::Borrowed(""),
1075 server: Server::Pn,
1076 agent: 0,
1077 device: 0,
1078 integrator: 0,
1079 });
1080 assert!(server_only == "s.whatsapp.net");
1081 assert!(server_only != "5511999998888@s.whatsapp.net");
1082 }
1083}
1084
1085#[cfg(test)]
1086mod owned_node_ref_tests {
1087 use super::*;
1088
1089 fn encoded(node: &Node) -> Bytes {
1092 let bytes = crate::marshal::marshal(node).unwrap();
1093 Bytes::from(bytes[1..].to_vec())
1094 }
1095
1096 fn sample() -> Node {
1097 Node::new(
1098 "iq",
1099 Attrs(vec![(Cow::Borrowed("id"), NodeValue::String("abc".into()))].into()),
1100 Some(NodeContent::Bytes(b"payload".to_vec())),
1101 )
1102 }
1103
1104 #[test]
1105 fn borrowed_payloads_survive_moving_the_cart() {
1106 let node = sample();
1107 let owned = OwnedNodeRef::new(encoded(&node)).unwrap();
1108
1109 let mut moved = vec![*Box::new(owned)];
1116 let owned = moved.pop().unwrap();
1117
1118 assert_eq!(owned.tag(), "iq");
1119 assert!(owned.get_attr("id").unwrap() == "abc");
1120 assert_eq!(owned.content_bytes(), Some(&b"payload"[..]));
1121 assert_eq!(owned.to_owned_node(), node);
1122 }
1123
1124 #[test]
1125 fn yoked_attrs_ref_survives_make_transform_and_mutation() {
1126 let cart = BytesCart(Bytes::from_static(b"idabc"));
1133 let mut yoke: Yoke<AttrsRef<'static>, BytesCart> = Yoke::attach_to_cart(cart, |buf| {
1134 let (key, value) = buf.split_at(2);
1136 AttrsRef::from_vec(vec![(
1137 NodeStr::Borrowed(std::str::from_utf8(key).expect("ascii")),
1138 ValueRef::String(NodeStr::Borrowed(
1139 std::str::from_utf8(value).expect("ascii"),
1140 )),
1141 )])
1142 });
1143
1144 let (key, value) = &yoke.get().as_slice()[0];
1146 assert!(*key == "id");
1147 assert!(*value == "abc");
1148
1149 yoke.with_mut(|attrs| {
1151 *attrs = AttrsRef::from_vec(vec![(
1152 NodeStr::Owned("k".into()),
1153 ValueRef::String(NodeStr::Owned("v".into())),
1154 )]);
1155 });
1156 assert!(yoke.get().as_slice()[0].1 == "v");
1157 }
1158
1159 #[test]
1160 fn slice_bytes_views_the_backing_buffer_without_copying() {
1161 let owned = OwnedNodeRef::new(encoded(&sample())).unwrap();
1162 let content = owned.content_bytes().unwrap();
1163
1164 let view = owned.slice_bytes(content);
1165
1166 assert_eq!(view.as_ref(), b"payload");
1167 assert_eq!(view.as_ptr(), content.as_ptr(), "slice_bytes copied");
1168 }
1169}
1170
1171#[cfg(feature = "serde")]
1172impl serde::Serialize for OwnedNodeRef {
1173 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1174 self.get().serialize(serializer)
1175 }
1176}
1177
1178impl fmt::Debug for OwnedNodeRef {
1179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1180 self.inner.get().fmt(f)
1181 }
1182}
1183
1184#[cfg(test)]
1185mod value_ref_tests {
1186 use super::*;
1187 use crate::jid::Server;
1188
1189 #[test]
1190 fn value_ref_compares_string_and_jid_display_without_conversion() {
1191 let string = ValueRef::String(NodeStr::Borrowed("encrypt"));
1192 assert!(string == "encrypt");
1193 assert!(string != "other");
1194
1195 let jid = ValueRef::Jid(JidRef {
1196 user: NodeStr::Borrowed("12025550111"),
1197 server: Server::Pn,
1198 agent: 0,
1199 device: 7,
1200 integrator: 0,
1201 });
1202 assert!(jid == "12025550111:7@s.whatsapp.net");
1203 assert!(jid != "12025550111@s.whatsapp.net");
1204 }
1205}
1206
1207#[cfg(test)]
1208#[cfg(feature = "serde")]
1209mod serde_tests {
1210 use super::*;
1211 use crate::jid::{Jid, Server};
1212
1213 #[test]
1214 fn node_ref_serializes_same_as_node() {
1215 let node = Node::new(
1216 Cow::Borrowed("message"),
1217 Attrs(
1218 vec![
1219 (Cow::Borrowed("type"), NodeValue::String("text".into())),
1220 (Cow::Borrowed("from"), NodeValue::Jid(Jid::pn("5550199999"))),
1221 ]
1222 .into(),
1223 ),
1224 Some(NodeContent::String("hello".into())),
1225 );
1226 let node_ref = node.as_node_ref();
1227
1228 let owned_json = serde_json::to_value(&node).unwrap();
1229 let ref_json = serde_json::to_value(&node_ref).unwrap();
1230 assert_eq!(owned_json, ref_json);
1231 }
1232
1233 #[test]
1234 fn nested_nodes_serialize_same() {
1235 let child = Node::new(Cow::Borrowed("item"), Attrs::new(), None);
1236 let parent = Node::new(
1237 Cow::Borrowed("list"),
1238 Attrs::new(),
1239 Some(NodeContent::Nodes(vec![child])),
1240 );
1241 let parent_ref = parent.as_node_ref();
1242
1243 assert_eq!(
1244 serde_json::to_value(&parent).unwrap(),
1245 serde_json::to_value(&parent_ref).unwrap(),
1246 );
1247 }
1248
1249 #[test]
1250 fn bytes_content_serializes_same() {
1251 let node = Node::new(
1252 Cow::Borrowed("iq"),
1253 Attrs(vec![(Cow::Borrowed("id"), NodeValue::String("1".into()))].into()),
1254 Some(NodeContent::Bytes(vec![0xDE, 0xAD])),
1255 );
1256 let node_ref = node.as_node_ref();
1257
1258 let owned_json = serde_json::to_value(&node).unwrap();
1259 let ref_json = serde_json::to_value(&node_ref).unwrap();
1260 assert_eq!(owned_json, ref_json);
1261 }
1262
1263 #[test]
1264 fn value_ref_matches_node_value() {
1265 let string_val = NodeValue::String("hello".into());
1266 let string_ref = ValueRef::String(NodeStr::Borrowed("hello"));
1267 assert_eq!(
1268 serde_json::to_value(&string_val).unwrap(),
1269 serde_json::to_value(&string_ref).unwrap(),
1270 );
1271
1272 let jid = Jid {
1273 user: "5550199999".into(),
1274 server: Server::Group,
1275 agent: 1,
1276 device: 2,
1277 integrator: 3,
1278 };
1279 let jid_val = NodeValue::Jid(jid.clone());
1280 let jid_ref_val = ValueRef::Jid(JidRef {
1281 user: NodeStr::Borrowed("5550199999"),
1282 server: Server::Group,
1283 agent: 1,
1284 device: 2,
1285 integrator: 3,
1286 });
1287 assert_eq!(
1288 serde_json::to_value(&jid_val).unwrap(),
1289 serde_json::to_value(&jid_ref_val).unwrap(),
1290 );
1291 }
1292
1293 #[test]
1294 fn owned_node_ref_serializes_same_as_owned() {
1295 let node = Node::new(
1296 Cow::Borrowed("iq"),
1297 Attrs(vec![(Cow::Borrowed("id"), NodeValue::String("abc".into()))].into()),
1298 Some(NodeContent::String("payload".into())),
1299 );
1300
1301 let bytes = crate::marshal::marshal(&node).unwrap();
1302 let owned_ref = OwnedNodeRef::new(Bytes::from(bytes[1..].to_vec())).unwrap();
1304
1305 let from_ref = serde_json::to_value(&owned_ref).unwrap();
1306 let from_owned = serde_json::to_value(owned_ref.to_owned_node()).unwrap();
1307 assert_eq!(from_ref, from_owned);
1308 }
1309}