#![forbid(unsafe_code)]
#[derive(Debug)]
pub enum HtmlEvent<'a> {
StartElement {
name: &'a str,
attributes: HtmlAttrs<'a>,
},
EndElement {
name: &'a str,
},
Text(&'a str),
Comment(&'a str),
Doctype {
name: &'a str,
public_id: &'a str,
system_id: &'a str,
},
Eof,
}
#[derive(Debug, Clone, Copy)]
pub struct HtmlAttrs<'a> {
pub(crate) inner: &'a [OwnedAttr],
}
impl<'a> HtmlAttrs<'a> {
pub fn iter(&self) -> HtmlAttrsIter<'a> {
HtmlAttrsIter {
slice: self.inner,
pos: 0,
}
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn get(&self, name: &str) -> Option<&'a str> {
self.inner
.iter()
.find(|a| a.name == name)
.map(|a| a.value.as_str())
}
}
pub struct HtmlAttrsIter<'a> {
slice: &'a [OwnedAttr],
pos: usize,
}
impl<'a> Iterator for HtmlAttrsIter<'a> {
type Item = HtmlAttribute<'a>;
fn next(&mut self) -> Option<HtmlAttribute<'a>> {
let a = self.slice.get(self.pos)?;
self.pos += 1;
Some(HtmlAttribute {
name: &a.name,
value: &a.value,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let rem = self.slice.len() - self.pos;
(rem, Some(rem))
}
}
impl<'a> ExactSizeIterator for HtmlAttrsIter<'a> {}
#[derive(Debug, Clone, Copy)]
pub struct HtmlAttribute<'a> {
pub name: &'a str,
pub value: &'a str,
}
use crate::error::XmlError;
#[derive(Debug)]
pub(crate) enum OwnedEvent {
StartElement {
name: String,
attrs: Vec<OwnedAttr>,
},
EndElement {
name: String,
},
Text(String),
Comment(String),
Doctype {
name: String,
public_id: String,
system_id: String,
},
ParseError(XmlError),
Eof,
}
#[derive(Debug)]
pub(crate) struct OwnedAttr {
pub name: String,
pub value: String,
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_attrs() -> Vec<OwnedAttr> {
vec![
OwnedAttr { name: "id".into(), value: "main".into() },
OwnedAttr { name: "class".into(), value: "x y".into() },
]
}
#[test]
fn html_attrs_len_and_is_empty() {
let attrs = sample_attrs();
let v = HtmlAttrs { inner: &attrs };
assert_eq!(v.len(), 2);
assert!(!v.is_empty());
let empty: Vec<OwnedAttr> = Vec::new();
let v2 = HtmlAttrs { inner: &empty };
assert_eq!(v2.len(), 0);
assert!(v2.is_empty());
}
#[test]
fn html_attrs_iter_yields_in_source_order() {
let attrs = sample_attrs();
let v = HtmlAttrs { inner: &attrs };
let names: Vec<&str> = v.iter().map(|a| a.name).collect();
assert_eq!(names, vec!["id", "class"]);
let values: Vec<&str> = v.iter().map(|a| a.value).collect();
assert_eq!(values, vec!["main", "x y"]);
}
#[test]
fn html_attrs_iter_size_hint_exact() {
let attrs = sample_attrs();
let v = HtmlAttrs { inner: &attrs };
let mut it = v.iter();
assert_eq!(it.size_hint(), (2, Some(2)));
let _ = it.next();
assert_eq!(it.size_hint(), (1, Some(1)));
assert_eq!(it.len(), 1);
let _ = it.next();
assert_eq!(it.size_hint(), (0, Some(0)));
assert!(it.next().is_none());
}
#[test]
fn html_attrs_get_finds_by_lowercase_name() {
let attrs = sample_attrs();
let v = HtmlAttrs { inner: &attrs };
assert_eq!(v.get("id"), Some("main"));
assert_eq!(v.get("class"), Some("x y"));
assert_eq!(v.get("missing"), None);
}
#[test]
fn html_attrs_is_copy() {
let attrs = sample_attrs();
let v = HtmlAttrs { inner: &attrs };
let v2 = v; let v3 = v; assert_eq!(v2.len(), v3.len());
}
}