lyceris/minecraft/
parse.rs

1use std::env::consts::OS;
2
3use crate::{error::Error, json::version::meta::vanilla::{Action, Name, Rule}};
4
5use super::TARGET_ARCH;
6
7/// Trait for parsing rules related to operating system and architecture.
8pub trait ParseRule {
9    /// Parses the rules and determines if the current environment is allowed.
10    ///
11    /// # Returns
12    /// A boolean indicating whether the current environment meets the rules.
13    fn parse_rule(&self) -> bool;
14}
15
16impl ParseRule for [Rule] {
17    /// Parses the rules for an array of `Rule` and determines if the current environment is allowed.
18    ///
19    /// # Returns
20    /// A boolean indicating whether the current environment meets the rules.
21    fn parse_rule(&self) -> bool {
22        let parsed_os: Name = match OS {
23            "linux" => Name::Linux,
24            "windows" => Name::Windows,
25            "macos" => Name::Osx,
26            _ => panic!("Unknown operating system!"),
27        };
28
29        if self.is_empty() {
30            true
31        } else {
32            let mut should_push = false;
33            for rule in self {
34                if rule.action == Action::Disallow {
35                    if let Some(os) = &rule.os {
36                        if os.name.is_some()
37                            && os.name != Some(parsed_os.clone())
38                            && os.arch.is_some()
39                            && os.arch != Some(TARGET_ARCH.to_string())
40                        {
41                            continue;
42                        } else {
43                            break;
44                        }
45                    } else {
46                        continue;
47                    }
48                } else if rule.action == Action::Allow {
49                    if let Some(os) = &rule.os {
50                        if (os.name.is_some() && os.name != Some(parsed_os.clone()))
51                            || (os.arch.is_some() && os.arch != Some(TARGET_ARCH.to_string()))
52                        {
53                            continue;
54                        } else {
55                            should_push = true;
56                            break;
57                        }
58                    } else {
59                        should_push = true;
60                        continue;
61                    }
62                }
63            }
64            should_push
65        }
66    }
67}
68
69impl ParseRule for Option<Vec<Rule>> {
70    /// Parses the rules for an optional vector of `Rule` and determines if the current environment is allowed.
71    ///
72    /// # Returns
73    /// A boolean indicating whether the current environment meets the rules.
74    fn parse_rule(&self) -> bool {
75        match self {
76            Some(rules) => {
77                let parsed_os: Name = match OS {
78                    "linux" => Name::Linux,
79                    "windows" => Name::Windows,
80                    "macos" => Name::Osx,
81                    _ => panic!("Unknown operating system!"),
82                };
83
84                if rules.is_empty() {
85                    true
86                } else {
87                    let mut should_push = false;
88                    for rule in rules {
89                        if rule.action == Action::Disallow {
90                            if let Some(os) = &rule.os {
91                                if os.name.is_some()
92                                    && os.name != Some(parsed_os.clone())
93                                    && os.arch.is_some()
94                                    && os.arch != Some(TARGET_ARCH.to_string())
95                                {
96                                    continue;
97                                } else {
98                                    break;
99                                }
100                            } else {
101                                continue;
102                            }
103                        } else if rule.action == Action::Allow {
104                            if let Some(os) = &rule.os {
105                                if (os.name.is_some() && os.name != Some(parsed_os.clone()))
106                                    || (os.arch.is_some()
107                                        && os.arch != Some(TARGET_ARCH.to_string()))
108                                {
109                                    continue;
110                                } else {
111                                    should_push = true;
112                                    break;
113                                }
114                            } else {
115                                should_push = true;
116                                continue;
117                            }
118                        }
119                    }
120                    should_push
121                }
122            }
123            None => true,
124        }
125    }
126}
127
128/// Parses the library path from the given artifact string.
129///
130/// # Parameters
131/// - `artifact`: The artifact string in the format "group:name:version[@classifier]".
132///
133/// # Returns
134/// A `Result` containing the parsed library path as a string or an error if the format is invalid.
135pub fn parse_lib_path(artifact: &str) -> crate::Result<String> {
136    let name_items: Vec<&str> = artifact.split(':').collect();
137    if name_items.len() < 3 {
138        return Err(Error::Parse(format!("Invalid artifact format: {}", artifact)));
139    }
140
141    let package = name_items[0];
142    let name = name_items[1];
143    let version_ext: Vec<&str> = name_items[2].split('@').collect();
144    let version = version_ext[0];
145    let ext = version_ext.get(1).unwrap_or(&"jar");
146
147    if name_items.len() == 3 {
148        Ok(format!(
149            "{}/{}/{}/{}-{}.{}",
150            package.replace('.', "/"),
151            name,
152            version,
153            name,
154            version,
155            ext
156        ))
157    } else {
158        let data_ext: Vec<&str> = name_items[3].split('@').collect();
159        let data = data_ext[0];
160        let data_ext = data_ext.get(1).unwrap_or(&"jar");
161
162        Ok(format!(
163            "{}/{}/{}/{}-{}-{}.{}",
164            package.replace('.', "/"),
165            name,
166            version,
167            name,
168            version,
169            data,
170            data_ext
171        ))
172    }
173}