use regex::Regex; use std::iter::Peekable; use super::parser; #[derive(Debug)] pub enum QueryToken { Regex(Regex), Must(String), None(String), Plain(String), } #[derive(Debug)] pub struct Query { /// Query string that user provided. pub full: String, /// "keyword" pub musts: Vec, /// -keyword pub nones: Vec, /// `(some|regex)` pub regexes: Vec, /// full - (musts + nones + regexes). Used for fuzzy searching. pub rest: Vec, } impl Query { pub fn new(input: &str) -> Query { let full = input.to_string(); let mut musts = vec![]; let mut nones = vec![]; let mut regexes = vec![]; let mut rest = vec![]; let iter = &mut full.chars().peekable(); while let Some(x) = Query::tokenize_single(iter) { match x { QueryToken::Regex(r) => regexes.push(r), QueryToken::Plain(r) => rest.push(r), QueryToken::Must(r) => musts.push(r), QueryToken::None(r) => nones.push(r), } } Query { full, musts, nones, regexes, rest } } pub fn tokenize_single(iter: &mut Peekable) -> Option where I: Iterator { while parser::parse_whitespace(iter) { continue } parser::parse_around(iter, '"', '"').map(QueryToken::Must) .or_else(|| parser::parse_around(iter, '`', '`').map(|x| QueryToken::Regex(Regex::new(&x).unwrap()))) .or_else(|| parser::parse_prefixed(iter, '-').map(QueryToken::None)) .or_else(|| parser::parse_plain(iter).map(QueryToken::Plain)) } }