node.rs

  1// Copyright (c) 2020 lumi <lumi@pew.im>
  2// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  3// Copyright (c) 2020 Maxime “pep” Buquet <pep@bouah.net>
  4//
  5// This Source Code Form is subject to the terms of the Mozilla Public
  6// License, v. 2.0. If a copy of the MPL was not distributed with this
  7// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8
  9//! Provides the `Node` struct, which represents a node in the DOM.
 10
 11use crate::element::{Element, ElementBuilder, ItemWriter};
 12use crate::error::Result;
 13
 14use rxml::writer::Item;
 15
 16use std::convert::TryInto;
 17use std::io::Write;
 18
 19/// A node in an element tree.
 20#[derive(Clone, Debug, Eq)]
 21pub enum Node {
 22    /// An `Element`.
 23    Element(Element),
 24    /// A text node.
 25    Text(String),
 26}
 27
 28impl Node {
 29    /// Turns this into a reference to an `Element` if this is an element node.
 30    /// Else this returns `None`.
 31    ///
 32    /// # Examples
 33    ///
 34    /// ```rust
 35    /// use minidom::Node;
 36    ///
 37    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
 38    /// let txt = Node::Text("meow".to_owned());
 39    ///
 40    /// assert_eq!(elm.as_element().unwrap().name(), "meow");
 41    /// assert_eq!(txt.as_element(), None);
 42    /// ```
 43    pub fn as_element(&self) -> Option<&Element> {
 44        match *self {
 45            Node::Element(ref e) => Some(e),
 46            Node::Text(_) => None,
 47        }
 48    }
 49
 50    /// Turns this into a mutable reference of an `Element` if this is an element node.
 51    /// Else this returns `None`.
 52    ///
 53    /// # Examples
 54    ///
 55    /// ```rust
 56    /// use minidom::Node;
 57    ///
 58    /// let mut elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
 59    /// let mut txt = Node::Text("meow".to_owned());
 60    ///
 61    /// assert_eq!(elm.as_element_mut().unwrap().name(), "meow");
 62    /// assert_eq!(txt.as_element_mut(), None);
 63    /// ```
 64    pub fn as_element_mut(&mut self) -> Option<&mut Element> {
 65        match *self {
 66            Node::Element(ref mut e) => Some(e),
 67            Node::Text(_) => None,
 68        }
 69    }
 70
 71    /// Turns this into an `Element`, consuming self, if this is an element node.
 72    /// Else this returns `None`.
 73    ///
 74    /// # Examples
 75    ///
 76    /// ```rust
 77    /// use minidom::Node;
 78    ///
 79    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
 80    /// let txt = Node::Text("meow".to_owned());
 81    ///
 82    /// assert_eq!(elm.into_element().unwrap().name(), "meow");
 83    /// assert_eq!(txt.into_element(), None);
 84    /// ```
 85    pub fn into_element(self) -> Option<Element> {
 86        match self {
 87            Node::Element(e) => Some(e),
 88            Node::Text(_) => None,
 89        }
 90    }
 91
 92    /// Turns this into an `&str` if this is a text node.
 93    /// Else this returns `None`.
 94    ///
 95    /// # Examples
 96    ///
 97    /// ```rust
 98    /// use minidom::Node;
 99    ///
100    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
101    /// let txt = Node::Text("meow".to_owned());
102    ///
103    /// assert_eq!(elm.as_text(), None);
104    /// assert_eq!(txt.as_text().unwrap(), "meow");
105    /// ```
106    pub fn as_text(&self) -> Option<&str> {
107        match *self {
108            Node::Element(_) => None,
109            Node::Text(ref s) => Some(s),
110        }
111    }
112
113    /// Turns this into an `&mut String` if this is a text node.
114    /// Else this returns `None`.
115    ///
116    /// # Examples
117    ///
118    /// ```rust
119    /// use minidom::Node;
120    ///
121    /// let mut elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
122    /// let mut txt = Node::Text("meow".to_owned());
123    ///
124    /// assert_eq!(elm.as_text_mut(), None);
125    /// {
126    ///     let text_mut = txt.as_text_mut().unwrap();
127    ///     assert_eq!(text_mut, "meow");
128    ///     text_mut.push_str("zies");
129    ///     assert_eq!(text_mut, "meowzies");
130    /// }
131    /// assert_eq!(txt.as_text().unwrap(), "meowzies");
132    /// ```
133    pub fn as_text_mut(&mut self) -> Option<&mut String> {
134        match *self {
135            Node::Element(_) => None,
136            Node::Text(ref mut s) => Some(s),
137        }
138    }
139
140    /// Turns this into an `String`, consuming self, if this is a text node.
141    /// Else this returns `None`.
142    ///
143    /// # Examples
144    ///
145    /// ```rust
146    /// use minidom::Node;
147    ///
148    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
149    /// let txt = Node::Text("meow".to_owned());
150    ///
151    /// assert_eq!(elm.into_text(), None);
152    /// assert_eq!(txt.into_text().unwrap(), "meow");
153    /// ```
154    pub fn into_text(self) -> Option<String> {
155        match self {
156            Node::Element(_) => None,
157            Node::Text(s) => Some(s),
158        }
159    }
160
161    #[doc(hidden)]
162    pub(crate) fn write_to_inner<W: Write>(&self, writer: &mut ItemWriter<W>) -> Result<()> {
163        match *self {
164            Node::Element(ref elmt) => elmt.write_to_inner(writer)?,
165            Node::Text(ref s) => {
166                writer.write(Item::Text((&**s).try_into()?))?;
167            }
168        }
169
170        Ok(())
171    }
172}
173
174impl<I> From<I> for Node
175where
176    I: Into<Element>,
177{
178    fn from(elm: I) -> Node {
179        Node::Element(elm.into())
180    }
181}
182
183impl From<String> for Node {
184    fn from(s: String) -> Node {
185        Node::Text(s)
186    }
187}
188
189impl<'a> From<&'a str> for Node {
190    fn from(s: &'a str) -> Node {
191        Node::Text(s.to_owned())
192    }
193}
194
195impl From<ElementBuilder> for Node {
196    fn from(builder: ElementBuilder) -> Node {
197        Node::Element(builder.build())
198    }
199}
200
201impl PartialEq for Node {
202    fn eq(&self, other: &Self) -> bool {
203        match (self, other) {
204            (&Node::Element(ref elem1), &Node::Element(ref elem2)) => elem1 == elem2,
205            (&Node::Text(ref text1), &Node::Text(ref text2)) => text1 == text2,
206            _ => false,
207        }
208    }
209}