changepacks_utils/
split_version.rs1use anyhow::Result;
2
3pub fn split_version(version: &str) -> Result<(Option<String>, String)> {
4 let first_digit_pos = version
5 .char_indices()
6 .find(|(_, c)| c.is_ascii_digit())
7 .map(|(pos, _)| pos);
8
9 match first_digit_pos {
10 Some(0) => Ok((None, version.to_string())),
11 Some(pos) => {
12 let prefix = version[..pos].to_string();
13 let version_part = version[pos..].to_string();
14 Ok((Some(prefix), version_part))
15 }
16 None => Ok((None, version.to_string())),
17 }
18}
19
20#[cfg(test)]
21mod tests {
22 use super::*;
23
24 use rstest::rstest;
25
26 #[rstest]
27 #[case("1.0.0", (None, "1.0.0"))]
28 #[case("^1.0.0", (Some("^"), "1.0.0"))]
29 #[case("~1.0.0", (Some("~"), "1.0.0"))]
30 #[case("1.0.0-alpha.1", (None, "1.0.0-alpha.1"))]
31 #[case("1.0.0-alpha.1+build1", (None, "1.0.0-alpha.1+build1"))]
32 #[case(">=1.0.0+build1", (Some(">="), "1.0.0+build1"))]
33 #[case("helloworld-1.0.2", (Some("helloworld-"), "1.0.2"))]
34 #[case("latest", (None, "latest"))]
35 #[case("*", (None, "*"))]
36 fn test_split_version(#[case] input: &str, #[case] expected: (Option<&str>, &str)) {
37 let (prefix, version) = split_version(input).unwrap();
38 assert_eq!(prefix.as_deref(), expected.0);
39 assert_eq!(version.as_str(), expected.1);
40 }
41}