diff options
| author | 2025-02-11 17:28:51 -0600 | |
|---|---|---|
| committer | 2025-02-11 17:28:51 -0600 | |
| commit | 27ee95f3d6e65bae8022afa88cb0ee3d7d19108f (patch) | |
| tree | 949958a4bd75552ed31e17cbd585d3a87a8cc9f9 | |
| parent | add some documentation (diff) | |
unstupid some stuff
| -rw-r--r-- | ozone/src/launcher.rs | 55 | ||||
| -rw-r--r-- | ozone/src/launcher/rules.rs | 2 | ||||
| -rw-r--r-- | ozone/src/launcher/runner.rs | 23 | ||||
| -rw-r--r-- | ozone/src/launcher/strsub.rs | 83 | ||||
| -rw-r--r-- | ozone/src/version.rs | 15 |
5 files changed, 91 insertions, 87 deletions
diff --git a/ozone/src/launcher.rs b/ozone/src/launcher.rs index a2902da..8c5db3f 100644 --- a/ozone/src/launcher.rs +++ b/ozone/src/launcher.rs @@ -197,9 +197,8 @@ impl Error for LaunchError { } } -struct LaunchInfo<'l, F: FeatureMatcher> { +struct LaunchInfo<'l> { launcher: &'l Launcher, - feature_matcher: &'l F, client_id: Uuid, asset_index_name: Option<String>, @@ -225,12 +224,13 @@ pub struct Launch { jni_launch: bool } -struct InstanceFeatureMatcher<'prof> { - instance: &'prof Instance +#[derive(Clone, Copy)] +struct InstanceFeatureMatcher<'inst> { + instance: &'inst Instance } -impl FeatureMatcher for InstanceFeatureMatcher<'_> { - fn matches(&self, feature: &str) -> bool { +impl<'a> FeatureMatcher<'a> for InstanceFeatureMatcher<'_> { + fn matches(self, feature: &str) -> bool { match feature { "has_custom_resolution" => self.instance.resolution.is_some(), _ => false @@ -311,17 +311,10 @@ impl Launcher { util::ensure_file(&path, dlinfo.url.as_deref(), dlinfo.size, dlinfo.sha1, self.online, false).await .map_err(LaunchError::EnsureFile)?; - struct PathSub<'a>(&'a Path); - impl<'a> SubFunc<'a> for PathSub<'a> { - fn substitute(&self, key: &str) -> Option<Cow<'a, str>> { - match key { - "path" => Some(self.0.as_java_path().to_string_lossy()), - _ => None - } - } - } - - Ok(strsub::replace_string(config.argument.as_str(), &PathSub(path.as_ref())).to_string()) + Ok(strsub::replace_string(config.argument.as_str(), |k| match k { + "path" => Some(path.as_java_path().to_string_lossy()), + _ => None + }).to_string()) } /* TODO: @@ -356,7 +349,7 @@ impl Launcher { }; let ver = self.versions.resolve_version(ver.as_ref()).await.map_err(LaunchError::ResolveVersion)?; - ver.rules_apply(&self.system_info, &feature_matcher).map_err(LaunchError::IncompatibleVersion)?; + ver.rules_apply(&self.system_info, feature_matcher).map_err(LaunchError::IncompatibleVersion)?; info!("Resolved launch version {}!", ver.id); @@ -364,7 +357,7 @@ impl Launcher { let mut downloads = IndexMap::new(); for lib in ver.libraries.iter() { - if lib.rules_apply(&self.system_info, &feature_matcher).is_err() { + if lib.rules_apply(&self.system_info, feature_matcher).is_err() { trace!("Skipping library {}, compatibility rules failed", lib.name); continue; } @@ -510,7 +503,6 @@ impl Launcher { info!("Deriving launch arguments"); let info = LaunchInfo { launcher: self, - feature_matcher: &feature_matcher, client_id, asset_index_name: asset_idx_name.map(|s| s.to_owned()), @@ -534,10 +526,10 @@ impl Launcher { let mut jvm_args: Vec<_> = instance.jvm_arguments.as_ref() .map(|a| a.iter().map(OsString::from).collect()) .unwrap_or_else(|| iter_default_arguments().map(OsString::from).collect()); - jvm_args.extend(runner::build_arguments(&info, ver.as_ref(), ArgumentType::Jvm).into_iter()); + jvm_args.extend(runner::build_arguments(&info, feature_matcher, ver.as_ref(), ArgumentType::Jvm).into_iter()); jvm_args.extend(log_arg.iter().map(OsString::from)); - let game_args = runner::build_arguments(&info, ver.as_ref(), ArgumentType::Game); + let game_args = runner::build_arguments(&info, feature_matcher, ver.as_ref(), ArgumentType::Game); let diff = Instant::now().duration_since(start); info!("Finished preparing launch for {} in {:.02} seconds!", ver.id, diff.as_secs_f32()); @@ -569,26 +561,23 @@ impl LibraryRepository { fn get_artifact_filename(name: &str, classifier: Option<&str>) -> Option<PathBuf> { let n: Vec<&str> = name.splitn(4, ':').skip(1).collect(); - struct LibReplace; - impl SubFunc<'static> for LibReplace { - fn substitute(&self, key: &str) -> Option<Cow<'static, str>> { - match key { - "arch" => Some(Cow::Borrowed(ozone_arch_bits!())), - _ => None - } + fn arch_sub(key: &str) -> Option<Cow<'static, str>> { + match key { + "arch" => Some(Cow::Borrowed(ozone_arch_bits!())), + _ => None } } if let Some(classifier) = classifier { match n.len() { - 2 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}-{}.jar", n[0], n[1], classifier).as_str(), &LibReplace).as_ref())), - 3 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}-{}-{}.jar", n[0], n[1], classifier, n[2]).as_str(), &LibReplace).as_ref())), + 2 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}-{}.jar", n[0], n[1], classifier).as_str(), arch_sub).as_ref())), + 3 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}-{}-{}.jar", n[0], n[1], classifier, n[2]).as_str(), arch_sub).as_ref())), _ => None } } else { match n.len() { - 2 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}.jar", n[0], n[1]).as_str(), &LibReplace).as_ref())), - 3 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}-{}.jar", n[0], n[1], n[2]).as_str(), &LibReplace).as_ref())), + 2 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}.jar", n[0], n[1]).as_str(), arch_sub).as_ref())), + 3 => Some(PathBuf::from(strsub::replace_string(format!("{}-{}-{}.jar", n[0], n[1], n[2]).as_str(), arch_sub).as_ref())), _ => None } } diff --git a/ozone/src/launcher/rules.rs b/ozone/src/launcher/rules.rs index ceed3ef..9d36157 100644 --- a/ozone/src/launcher/rules.rs +++ b/ozone/src/launcher/rules.rs @@ -31,7 +31,7 @@ mod seal { } pub trait CompatCheck: seal::CompatCheckInner { - fn rules_apply(&self, system: &SystemInfo, feature_matcher: &impl FeatureMatcher) -> Result<(), IncompatibleError> { + fn rules_apply<'a>(&'a self, system: &SystemInfo, feature_matcher: impl FeatureMatcher<'a>) -> Result<(), IncompatibleError> { let Some(rules) = self.get_rules() else { return Ok(()) }; let mut action = RuleAction::Disallow; diff --git a/ozone/src/launcher/runner.rs b/ozone/src/launcher/runner.rs index 7c1a903..4e1f353 100644 --- a/ozone/src/launcher/runner.rs +++ b/ozone/src/launcher/runner.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::ffi::{OsStr, OsString}; use std::iter; +use std::marker::PhantomData; use std::path::{Path, PathBuf}; use std::process::Command; use log::{debug, warn}; @@ -12,7 +13,7 @@ use super::strsub::{self, SubFunc}; use super::{Launch, LaunchInfo}; #[derive(Clone, Copy)] -struct LaunchArgSub<'a, 'l, F: FeatureMatcher>(&'a LaunchInfo<'l, F>); +struct LaunchArgSub<'a, 'l>(&'a LaunchInfo<'l>); // FIXME: this is not correct #[cfg(windows)] @@ -21,8 +22,8 @@ const PATH_SEP: &str = ";"; #[cfg(not(windows))] const PATH_SEP: &str = ":"; -impl<'rep, F: FeatureMatcher> SubFunc<'rep> for LaunchArgSub<'rep, '_, F> { - fn substitute(&self, key: &str) -> Option<Cow<'rep, str>> { +impl<'key, 'rep> SubFunc<'key, 'rep> for LaunchArgSub<'rep, '_> { + fn substitute(self, key: &'key str) -> Option<Cow<'rep, str>> { match key { "assets_index_name" => self.0.asset_index_name.as_ref().map(|s| Cow::Borrowed(s.as_str())), "assets_root" => Some(self.0.launcher.assets.get_home().as_java_path().to_string_lossy()), @@ -72,7 +73,7 @@ pub enum ArgumentType { Game } -pub fn build_arguments<F: FeatureMatcher>(launch: &LaunchInfo<'_, F>, version: &CompleteVersion, arg_type: ArgumentType) -> Vec<OsString> { +pub fn build_arguments<'v, F: FeatureMatcher<'v>>(launch: &LaunchInfo<'_>, feature_matcher: F, version: &'v CompleteVersion, arg_type: ArgumentType) -> Vec<OsString> { let sub = LaunchArgSub(launch); let system_info = &launch.launcher.system_info; @@ -81,9 +82,9 @@ pub fn build_arguments<F: FeatureMatcher>(launch: &LaunchInfo<'_, F>, version: & ArgumentType::Game => args.game.as_ref() }) { arguments.iter() - .filter(|wa| wa.rules_apply(system_info, launch.feature_matcher).is_ok()) + .filter(|wa| wa.rules_apply(system_info, feature_matcher).is_ok()) .flat_map(|wa| &wa.value) - .map(|s| OsString::from(strsub::replace_string(s, &sub).into_owned())).collect() + .map(|s| OsString::from(strsub::replace_string(s, sub).into_owned())).collect() } else if let Some(arguments) = version.minecraft_arguments.as_ref() { match arg_type { ArgumentType::Jvm => { @@ -98,22 +99,22 @@ pub fn build_arguments<F: FeatureMatcher>(launch: &LaunchInfo<'_, F>, version: & .chain(iter::once("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump") .take_while(|_| system_info.os == OperatingSystem::Windows)) .chain(iter::once(["-Dos.name=Windows 10", "-Dos.version=10.0"]) - .take_while(|_| launch.feature_matcher.matches("__ozone_win10_hack")) + .take_while(|_| feature_matcher.matches("__ozone_win10_hack")) .flatten()) .chain(iter::once(["-Xdock:icon=${asset=icons/minecraft.icns}", "-Xdock:name=Minecraft"]) .take_while(|_| system_info.os == OperatingSystem::MacOS) .flatten()) - .map(|s| OsString::from(strsub::replace_string(s, &sub).into_owned())) + .map(|s| OsString::from(strsub::replace_string(s, sub).into_owned())) .collect() }, ArgumentType::Game => { arguments.split(' ') .chain(iter::once("--demo") - .take_while(|_| launch.feature_matcher.matches("is_demo_user"))) + .take_while(|_| feature_matcher.matches("is_demo_user"))) .chain(iter::once(["--width", "${resolution_width}", "--height", "${resolution_height}"]) - .take_while(|_| launch.feature_matcher.matches("has_custom_resolution")) + .take_while(|_| feature_matcher.matches("has_custom_resolution")) .flatten()) - .map(|s| OsString::from(strsub::replace_string(s, &sub).into_owned())) + .map(|s| OsString::from(strsub::replace_string(s, sub).into_owned())) .collect() } } diff --git a/ozone/src/launcher/strsub.rs b/ozone/src/launcher/strsub.rs index 5764405..307d0a1 100644 --- a/ozone/src/launcher/strsub.rs +++ b/ozone/src/launcher/strsub.rs @@ -8,8 +8,17 @@ const VAR_BEGIN: &str = "${"; const VAR_END: &str = "}"; const VAR_DEFAULT: &str = ":-"; -pub trait SubFunc<'rep> { - fn substitute(&self, key: &str) -> Option<Cow<'rep, str>>; +pub trait SubFunc<'key, 'rep>: Copy { + fn substitute(self, key: &'key str) -> Option<Cow<'rep, str>>; +} + +impl<'key, 'rep, F> SubFunc<'key, 'rep> for F +where + F: Fn(&'key str) -> Option<Cow<'rep, str>> + Copy +{ + fn substitute(self, key: &'key str) -> Option<Cow<'rep, str>> { + self(key) + } } /* NOTE: the in-place implementation has been replaced for the following reasons: @@ -60,7 +69,7 @@ pub trait SubFunc<'rep> { } }*/ -pub fn replace_string<'inp, 'rep>(input: &'inp str, sub: &impl SubFunc<'rep>) -> Cow<'inp, str> { +pub fn replace_string<'inp, 'rep>(input: &'inp str, sub: impl SubFunc<'inp, 'rep>) -> Cow<'inp, str> { let mut ret: Option<String> = None; let mut cursor = 0usize; @@ -116,77 +125,73 @@ pub fn replace_string<'inp, 'rep>(input: &'inp str, sub: &impl SubFunc<'rep>) -> mod tests { use super::*; - #[derive(Clone, Copy)] - struct TestSub; - impl SubFunc<'static> for TestSub { - fn substitute(&self, key: &str) -> Option<Cow<'static, str>> { - match key { - "exists" => Some(Cow::Borrowed("value123")), - "empty" => None, - "borger" => Some(Cow::Borrowed("\u{1f354}")), - _ => panic!("replace_fun called with unexpected key: {}", key) - } + fn test_sub(key: &str) -> Option<Cow<'static, str>> { + 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"); + assert_eq!(replace_string("this has ${exists} and more", test_sub), "this has value123 and more"); + assert_eq!(replace_string("multiple ${exists} repl${exists}ace", test_sub), "multiple value123 replvalue123ace"); + assert_eq!(replace_string("${exists}${exists}", test_sub), "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}"); + assert_eq!(replace_string("this has ${empty} and more", test_sub), "this has ${empty} and more"); + assert_eq!(replace_string("multiple ${empty} repl${empty}ace", test_sub), "multiple ${empty} repl${empty}ace"); + assert_eq!(replace_string("${empty}${empty}", test_sub), "${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"); + assert_eq!(replace_string("some ${exists} and ${empty} ...", test_sub), "some value123 and ${empty} ..."); + assert_eq!(replace_string("some ${empty} and ${exists} ...", test_sub), "some ${empty} and value123 ..."); + assert_eq!(replace_string("${exists}${empty}", test_sub), "value123${empty}"); + assert_eq!(replace_string("${empty}${exists}", test_sub), "${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), ""); + assert_eq!(replace_string("some ${exists:-def1} and ${empty:-def2} ...", test_sub), "some value123 and def2 ..."); + assert_eq!(replace_string("some ${empty:-def1} and ${exists:-def2} ...", test_sub), "some def1 and value123 ..."); + assert_eq!(replace_string("abc${empty:-}def", test_sub), "abcdef"); + assert_eq!(replace_string("${empty:-}${empty:-}", test_sub), ""); } #[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"); + assert_eq!(replace_string("an $${escaped} replacement (${exists})", test_sub), "an ${escaped} replacement (value123)"); + assert_eq!(replace_string("${exists}$${escaped}${exists}", test_sub), "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"); + assert_eq!(replace_string("some $${ else", test_sub), "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), ""); + assert_eq!(replace_string("${exists}", test_sub), "value123"); + assert_eq!(replace_string("$${empty}", test_sub), "${empty}"); + assert_eq!(replace_string("${empty:-a}", test_sub), "a"); + assert_eq!(replace_string("${empty:-}", test_sub), ""); } // 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}"); + assert_eq!(replace_string("\u{1f354}$${}\u{1f354}", test_sub), "\u{1f354}${}\u{1f354}"); + assert_eq!(replace_string("\u{1f354}${exists}\u{1f354}${empty:-}\u{1f354}", test_sub), "\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}"); + assert_eq!(replace_string("borger ${borger}", test_sub), "borger \u{1f354}"); + assert_eq!(replace_string("${exists:-\u{1f354}}${empty:-\u{1f354}}", test_sub), "value123\u{1f354}"); + assert_eq!(replace_string("${borger}$${}${borger}", test_sub), "\u{1f354}${}\u{1f354}"); } } diff --git a/ozone/src/version.rs b/ozone/src/version.rs index 27c2a6d..458ed80 100644 --- a/ozone/src/version.rs +++ b/ozone/src/version.rs @@ -81,12 +81,21 @@ pub struct CompatibilityRule { pub os: Option<OSRestriction> } -pub trait FeatureMatcher { - fn matches(&self, feature: &str) -> bool; +pub trait FeatureMatcher<'feat>: Copy { + fn matches(self, feature: &'feat str) -> bool; +} + +impl<'feat, F> FeatureMatcher<'feat> for F +where + F: Fn(&'feat str) -> bool + Copy +{ + fn matches(self, feature: &'feat str) -> bool { + self(feature) + } } impl CompatibilityRule { - pub fn features_match(&self, checker: &impl FeatureMatcher) -> bool { + pub fn features_match<'a>(&'a self, checker: impl FeatureMatcher<'a>) -> bool { if let Some(m) = self.features.as_ref() { for (feat, expect) in m { if checker.matches(feat) != *expect { |
