use crate::misc::chars_take; pub const HINT_EMPTY: Hint = Hint::Single("x^2"); const HINT_CLOSED_PARENS: Hint = Hint::Single(")"); /// Generate a hint based on the input `input`, returns an `Option` pub fn generate_hint<'a>(input: &str) -> &'a Hint<'a> { if input.is_empty() { return &HINT_EMPTY; } let chars: Vec = input.chars().collect::>(); let mut open_parens: usize = 0; let mut closed_parens: usize = 0; chars.iter().for_each(|chr| match *chr { '(' => open_parens += 1, ')' => closed_parens += 1, _ => {} }); if open_parens > closed_parens { return &HINT_CLOSED_PARENS; } let len = chars.len(); for key in (1..=MAX_COMPLETION_LEN) .rev() .filter(|i| len >= *i) .map(|i| chars_take(&chars, i)) .filter(|cut_string| !cut_string.is_empty()) { if let Some(output) = COMPLETION_HASHMAP.get(&key) { return output; } } &Hint::None } #[derive(PartialEq)] pub enum Hint<'a> { Single(&'a str), Many(&'a [&'a str]), None, } impl<'a> std::fmt::Debug for Hint<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self) } } impl<'a> std::fmt::Display for Hint<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Hint::Single(single_data) => { return write!(f, "{}", single_data); } Hint::Many(multi_data) => { return write!(f, "{:?}", multi_data); } Hint::None => { return write!(f, "None"); } } } } impl<'a> Hint<'a> { pub fn is_none(&self) -> bool { matches!(self, Hint::None) } #[allow(dead_code)] pub fn is_some(&self) -> bool { !self.is_none() } #[allow(dead_code)] pub fn is_single(&self) -> bool { matches!(self, Hint::Single(_)) } } include!(concat!(env!("OUT_DIR"), "/codegen.rs")); #[cfg(test)] mod tests { use std::collections::HashMap; use super::*; /// Tests to make sure hints are properly outputed based on input #[test] fn hint_test() { let values = HashMap::from([ ("", Hint::Single("x^2")), ("si", Hint::Many(&["n(", "nh(", "gnum("])), ("log", Hint::Many(&["2(", "10("])), ("cos", Hint::Many(&["(", "h("])), ("sin(", Hint::Single(")")), ("sqrt", Hint::Single("(")), ("ln(x)", Hint::None), ]); for (key, value) in values { println!("{} + {:?}", key, value); assert_eq!(generate_hint(key), &value); } } #[test] fn hint_to_string_test() { let values = HashMap::from([ ("x^2", Hint::Single("x^2")), ( r#"["n(", "nh(", "gnum("]"#, Hint::Many(&["n(", "nh(", "gnum("]), ), (r#"["n("]"#, Hint::Many(&["n("])), ("None", Hint::None), ]); for (key, value) in values { assert_eq!(value.to_string(), key); } } }