1use std::collections::BTreeMap;
2
3use serde::Deserialize;
4
5#[derive(Debug, Deserialize)]
6pub struct CargoToml {
7 pub package: Package,
8 pub dependencies: Option<BTreeMap<String, Dependency>>,
9}
10
11#[derive(Debug, Deserialize)]
12pub struct Package {
13 pub name: String,
14 pub version: String,
15}
16
17#[derive(Debug, Deserialize)]
18pub struct Dependency {
19 pub version: String,
20}
21
22impl CargoToml {
23 pub fn get_dependency(&self, name: &str) -> Option<&Dependency> {
24 self.dependencies.as_ref().and_then(|deps| deps.get(name))
25 }
26}
27
28pub fn parse_cargo_toml(toml: &str) -> Result<CargoToml, String> {
29 #[derive(Deserialize)]
30 struct CargoTomlVisitor {
31 package: Package,
32 dependencies: Option<BTreeMap<String, toml::Value>>,
33 }
34
35 let parsed = toml::from_str::<CargoTomlVisitor>(toml).map_err(|e| e.to_string())?;
36
37 let dependencies = parsed
38 .dependencies
39 .map(parse_dependencies)
40 .map_or(Ok(None), |v| v.map(Some))?;
41
42 Ok(CargoToml {
43 package: parsed.package,
44 dependencies,
45 })
46}
47
48fn parse_dependencies(
49 deps: BTreeMap<String, toml::Value>,
50) -> Result<BTreeMap<String, Dependency>, String> {
51 let mut dependencies = BTreeMap::new();
52 for (name, value) in deps {
53 if value.is_str() {
54 let version = value.as_str().unwrap();
55 dependencies.insert(
56 name,
57 Dependency {
58 version: version.to_string(),
59 },
60 );
61 } else if value.is_table() {
62 if let Some(version) = value.get("version") {
63 dependencies.insert(
64 name,
65 Dependency {
66 version: version
67 .as_str()
68 .ok_or("can't parse version as str".to_string())?
69 .to_string(),
70 },
71 );
72 } else if let Some(tag) = value.get("tag") {
73 dependencies.insert(
74 name,
75 Dependency {
76 version: tag
77 .as_str()
78 .ok_or("can't parse tag as str".to_string())?
79 .to_string(),
80 },
81 );
82 } else {
83 return Err("can't find version or path".to_string());
84 }
85 }
86 }
87 Ok(dependencies)
88}
89
90#[cfg(test)]
91mod test {
92 use super::*;
93 #[test]
94 fn test_parse_cargo_toml() {
95 let toml = r#"
96 [package]
97 name = "hello"
98 version = "0.1.0"
99 [dependencies]
100 serde = "1.0"
101 toml = { version = "0.5" }
102 hyle = { git = "https://github.com/Hyle-org/hyle", tag = "0.12" }
103 "#;
104 let cargo_toml = parse_cargo_toml(toml).unwrap();
105 assert_eq!(cargo_toml.package.name, "hello");
106 assert_eq!(cargo_toml.package.version, "0.1.0");
107 assert_eq!(cargo_toml.dependencies.as_ref().unwrap().len(), 3);
108
109 assert_eq!(cargo_toml.get_dependency("serde").unwrap().version, "1.0");
110 assert_eq!(cargo_toml.get_dependency("toml").unwrap().version, "0.5");
111 assert_eq!(cargo_toml.get_dependency("hyle").unwrap().version, "0.12");
112 }
113}
114