123 lines
2.6 KiB
Rust
123 lines
2.6 KiB
Rust
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<String>`
|
|
pub fn generate_hint<'a>(input: &str) -> &'a Hint<'a> {
|
|
if input.is_empty() {
|
|
return &HINT_EMPTY;
|
|
}
|
|
|
|
let chars: Vec<char> = input.chars().collect::<Vec<char>>();
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|