From c19a1077e85334a3e5ba885a60b03d76409a2b2e Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Sat, 1 Feb 2025 23:06:37 -0600 Subject: restructure project --- src/launcher/strsub.rs | 192 ------------------------------------------------- 1 file changed, 192 deletions(-) delete mode 100644 src/launcher/strsub.rs (limited to 'src/launcher/strsub.rs') diff --git a/src/launcher/strsub.rs b/src/launcher/strsub.rs deleted file mode 100644 index 5764405..0000000 --- a/src/launcher/strsub.rs +++ /dev/null @@ -1,192 +0,0 @@ -// a cheap-o implementation of StrSubstitutor from apache commons -// (does not need to support recursive evaluation or preserving escapes, it was never enabled in - -use std::borrow::Cow; - -const ESCAPE: char = '$'; -const VAR_BEGIN: &str = "${"; -const VAR_END: &str = "}"; -const VAR_DEFAULT: &str = ":-"; - -pub trait SubFunc<'rep> { - fn substitute(&self, key: &str) -> Option>; -} - -/* NOTE: the in-place implementation has been replaced for the following reasons: - * - it was annoying to get lifetimes to work, so you could only either pass a trait implementation - * or a closure - * - it was probably slower than doing it out-of-place anyway, since you keep having to copy the - * tail of the string for each replacement - */ - -// handles ${replacements} on this string IN-PLACE. Calls the "sub" function for each key it receives. -// if "sub" returns None, it will use a default value or ignore the ${substitution}. -// There are no "invalid inputs" and this function should never panic unless "sub" panics. -/*pub fn replace_string(input: &mut String, sub: impl SubFunc) { - let mut cursor = input.len(); - while let Some(idx) = input[..cursor].rfind(VAR_BEGIN) { - // note: for some reason, apache processes escapes BEFORE checking if it's even a valid - // replacement expression. strange behavior IMO. - if let Some((pidx, ESCAPE)) = prev_char(input.as_ref(), idx) { - // this "replacement" is escaped. remove the escape marker and continue. - input.remove(pidx); - cursor = pidx; - continue; - } - - let Some(endidx) = input[idx..cursor].find(VAR_END).map(|v| v + idx) else { - // unclosed replacement expression. ignore. - cursor = idx; - continue; - }; - - let spec = &input[(idx + VAR_BEGIN.len())..endidx]; - let name; - let def_opt; - - if let Some(def) = spec.find(VAR_DEFAULT) { - name = &spec[..def]; - def_opt = Some(&spec[(def + VAR_DEFAULT.len())..]); - } else { - name = spec; - def_opt = None; - } - - if let Some(sub_val) = sub.substitute(name).map_or_else(|| def_opt.map(|d| Cow::Owned(d.to_owned())), |v| Some(v)) { - input.replace_range(idx..(endidx + VAR_END.len()), sub_val.as_ref()); - } - - cursor = idx; - } -}*/ - -pub fn replace_string<'inp, 'rep>(input: &'inp str, sub: &impl SubFunc<'rep>) -> Cow<'inp, str> { - let mut ret: Option = None; - let mut cursor = 0usize; - - while let Some(idx) = input[cursor..].find(VAR_BEGIN) { - let idx = idx + cursor; // make idx an absolute index into 'input' - let spec_start = idx + VAR_BEGIN.len(); // the start of the "spec" (area inside {}) - - // first, check if this is escaped - if let Some((prev_idx, ESCAPE)) = input[..idx].char_indices().next_back() { - let s = ret.get_or_insert_default(); - s.push_str(&input[cursor..prev_idx]); - - // advance past this so we don't match it again - s.push_str(&input[idx..spec_start]); - cursor = spec_start; - continue; - } - - // now, find the closing tag - let Some(spec_end) = input[spec_start..].find(VAR_END).map(|v| v + spec_start) else { - break; // reached the end of the string - }; - - let full_spec = &input[spec_start..spec_end]; - - // check for a default argument - let (name, def) = if let Some(defidx) = full_spec.find(VAR_DEFAULT) { - (&full_spec[..defidx], Some(&full_spec[(defidx + VAR_DEFAULT.len())..])) - } else { - (full_spec, None) - }; - - let after = spec_end + VAR_END.len(); - if let Some(subst) = sub.substitute(name).map_or_else(|| def.map(Cow::Borrowed), Some) { - let s = ret.get_or_insert_default(); - s.push_str(&input[cursor..idx]); - s.push_str(subst.as_ref()); - } else { - ret.get_or_insert_default().push_str(&input[cursor..after]); - } - - cursor = after; - } - - if let Some(ret) = ret.as_mut() { - ret.push_str(&input[cursor..]); - } - - ret.map_or(Cow::Borrowed(input), Cow::Owned) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(Clone, Copy)] - struct TestSub; - impl SubFunc<'static> for TestSub { - fn substitute(&self, key: &str) -> Option> { - match key { - "exists" => Some(Cow::Borrowed("value123")), - "empty" => None, - "borger" => Some(Cow::Borrowed("\u{1f354}")), - _ => panic!("replace_fun called with unexpected key: {}", key) - } - } - } - - #[test] - fn test_standard_replace() { - assert_eq!(replace_string("this has ${exists} and more", &TestSub), "this has value123 and more"); - assert_eq!(replace_string("multiple ${exists} repl${exists}ace", &TestSub), "multiple value123 replvalue123ace"); - assert_eq!(replace_string("${exists}${exists}", &TestSub), "value123value123"); - } - - #[test] - fn test_empty_replace() { - assert_eq!(replace_string("this has ${empty} and more", &TestSub), "this has ${empty} and more"); - assert_eq!(replace_string("multiple ${empty} repl${empty}ace", &TestSub), "multiple ${empty} repl${empty}ace"); - assert_eq!(replace_string("${empty}${empty}", &TestSub), "${empty}${empty}"); - } - - #[test] - fn test_homogenous_replace() { - assert_eq!(replace_string("some ${exists} and ${empty} ...", &TestSub), "some value123 and ${empty} ..."); - assert_eq!(replace_string("some ${empty} and ${exists} ...", &TestSub), "some ${empty} and value123 ..."); - assert_eq!(replace_string("${exists}${empty}", &TestSub), "value123${empty}"); - assert_eq!(replace_string("${empty}${exists}", &TestSub), "${empty}value123"); - } - - #[test] - fn test_default_replace() { - assert_eq!(replace_string("some ${exists:-def1} and ${empty:-def2} ...", &TestSub), "some value123 and def2 ..."); - assert_eq!(replace_string("some ${empty:-def1} and ${exists:-def2} ...", &TestSub), "some def1 and value123 ..."); - assert_eq!(replace_string("abc${empty:-}def", &TestSub), "abcdef"); - assert_eq!(replace_string("${empty:-}${empty:-}", &TestSub), ""); - } - - #[test] - fn test_escape() { - assert_eq!(replace_string("an $${escaped} replacement (${exists})", &TestSub), "an ${escaped} replacement (value123)"); - assert_eq!(replace_string("${exists}$${escaped}${exists}", &TestSub), "value123${escaped}value123"); - - // make sure this weird behavior is preserved... (the original code seemed to show it) - assert_eq!(replace_string("some $${ else", &TestSub), "some ${ else"); - } - - #[test] - fn test_weird() { - assert_eq!(replace_string("${exists}", &TestSub), "value123"); - assert_eq!(replace_string("$${empty}", &TestSub), "${empty}"); - assert_eq!(replace_string("${empty:-a}", &TestSub), "a"); - assert_eq!(replace_string("${empty:-}", &TestSub), ""); - } - - // these make sure it doesn't chop up multibyte characters illegally - #[test] - fn test_multibyte_surround() { - assert_eq!(replace_string("\u{1f354}$${}\u{1f354}", &TestSub), "\u{1f354}${}\u{1f354}"); - assert_eq!(replace_string("\u{1f354}${exists}\u{1f354}${empty:-}\u{1f354}", &TestSub), "\u{1f354}value123\u{1f354}\u{1f354}"); - } - - #[test] - fn test_multibyte_replace() { - assert_eq!(replace_string("borger ${borger}", &TestSub), "borger \u{1f354}"); - assert_eq!(replace_string("${exists:-\u{1f354}}${empty:-\u{1f354}}", &TestSub), "value123\u{1f354}"); - assert_eq!(replace_string("${borger}$${}${borger}", &TestSub), "\u{1f354}${}\u{1f354}"); - } -} -- cgit v1.2.3-70-g09d2