summaryrefslogtreecommitdiffstats
path: root/src/launcher/rules.rs
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-01-13 20:58:36 -0600
committerLibravatar bigfoot547 <[email protected]>2025-01-13 20:58:36 -0600
commitff428f36935cefd2b6d8ea6ba4a0572d75d6512d (patch)
treecf8b71137247ba74c4a606146d45ec2791725877 /src/launcher/rules.rs
parentmore stuff (diff)
library downloads complete
Diffstat (limited to 'src/launcher/rules.rs')
-rw-r--r--src/launcher/rules.rs114
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