elko/utils/
manifest.rs

1//! Cargo Manifest for the zink project.
2use semver::Version;
3use serde::{Deserialize, Serialize};
4
5/// Cargo package.
6#[derive(Serialize, Deserialize, Debug, Clone)]
7pub struct Package {
8    /// Package name.
9    pub name: String,
10    /// Package version.
11    pub version: Version,
12    /// Package authors.
13    pub authors: Vec<String>,
14    /// Rust edition.
15    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/// Lib section of cargo manifest.
30#[derive(Serialize, Deserialize, Debug, Clone)]
31pub struct Lib {
32    /// The crate type of cargo project.
33    #[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/// Dependencies of the cargo project.
46#[derive(Serialize, Deserialize, Debug, Clone)]
47pub struct Dependencies {
48    /// Zink dependency.
49    pub zink: Version,
50}
51
52impl Default for Dependencies {
53    fn default() -> Self {
54        // Use the ZINK_VERSION set by build.rs, fallback to 0.1.0 if not available
55        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/// Dev-dependencies of the cargo project.
63#[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/// Empty workspace to indicate this crate is standalone.
79#[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/// Cargo Manifest for the zink project.
95#[derive(Serialize, Deserialize, Debug, Clone)]
96pub struct Manifest {
97    /// Package section of cargo manifest.
98    pub package: Package,
99    /// Lib section of cargo manifest.
100    pub lib: Lib,
101    /// Dependencies of the cargo project.
102    pub dependencies: Dependencies,
103    /// Dev-dependencies of the cargo project.
104    #[serde(default, skip_serializing_if = "Option::is_none")]
105    #[serde(rename = "dev-dependencies")]
106    pub dev_dependencies: Option<DevDependencies>,
107    /// Empty workspace to indicate this crate is standalone.
108    #[serde(default)]
109    pub workspace: Workspace,
110}
111
112impl Manifest {
113    /// Set package name
114    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        // Check that it’s not hardcoded to 0.1.0 unless fallback is triggered
137        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}