1use semver::Version;
3use serde::{Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize, Debug, Clone)]
7pub struct Package {
8    pub name: String,
10    pub version: Version,
12    pub authors: Vec<String>,
14    pub edition: String,
16}
17
18impl Default for Package {
19    fn default() -> Self {
20        Self {
21            name: "addition".to_string(),
22            version: Version::new(0, 1, 0),
23            authors: vec![],
24            edition: "2021".to_string(),
25        }
26    }
27}
28
29#[derive(Serialize, Deserialize, Debug, Clone)]
31pub struct Lib {
32    #[serde(rename = "crate-type")]
34    pub crate_type: Vec<String>,
35}
36
37impl Default for Lib {
38    fn default() -> Self {
39        Self {
40            crate_type: vec!["cdylib".to_string()],
41        }
42    }
43}
44
45#[derive(Serialize, Deserialize, Debug, Clone)]
47pub struct Dependencies {
48    pub zink: Version,
50}
51
52impl Default for Dependencies {
53    fn default() -> Self {
54        let zink_version = option_env!("ZINK_VERSION").unwrap_or("0.1.0");
56        Self {
57            zink: Version::parse(zink_version).expect("Invalid zink version format"),
58        }
59    }
60}
61
62#[derive(Serialize, Deserialize, Debug, Clone)]
64#[serde(rename = "dev-dependencies")]
65pub struct DevDependencies {
66    pub zint: Version,
67}
68
69impl Default for DevDependencies {
70    fn default() -> Self {
71        let zint_version = option_env!("ZINK_VERSION").unwrap_or("0.1.0");
72        Self {
73            zint: Version::parse(zint_version).expect("Invalid zint version format"),
74        }
75    }
76}
77
78#[derive(Serialize, Deserialize, Debug, Default, Clone)]
80pub struct Workspace {}
81
82impl Default for Manifest {
83    fn default() -> Self {
84        Self {
85            package: Package::default(),
86            lib: Lib::default(),
87            dependencies: Dependencies::default(),
88            dev_dependencies: Some(DevDependencies::default()),
89            workspace: Workspace::default(),
90        }
91    }
92}
93
94#[derive(Serialize, Deserialize, Debug, Clone)]
96pub struct Manifest {
97    pub package: Package,
99    pub lib: Lib,
101    pub dependencies: Dependencies,
103    #[serde(default, skip_serializing_if = "Option::is_none")]
105    #[serde(rename = "dev-dependencies")]
106    pub dev_dependencies: Option<DevDependencies>,
107    #[serde(default)]
109    pub workspace: Workspace,
110}
111
112impl Manifest {
113    pub fn name(&mut self, name: &str) -> &mut Self {
115        self.package.name = name.to_string();
116        self
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_default_zink_version() {
126        let manifest = Manifest::default();
127        let expected_version = option_env!("ZINK_VERSION")
128            .unwrap_or("0.1.0")
129            .parse::<Version>()
130            .expect("Invalid version format");
131        assert_eq!(
132            manifest.dependencies.zink, expected_version,
133            "Zink version should match the one set by build.rs or fallback to 0.1.0"
134        );
135
136        if option_env!("ZINK_VERSION").is_some() {
138            assert_ne!(
139                manifest.dependencies.zink,
140                Version::new(0, 1, 0),
141                "Zink version should reflect build.rs output, not the hardcoded fallback"
142            );
143        }
144    }
145
146    #[test]
147    fn test_manifest_serialization() {
148        let mut manifest = Manifest::default();
149        manifest.name("testproj");
150        let toml = toml::to_string_pretty(&manifest).expect("Failed to serialize manifest");
151        assert!(toml.contains("name = \"testproj\""));
152        assert!(toml.contains(&format!(
153            "zink = \"{}\"",
154            option_env!("ZINK_VERSION").unwrap_or("0.1.0")
155        )));
156    }
157}