alith_client/components/grammar/
faux_url.rs1use super::{Grammar, GrammarError, GrammarSetterTrait};
2use std::cell::RefCell;
3
4#[derive(Clone, PartialEq)]
5pub struct FauxUrlGrammar {
6 pub min_count: u8,
7 pub max_count: u8,
8 pub word_char_length: u8,
9 pub base_url: String,
10 pub stop_word_done: Option<String>,
11 pub stop_word_no_result: Option<String>,
12 grammar_string: RefCell<Option<String>>,
13}
14
15impl Default for FauxUrlGrammar {
16 fn default() -> Self {
17 Self {
18 min_count: 1,
19 max_count: 3,
20 word_char_length: 12,
21 base_url: "https://example.com/".to_string(),
22 stop_word_done: None,
23 stop_word_no_result: None,
24 grammar_string: RefCell::new(None),
25 }
26 }
27}
28
29impl FauxUrlGrammar {
30 #[inline]
31 pub fn wrap(self) -> Grammar {
32 Grammar::FauxUrl(self)
33 }
34
35 #[inline]
36 pub fn min_count(mut self, min_count: u8) -> Self {
37 self.min_count = min_count;
38 self
39 }
40
41 #[inline]
42 pub fn max_count(mut self, max_count: u8) -> Self {
43 self.max_count = max_count;
44 self
45 }
46
47 #[inline]
48 pub fn word_char_length(mut self, word_char_length: u8) -> Self {
49 self.word_char_length = word_char_length;
50 self
51 }
52
53 #[inline]
54 pub fn base_url<T: AsRef<str>>(mut self, base_url: T) -> Self {
55 self.base_url = base_url.as_ref().to_string();
56 self
57 }
58
59 pub fn grammar_string(&self) -> String {
60 let mut grammar_string = self.grammar_string.borrow_mut();
61 if grammar_string.is_none() {
62 *grammar_string = Some(faux_url_grammar(
63 self.min_count,
64 self.max_count,
65 self.word_char_length,
66 &self.base_url,
67 &self.stop_word_done,
68 &self.stop_word_no_result,
69 ));
70 }
71 grammar_string.as_ref().unwrap().clone()
72 }
73
74 #[inline]
75 pub fn validate_clean(&self, content: &str) -> Result<String, GrammarError> {
76 faux_url_validate_clean(content, &self.base_url)
77 }
78
79 #[inline]
80 pub fn grammar_parse(&self, content: &str) -> Result<Vec<String>, GrammarError> {
81 faux_url_parse(content, &self.base_url)
82 }
83}
84
85impl GrammarSetterTrait for FauxUrlGrammar {
86 fn stop_word_done_mut(&mut self) -> &mut Option<String> {
87 &mut self.stop_word_done
88 }
89
90 fn stop_word_no_result_mut(&mut self) -> &mut Option<String> {
91 &mut self.stop_word_no_result
92 }
93}
94
95pub fn faux_url_grammar<T: AsRef<str>>(
96 min_count: u8,
97 max_count: u8,
98 word_char_length: u8,
99 base_url: &str,
100 stop_word_done: &Option<T>,
101 stop_word_no_result: &Option<T>,
102) -> String {
103 let range = create_range(min_count, max_count, stop_word_done);
104 let first = format!("first ::= [a-z]{{3,{word_char_length}}}");
105 let item = format!("item ::= \"-\" [a-z]{{3,{word_char_length}}}");
106 match (stop_word_done, stop_word_no_result) {
107 (Some(stop_word_done), Some(stop_word_no_result)) => format!(
108 "root ::= \" \" ( \"{base_url}\" {range} | \"{}\" ) \" {}\"\n{item}\n{first}",
109 stop_word_no_result.as_ref(),
110 stop_word_done.as_ref()
111 ),
112 (None, Some(stop_word_no_result)) => {
113 format!(
114 "root ::= \" \" ( \"{base_url}\" {range} | \"{}\" )\n{item}\n{first}",
115 stop_word_no_result.as_ref()
116 )
117 }
118 (Some(stop_word_done), None) => {
119 format!(
120 "root ::= \" \" \"{base_url}\" {range} \" {}\"\n{item}\n{first}",
121 stop_word_done.as_ref()
122 )
123 }
124 (None, None) => format!("root ::= \" \" \"{base_url}\" {range}\n{item}\n{first}"),
125 }
126}
127
128fn create_range<T: AsRef<str>>(min_count: u8, max_count: u8, stop_word_done: &Option<T>) -> String {
129 let min_count = if min_count == 0 {
130 eprintln!("Min count must be greater than 0. Setting min count to 1.");
131 1
132 } else {
133 min_count
134 };
135 let max_count = match max_count.cmp(&min_count) {
136 std::cmp::Ordering::Less => {
137 eprintln!(
138 "Max count must be greater than or equal to min count. Setting max count to min count."
139 );
140 min_count
141 }
142 _ => max_count,
143 };
144 if min_count == 1 && max_count == 1 {
145 "first".to_owned()
146 } else {
147 let mut range = String::new();
148 range.push_str("first ");
149 if min_count > 1 {
150 range.push_str(&format!("item{{{}}} ", min_count - 1));
151 }
152 if max_count > min_count {
153 let opt_count = max_count - min_count;
154 if let Some(stop_word_done) = stop_word_done {
155 range.push_str(&format!(
156 "( \"{}\" | item ){{0,{opt_count}}}",
157 stop_word_done.as_ref()
158 ))
159 } else {
160 range.push_str(&format!("item{{0,{opt_count}}}"));
161 };
162 }
163 range
164 }
165}
166pub fn faux_url_validate_clean(content: &str, base: &str) -> Result<String, GrammarError> {
167 if faux_url_parse(content, base).is_ok() {
168 Ok(content
169 .trim()
170 .trim_end_matches(|c: char| !c.is_alphanumeric())
171 .to_string())
172 } else {
173 Err(GrammarError::ParseValueError {
174 content: content.to_string(),
175 parse_type: "FauxUrl".to_string(),
176 })
177 }
178}
179
180pub fn faux_url_parse(content: &str, base: &str) -> Result<Vec<String>, GrammarError> {
181 if let Some(trimmed_content) = content.trim().strip_prefix(base) {
182 Ok(trimmed_content
183 .trim_end_matches('-')
184 .split('-')
185 .map(String::from)
186 .collect())
187 } else {
188 Err(GrammarError::ParseValueError {
189 content: content.to_string(),
190 parse_type: "FauxUrl".to_string(),
191 })
192 }
193}