1use std::path::{Path, PathBuf};
7
8pub const LINKS_ENV_PREFIX: &str = "DEP_RNP_";
17
18pub const LINKS_LIB_DIR_SUFFIX: &str = "_LIB_DIR";
21
22pub const DEPS: &[&str] = &["botan", "jsonc", "zlib", "bzip2"];
27
28pub fn lib_dir_env_var(name: &str) -> String {
33 format!("{LINKS_ENV_PREFIX}{name}{LINKS_LIB_DIR_SUFFIX}").to_uppercase()
34}
35
36#[derive(Debug, Clone, Default)]
41pub struct Deps {
42 items: Vec<Dep>,
43}
44
45#[derive(Debug, Clone)]
46pub struct Dep {
47 pub name: &'static str,
48 pub prefix: PathBuf,
49}
50
51impl Deps {
52 pub fn new() -> Self {
53 Self { items: Vec::new() }
54 }
55
56 pub fn push(&mut self, name: &'static str, prefix: PathBuf) {
57 assert!(
58 DEPS.contains(&name),
59 "rnp-src: Deps::push({name}) — name not in DEPS; update src/links.rs first"
60 );
61 self.items.push(Dep { name, prefix });
62 }
63
64 pub fn by_name(&self, name: &str) -> Option<&Dep> {
65 self.items.iter().find(|d| d.name == name)
66 }
67
68 pub fn cmake_prefix_path(&self) -> String {
70 self.items
71 .iter()
72 .map(|d| d.prefix.display().to_string())
73 .collect::<Vec<_>>()
74 .join(";")
75 }
76
77 pub fn emit_cargo_paths(&self) {
80 for dep in &self.items {
81 println!(
82 "cargo:{}_lib_dir={}",
83 dep.name,
84 dep.prefix.join("lib").display()
85 );
86 }
87 }
88
89 pub fn iter(&self) -> impl Iterator<Item = &Dep> {
90 self.items.iter()
91 }
92}
93
94#[derive(Debug, Clone)]
99pub struct CmakeDep {
100 pub name: &'static str,
101 pub version: &'static str,
102 pub url_template: &'static str,
104 pub extra_cmake_args: &'static [&'static str],
107 pub cmake_policy_minimum: Option<&'static str>,
109}
110
111impl CmakeDep {
112 pub fn source_dir(&self, src_root: &Path) -> PathBuf {
113 src_root.join(format!("{}-{}", self.name, self.version))
114 }
115
116 pub fn build_dir(&self, src_root: &Path) -> PathBuf {
117 src_root.join(format!("{}-build", self.name))
118 }
119
120 pub fn url(&self) -> String {
121 self.url_template.replace("{version}", self.version)
122 }
123}
124
125pub const JSON_C: CmakeDep = CmakeDep {
127 name: "json-c",
128 version: "0.17",
129 url_template: "https://s3.amazonaws.com/json-c_releases/releases/json-c-{version}.tar.gz",
130 extra_cmake_args: &["-DBUILD_TESTING=OFF"],
131 cmake_policy_minimum: Some("3.5"),
132};
133
134pub const ZLIB: CmakeDep = CmakeDep {
135 name: "zlib",
136 version: "1.3.1",
137 url_template: "https://github.com/madler/zlib/releases/download/v{version}/zlib-{version}.tar.gz",
138 extra_cmake_args: &[],
139 cmake_policy_minimum: None,
140};
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn lib_dir_env_var_for_botan() {
148 assert_eq!(lib_dir_env_var("botan"), "DEP_RNP_BOTAN_LIB_DIR");
149 }
150
151 #[test]
152 fn lib_dir_env_var_for_zlib() {
153 assert_eq!(lib_dir_env_var("zlib"), "DEP_RNP_ZLIB_LIB_DIR");
154 }
155
156 #[test]
157 fn all_deps_produce_well_formed_env_vars() {
158 for &name in DEPS {
159 let var = lib_dir_env_var(name);
160 assert!(var.starts_with(LINKS_ENV_PREFIX));
161 assert!(var.ends_with(LINKS_LIB_DIR_SUFFIX));
162 }
163 }
164
165 #[test]
166 fn deps_cmake_prefix_path_joins_with_semicolon() {
167 let mut deps = Deps::new();
168 deps.push("botan", PathBuf::from("/a/botan"));
169 deps.push("jsonc", PathBuf::from("/b/json-c"));
170 assert_eq!(deps.cmake_prefix_path(), "/a/botan;/b/json-c");
171 }
172
173 #[test]
174 fn empty_deps_yields_empty_prefix_path() {
175 let deps = Deps::new();
176 assert_eq!(deps.cmake_prefix_path(), "");
177 }
178
179 #[test]
180 fn deps_by_name_finds_pushed_entry() {
181 let mut deps = Deps::new();
182 deps.push("botan", PathBuf::from("/x/botan"));
183 assert_eq!(
184 deps.by_name("botan").map(|d| d.prefix.clone()),
185 Some(PathBuf::from("/x/botan"))
186 );
187 assert!(deps.by_name("jsonc").is_none());
188 }
189
190 #[test]
191 fn deps_push_rejects_unknown_name() {
192 let mut deps = Deps::new();
193 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
194 deps.push("nonexistent", PathBuf::from("/x"));
195 }));
196 assert!(result.is_err(), "push should panic for unknown dep name");
197 }
198
199 #[test]
200 fn cmake_dep_source_and_build_dirs() {
201 let dep = CmakeDep {
202 name: "json-c",
203 version: "0.17",
204 url_template: "",
205 extra_cmake_args: &[],
206 cmake_policy_minimum: None,
207 };
208 let root = Path::new("/tmp/src");
209 assert_eq!(dep.source_dir(root), PathBuf::from("/tmp/src/json-c-0.17"));
210 assert_eq!(dep.build_dir(root), PathBuf::from("/tmp/src/json-c-build"));
211 }
212
213 #[test]
214 fn cmake_dep_url_substitutes_version() {
215 assert_eq!(
216 JSON_C.url(),
217 "https://s3.amazonaws.com/json-c_releases/releases/json-c-0.17.tar.gz"
218 );
219 assert_eq!(
220 ZLIB.url(),
221 "https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.gz"
222 );
223 }
224}