use crate::Reader;
#[derive(Debug, PartialEq)]
pub enum ElementAttributeToken<'a> {
String(&'a str),
Equal,
}
const DOUBLEQUOTE: u8 = b'"';
const SINGLEQUOTE: u8 = b'\'';
const EQUAL: u8 = b'=';
const END_OF_ELEMENT: u8 = b'>';
const WHITESPACE: [u8; 5] = [b' ', b'\t', b'\n', 0x0C, b'\r'];
const WORD_BOUNDARIES: [u8; 9] = [
b' ',
b'\t',
b'\n',
0x0C,
b'\r',
DOUBLEQUOTE,
SINGLEQUOTE,
EQUAL,
END_OF_ELEMENT,
];
impl<'a> ElementAttributeToken<'a> {
pub fn next(reader: &mut Reader<'a>, in_value: bool) -> Option<Self> {
reader.next_while_list(&WHITESPACE);
let start_pos = reader.get_position();
match reader.next()? {
DOUBLEQUOTE => {
let star_position = reader.get_position();
reader.next_until(DOUBLEQUOTE);
let content_inside_quotes = reader.slice(star_position..reader.get_position());
reader.skip();
Some(Self::String(content_inside_quotes))
}
SINGLEQUOTE => {
let star_position = reader.get_position();
reader.next_until(SINGLEQUOTE);
let content_inside_quotes = reader.slice(star_position..reader.get_position());
reader.skip();
Some(Self::String(content_inside_quotes))
}
EQUAL => Some(Self::Equal),
END_OF_ELEMENT => None,
_ => {
reader.next_until_list(&WORD_BOUNDARIES);
let word = reader.slice(start_pos..reader.get_position());
if !in_value
&& reader.peek() == Some(END_OF_ELEMENT)
&& let Some(stripped) = word.strip_suffix('/')
{
if stripped.is_empty() {
reader.skip();
return None;
}
return Some(Self::String(stripped));
}
Some(Self::String(word))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_attribute_iterator() {
let string: String = String::from("key=\"value\"");
let mut reader = Reader::new(&string);
let mut next_iter = ElementAttributeToken::next(&mut reader, false);
assert!(next_iter.is_some());
let mut next_value = next_iter.unwrap();
assert_eq!(next_value, ElementAttributeToken::String("key"));
next_iter = ElementAttributeToken::next(&mut reader, false);
assert!(next_iter.is_some());
next_value = next_iter.unwrap();
assert_eq!(next_value, ElementAttributeToken::Equal);
next_iter = ElementAttributeToken::next(&mut reader, true);
assert!(next_iter.is_some());
next_value = next_iter.unwrap();
assert_eq!(next_value, ElementAttributeToken::String("value"));
}
}