1use std::borrow::Cow;
11use std::collections::BTreeMap;
12
13use guppy::graph::PackageMetadata;
14use std::sync::LazyLock;
15
16use crate::ToBazelDefinition;
17use crate::targets::{AdditiveContent, RustTestSize};
18
19const KEY_NAME: &str = "cargo-gazelle";
20
21const LIB_TEST_NAME: &str = "lib";
25
26const DOC_TEST_NAME: &str = "doc";
30
31#[derive(Debug, Clone)]
33pub struct GlobalConfig {
34 pub ignored_crates: Vec<Cow<'static, str>>,
35 pub proto_build_crates: Vec<Cow<'static, str>>,
36}
37
38impl Default for GlobalConfig {
39 fn default() -> Self {
40 GlobalConfig {
41 ignored_crates: vec!["workspace-hack".into()],
42 proto_build_crates: vec!["prost_build".into(), "tonic_build".into()],
43 }
44 }
45}
46
47impl GlobalConfig {
48 pub fn include_dep(&self, name: &str) -> bool {
50 !self.ignored_crates.contains(&Cow::Borrowed(name))
51 }
52}
53
54#[derive(Default, Debug, serde::Deserialize)]
62pub struct CrateConfig {
63 #[serde(default)]
65 skip_generating: bool,
66 additive_content: Option<String>,
68
69 #[serde(default)]
71 lib: LibraryConfig,
72 #[serde(default)]
74 build: BuildConfig,
75 #[serde(alias = "test")]
77 #[serde(default)]
78 tests: BTreeMap<String, TestConfig>,
79 #[serde(alias = "binary")]
81 #[serde(default)]
82 binaries: BTreeMap<String, BinaryConfig>,
83}
84
85impl CrateConfig {
86 pub fn new(package: &PackageMetadata) -> Self {
87 package
88 .metadata_table()
89 .get(KEY_NAME)
90 .and_then(|v| serde_json::from_value(v.clone()).ok())
91 .unwrap_or_default()
92 }
93
94 pub fn skip_generating(&self) -> bool {
95 self.skip_generating
96 }
97
98 pub fn additive_content(&self) -> Option<AdditiveContent> {
99 self.additive_content
100 .as_ref()
101 .map(|s| AdditiveContent::new(s.as_str()))
102 }
103
104 pub fn lib(&self) -> &LibraryConfig {
105 &self.lib
106 }
107
108 pub fn lib_test(&self) -> &TestConfig {
109 self.test(LIB_TEST_NAME)
110 }
111
112 pub fn doc_test(&self) -> &TestConfig {
113 self.test(DOC_TEST_NAME)
114 }
115
116 pub fn build(&self) -> &BuildConfig {
117 &self.build
118 }
119
120 pub fn test(&self, name: &str) -> &TestConfig {
121 static EMPTY_TEST: LazyLock<TestConfig> = LazyLock::new(TestConfig::default);
122 self.tests.get(name).unwrap_or(&*EMPTY_TEST)
123 }
124
125 pub fn binary(&self, name: &str) -> &BinaryConfig {
126 static EMPTY_BINARY: LazyLock<BinaryConfig> = LazyLock::new(BinaryConfig::default);
127 self.binaries.get(name).unwrap_or(&*EMPTY_BINARY)
128 }
129}
130
131#[derive(Default, Debug, serde::Deserialize)]
135pub struct LibraryConfig {
136 #[serde(flatten)]
137 common: CommonConfig,
138
139 features_override: Option<Vec<String>>,
142 #[serde(default)]
144 extra_deps: Vec<String>,
145 #[serde(default)]
147 extra_proc_macro_deps: Vec<String>,
148 #[serde(default)]
150 disable_pipelining: Option<bool>,
151}
152
153impl LibraryConfig {
154 pub fn common(&self) -> &CommonConfig {
155 &self.common
156 }
157
158 pub fn features_override(&self) -> Option<&Vec<String>> {
159 self.features_override.as_ref()
160 }
161
162 pub fn extra_deps(&self) -> &[String] {
163 &self.extra_deps
164 }
165
166 pub fn extra_proc_macro_deps(&self) -> &[String] {
167 &self.extra_proc_macro_deps
168 }
169
170 pub fn disable_pipelining(&self) -> Option<bool> {
171 self.disable_pipelining
172 }
173}
174
175#[derive(Default, Debug, serde::Deserialize)]
179pub struct BuildConfig {
180 #[serde(flatten)]
181 common: CommonConfig,
182
183 #[serde(default)]
185 build_script_env: BTreeMap<String, String>,
186 #[serde(default)]
188 skip_proto_search: bool,
189}
190
191impl BuildConfig {
192 pub fn common(&self) -> &CommonConfig {
193 &self.common
194 }
195
196 pub fn build_script_env(&self) -> &BTreeMap<String, String> {
197 &self.build_script_env
198 }
199
200 pub fn skip_proto_search(&self) -> bool {
201 self.skip_proto_search
202 }
203}
204
205#[derive(Default, Debug, serde::Deserialize)]
209pub struct TestConfig {
210 #[serde(flatten)]
211 common: CommonConfig,
212
213 size: Option<RustTestSize>,
216 #[serde(default)]
218 env: BTreeMap<String, String>,
219}
220
221impl TestConfig {
222 pub fn common(&self) -> &CommonConfig {
223 &self.common
224 }
225
226 pub fn size(&self) -> Option<&RustTestSize> {
227 self.size.as_ref()
228 }
229
230 pub fn env(&self) -> &BTreeMap<String, String> {
231 &self.env
232 }
233}
234
235#[derive(Default, Debug, serde::Deserialize)]
239pub struct BinaryConfig {
240 #[serde(flatten)]
241 common: CommonConfig,
242
243 #[serde(default)]
245 env: BTreeMap<String, String>,
246}
247
248impl BinaryConfig {
249 pub fn common(&self) -> &CommonConfig {
250 &self.common
251 }
252
253 pub fn env(&self) -> &BTreeMap<String, String> {
254 &self.env
255 }
256}
257
258#[derive(Default, Debug, serde::Deserialize)]
260pub struct CommonConfig {
261 #[serde(default)]
263 skip: bool,
264 #[serde(default)]
266 compile_data: Vec<String>,
267 #[serde(default)]
269 data: Vec<String>,
270 #[serde(default)]
272 rustc_flags: Vec<String>,
273 #[serde(default)]
275 rustc_env: BTreeMap<String, String>,
276}
277
278impl CommonConfig {
279 pub fn skip(&self) -> bool {
280 self.skip
281 }
282
283 pub fn compile_data(&self) -> (Vec<&String>, Option<Vec<&String>>) {
285 let paths: Vec<_> = self
286 .compile_data
287 .iter()
288 .filter(|s| !s.contains('*'))
289 .collect();
290 let globs: Vec<_> = self
291 .compile_data
292 .iter()
293 .filter(|s| s.contains('*'))
294 .collect();
295
296 let globs = if globs.is_empty() { None } else { Some(globs) };
297
298 (paths, globs)
299 }
300
301 pub fn data(&self) -> (Vec<&String>, Option<Vec<&String>>) {
303 let paths: Vec<_> = self.data.iter().filter(|s| !s.contains('*')).collect();
304 let globs: Vec<_> = self.data.iter().filter(|s| s.contains('*')).collect();
305
306 let globs = if globs.is_empty() { None } else { Some(globs) };
307
308 (paths, globs)
309 }
310
311 pub fn rustc_flags(&self) -> &[String] {
312 &self.rustc_flags
313 }
314
315 pub fn rustc_env(&self) -> &BTreeMap<String, String> {
316 &self.rustc_env
317 }
318}
319
320#[derive(Debug, Copy, Clone)]
322pub enum ConfigSettingGroup {
323 XlangLtoEnabled,
324}
325
326impl ToBazelDefinition for ConfigSettingGroup {
327 fn format(&self, w: &mut dyn std::fmt::Write) -> Result<(), std::fmt::Error> {
328 match self {
329 ConfigSettingGroup::XlangLtoEnabled => {
330 write!(w, "\"@//misc/bazel/platforms:xlang_lto_enabled\"")?
331 }
332 }
333
334 Ok(())
335 }
336}