#[derive(Clone, Debug)]
pub struct SelectorState {
pub tag: String,
pub classes: Option<Vec<String>>,
pub id: Option<String>,
pub attributes: Option<Vec<String>>,
}
impl SelectorState {
pub fn try_save(&mut self, mode: ParserMode, mut buffer: String) -> String {
match mode {
ParserMode::None => {
if self.tag.is_empty() {
self.tag = buffer;
buffer = String::new();
}
}
ParserMode::Class => {
if self.classes.is_none() {
self.classes = Some(vec![buffer]);
buffer = String::new();
} else if let Some(ref mut classes) = self.classes {
classes.push(buffer);
buffer = String::new();
}
}
ParserMode::Id => {
if self.id.is_none() {
self.id = Some(buffer);
buffer = String::new();
}
}
ParserMode::Attribute => {
if self.attributes.is_none() {
self.attributes = Some(vec![buffer]);
buffer = String::new();
} else if let Some(ref mut attributes) = self.attributes {
attributes.push(buffer);
buffer = String::new();
}
}
}
buffer
}
pub fn render(self) -> String {
let mut class_string = String::new();
let mut id_string = String::new();
let mut attributes_string = String::new();
if let Some(classes) = self.classes {
class_string = " class=\"".to_string();
for class in classes {
class_string.push_str(&(class + " "));
}
class_string += "\"";
}
if let Some(id) = self.id {
id_string = format!(" id=\"{id}\"");
}
if let Some(attributes) = self.attributes {
for attribute in attributes {
attributes_string.push_str(&format!(" {attribute}"));
}
}
format!("<{}{class_string}{id_string}{attributes_string}>", self.tag)
}
}
#[derive(PartialEq, Eq)]
pub enum ParserMode {
None,
Class,
Id,
Attribute,
}
pub struct Selector(String);
impl Selector {
pub fn new(input: String) -> Self {
Self(input)
}
pub fn parse(self) -> SelectorState {
let mut state = SelectorState {
tag: String::new(),
classes: None,
id: None,
attributes: None,
};
let mut chars = self.0.chars();
let mut mode: ParserMode = ParserMode::None;
let mut buffer: String = String::new();
while let Some(char) = chars.next() {
match char {
'.' => {
if mode == ParserMode::Attribute {
buffer.push(char);
continue;
}
buffer = state.try_save(mode, buffer.clone());
mode = ParserMode::Class
}
'#' => {
if mode == ParserMode::Attribute {
buffer.push(char);
continue;
}
buffer = state.try_save(mode, buffer.clone());
mode = ParserMode::Id
}
'[' => {
buffer = state.try_save(mode, buffer.clone());
mode = ParserMode::Attribute
}
']' => {
buffer = state.try_save(mode, buffer.clone());
mode = ParserMode::None
}
_ => buffer.push(char),
}
}
state.try_save(mode, buffer.clone()); state
}
}