1#[cfg(not(feature = "std"))]
11use alloc::format;
12#[cfg(not(feature = "std"))]
13use alloc::string::{String, ToString};
14
15use crate::collections::HashMap;
16
17#[derive(Debug, Clone, Default)]
20pub struct AntonymRegistry {
21 map: HashMap<String, String>,
22}
23
24impl AntonymRegistry {
25 pub fn new() -> Self {
26 Self::default()
27 }
28
29 pub fn register(&mut self, negative: &str, positive: &str) {
34 self.map
35 .insert(negative.to_lowercase(), positive.to_string());
36 }
37
38 pub fn lookup(&self, negative: &str) -> Option<&str> {
41 self.map.get(&negative.to_lowercase()).map(|s| s.as_str())
42 }
43
44 pub fn is_empty(&self) -> bool {
45 self.map.is_empty()
46 }
47
48 pub fn len(&self) -> usize {
49 self.map.len()
50 }
51}
52
53const SIMPLE_AUX: &[&str] = &[
59 "is", "are", "was", "were", "has", "have", "had", "will", "would", "could", "should", "may",
60 "might", "must", "can",
61];
62
63pub fn insert_not(phrase: &str) -> String {
74 let mut parts = phrase.splitn(2, ' ');
75 let first = match parts.next() {
76 Some(w) => w,
77 None => return phrase.to_string(),
78 };
79 let rest = parts.next().unwrap_or("");
80
81 if SIMPLE_AUX.contains(&first.to_lowercase().as_str()) {
82 if rest.is_empty() {
83 return format!("{first} not");
84 }
85 return format!("{first} not {rest}");
86 }
87
88 format!("not {phrase}")
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn insert_not_after_was() {
97 assert_eq!(insert_not("was modified"), "was not modified");
98 }
99
100 #[test]
101 fn insert_not_after_has_been() {
102 assert_eq!(insert_not("has been renamed"), "has not been renamed");
103 }
104
105 #[test]
106 fn insert_not_after_modal() {
107 assert_eq!(insert_not("will break"), "will not break");
108 assert_eq!(insert_not("must fail"), "must not fail");
109 }
110
111 #[test]
112 fn insert_not_without_aux_falls_back_to_prefix() {
113 assert_eq!(insert_not("broke"), "not broke");
115 }
116
117 #[test]
118 fn registry_lookup_case_insensitive() {
119 let mut r = AntonymRegistry::new();
120 r.register("was modified", "remained unchanged");
121 assert_eq!(r.lookup("Was Modified"), Some("remained unchanged"));
122 }
123
124 #[test]
125 fn registry_unknown_lookup_is_none() {
126 let r = AntonymRegistry::new();
127 assert_eq!(r.lookup("was modified"), None);
128 }
129}