diff options
| author | 2025-01-13 20:58:36 -0600 | |
|---|---|---|
| committer | 2025-01-13 20:58:36 -0600 | |
| commit | ff428f36935cefd2b6d8ea6ba4a0572d75d6512d (patch) | |
| tree | cf8b71137247ba74c4a606146d45ec2791725877 /src/launcher/rules.rs | |
| parent | more stuff (diff) | |
library downloads complete
Diffstat (limited to 'src/launcher/rules.rs')
| -rw-r--r-- | src/launcher/rules.rs | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/src/launcher/rules.rs b/src/launcher/rules.rs new file mode 100644 index 0000000..29da8a2 --- /dev/null +++ b/src/launcher/rules.rs @@ -0,0 +1,114 @@ +use std::error::Error; +use std::fmt::Display; +use crate::version::{Argument, CompatibilityRule, CompleteVersion, FeatureMatcher, Library, OSRestriction, RuleAction}; +use super::SystemInfo; + +#[derive(Debug)] +pub struct IncompatibleError { + what: &'static str, + reason: Option<String> +} + +impl Display for IncompatibleError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(reason) = self.reason.as_ref() { + write!(f, "{} incompatible: {}", self.what, reason) + } else { + write!(f, "{} incompatible", self.what) + } + } +} + +impl Error for IncompatibleError {} + +mod seal { + pub trait CompatCheckInner { + const WHAT: &'static str; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &super::CompatibilityRule>>; + fn get_incompatibility_reason(&self) -> Option<&str>; + } +} + +pub trait CompatCheck: seal::CompatCheckInner { + 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; + + fn match_os(os: &OSRestriction, system: &SystemInfo) -> bool { + os.os.is_none_or(|o| system.is_our_os(o)) + && os.version.as_ref().is_none_or(|v| v.is_match(system.os_version.as_str())) + && os.arch.as_ref().is_none_or(|a| a.is_match(system.arch.as_str())) + } + + for rule in rules { + if rule.os.as_ref().is_none_or(|o| match_os(o, system)) + && rule.features_match(feature_matcher) { + action = rule.action; + } + } + + if action == RuleAction::Disallow { + Err(IncompatibleError { + what: Self::WHAT, + reason: self.get_incompatibility_reason().map(|s| s.to_owned()) + }) + } else { + Ok(()) + } + } +} + +// trivial +impl seal::CompatCheckInner for CompatibilityRule { + const WHAT: &'static str = "rule"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + Some(Some(self)) + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + None + } +} + +impl seal::CompatCheckInner for CompleteVersion { + const WHAT: &'static str = "version"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + self.compatibility_rules.as_ref() + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + self.incompatibility_reason.as_ref().map(|s| s.as_str()) + } +} + +impl seal::CompatCheckInner for Library { + const WHAT: &'static str = "library"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + self.rules.as_ref() + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + None + } +} + +impl seal::CompatCheckInner for Argument { + const WHAT: &'static str = "argument"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + self.rules.as_ref() + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + None + } +} + +impl CompatCheck for CompatibilityRule {} +impl CompatCheck for CompleteVersion {} +impl CompatCheck for Library {} +impl CompatCheck for Argument {}
\ No newline at end of file |
