1use std::collections::BTreeMap;
2use std::env;
3use std::ffi::OsString;
4use std::path::PathBuf;
5
6#[derive(Default)]
7pub(crate) struct Crate {
8 pub include_prefix: Option<PathBuf>,
9 pub links: Option<OsString>,
10 pub header_dirs: Vec<HeaderDir>,
11}
12
13pub(crate) struct HeaderDir {
14 pub exported: bool,
15 pub path: PathBuf,
16}
17
18impl Crate {
19 pub(crate) fn print_to_cargo(&self) {
20 if let Some(include_prefix) = &self.include_prefix {
21 println!(
22 "cargo:CXXBRIDGE_PREFIX={}",
23 include_prefix.to_string_lossy(),
24 );
25 }
26 if let Some(links) = &self.links {
27 println!("cargo:CXXBRIDGE_LINKS={}", links.to_string_lossy());
28 }
29 for (i, header_dir) in self.header_dirs.iter().enumerate() {
30 if header_dir.exported {
31 println!(
32 "cargo:CXXBRIDGE_DIR{}={}",
33 i,
34 header_dir.path.to_string_lossy(),
35 );
36 }
37 }
38 }
39}
40
41pub(crate) fn direct_dependencies() -> Vec<Crate> {
42 let mut crates: BTreeMap<String, Crate> = BTreeMap::new();
43 let mut exported_header_dirs: BTreeMap<String, Vec<(usize, PathBuf)>> = BTreeMap::new();
44
45 for (k, v) in env::vars_os() {
61 let mut k = k.to_string_lossy().into_owned();
62 if !k.starts_with("DEP_") {
63 continue;
64 }
65
66 if k.ends_with("_CXXBRIDGE_PREFIX") {
67 k.truncate(k.len() - "_CXXBRIDGE_PREFIX".len());
68 crates.entry(k).or_default().include_prefix = Some(PathBuf::from(v));
69 continue;
70 }
71
72 if k.ends_with("_CXXBRIDGE_LINKS") {
73 k.truncate(k.len() - "_CXXBRIDGE_LINKS".len());
74 crates.entry(k).or_default().links = Some(v);
75 continue;
76 }
77
78 let without_counter = k.trim_end_matches(|ch: char| ch.is_ascii_digit());
79 let counter_len = k.len() - without_counter.len();
80 if counter_len == 0 || !without_counter.ends_with("_CXXBRIDGE_DIR") {
81 continue;
82 }
83
84 let sort_key = k[k.len() - counter_len..]
85 .parse::<usize>()
86 .unwrap_or(usize::MAX);
87 k.truncate(k.len() - counter_len - "_CXXBRIDGE_DIR".len());
88 exported_header_dirs
89 .entry(k)
90 .or_default()
91 .push((sort_key, PathBuf::from(v)));
92 }
93
94 for (k, mut dirs) in exported_header_dirs {
95 dirs.sort_by_key(|(sort_key, _dir)| *sort_key);
96 crates
97 .entry(k)
98 .or_default()
99 .header_dirs
100 .extend(dirs.into_iter().map(|(_sort_key, dir)| HeaderDir {
101 exported: true,
102 path: dir,
103 }));
104 }
105
106 crates.into_iter().map(|entry| entry.1).collect()
107}