target_spec/
simple_eval.rs

1// Copyright (c) The cargo-guppy Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use crate::{
5    Error, TargetSpec,
6    platform::{Platform, TargetFeatures},
7};
8
9/// Evaluates the given spec against the provided target and returns `Some(true)` on a successful
10/// match, and `Some(false)` on a failing match.
11///
12/// This defaults to treating target features as unknown, and returns `None` if the overall result
13/// is unknown.
14///
15/// For more advanced uses, see [`TargetSpec::eval`].
16///
17/// For more information, see the crate-level documentation.
18pub fn eval(spec_or_triple: &str, platform: &str) -> Result<Option<bool>, Error> {
19    let target_spec = spec_or_triple.parse::<TargetSpec>()?;
20    let platform = Platform::new(platform.to_owned(), TargetFeatures::Unknown)?;
21    Ok(target_spec.eval(&platform))
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27
28    #[test]
29    fn test_windows() {
30        assert_eq!(
31            eval("cfg(windows)", "x86_64-pc-windows-msvc").unwrap(),
32            Some(true),
33        );
34    }
35
36    #[test]
37    fn test_not_target_os() {
38        assert_eq!(
39            eval(
40                "cfg(not(target_os = \"windows\"))",
41                "x86_64-unknown-linux-gnu"
42            )
43            .unwrap(),
44            Some(true),
45        );
46    }
47
48    #[test]
49    fn test_not_target_os_false() {
50        assert_eq!(
51            eval(
52                "cfg(not(target_os = \"windows\"))",
53                "x86_64-pc-windows-msvc"
54            )
55            .unwrap(),
56            Some(false),
57        );
58    }
59
60    #[test]
61    fn test_exact_triple() {
62        assert_eq!(
63            eval("x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu").unwrap(),
64            Some(true),
65        );
66    }
67
68    #[test]
69    fn test_redox() {
70        assert_eq!(
71            eval(
72                "cfg(any(unix, target_os = \"redox\"))",
73                "x86_64-unknown-linux-gnu"
74            )
75            .unwrap(),
76            Some(true),
77        );
78    }
79
80    #[test]
81    fn test_bogus_families() {
82        // Known bogus families.
83        for family in &["test", "debug_assertions", "proc_macro"] {
84            let cfg = format!("cfg({})", family);
85            let cfg_not = format!("cfg(not({}))", family);
86            assert_eq!(eval(&cfg, "x86_64-unknown-linux-gnu").unwrap(), Some(false));
87            assert_eq!(
88                eval(&cfg_not, "x86_64-unknown-linux-gnu").unwrap(),
89                Some(true)
90            );
91        }
92
93        // Unknown bogus families.
94        let platform = Platform::new("x86_64-unknown-linux-gnu", TargetFeatures::Unknown).unwrap();
95        let mut platform_with_flags = platform.clone();
96        platform_with_flags.add_flags(["foo", "bar"].iter().copied());
97
98        for family in &["foo", "bar"] {
99            let cfg = format!("cfg({})", family);
100            let cfg_not = format!("cfg(not({}))", family);
101
102            // eval always means flags are evaluated to false.
103            assert_eq!(eval(&cfg, "x86_64-unknown-linux-gnu").unwrap(), Some(false));
104            assert_eq!(
105                eval(&cfg_not, "x86_64-unknown-linux-gnu").unwrap(),
106                Some(true)
107            );
108
109            let spec: TargetSpec = cfg.parse().unwrap();
110            let spec_not: TargetSpec = cfg_not.parse().unwrap();
111
112            // flag missing means false.
113            assert_eq!(spec.eval(&platform), Some(false));
114            assert_eq!(spec_not.eval(&platform), Some(true));
115
116            // flag present means true.
117            assert_eq!(spec.eval(&platform_with_flags), Some(true));
118            assert_eq!(spec_not.eval(&platform_with_flags), Some(false));
119        }
120
121        for family in &["baz", "nonsense"] {
122            let cfg = format!("cfg({})", family);
123            let cfg_not = format!("cfg(not({}))", family);
124
125            // eval always means flags are evaluated to false.
126            assert_eq!(eval(&cfg, "x86_64-unknown-linux-gnu").unwrap(), Some(false));
127            assert_eq!(
128                eval(&cfg_not, "x86_64-unknown-linux-gnu").unwrap(),
129                Some(true)
130            );
131
132            let spec: TargetSpec = cfg.parse().unwrap();
133            let spec_not: TargetSpec = cfg_not.parse().unwrap();
134
135            // flag missing means false.
136            assert_eq!(spec.eval(&platform), Some(false));
137            assert_eq!(spec_not.eval(&platform), Some(true));
138
139            // flag still missing means false.
140            assert_eq!(spec.eval(&platform_with_flags), Some(false));
141            assert_eq!(spec_not.eval(&platform_with_flags), Some(true));
142        }
143    }
144
145    #[test]
146    fn test_target_feature() {
147        // target features are unknown by default.
148        assert_eq!(
149            eval("cfg(target_feature = \"sse\")", "x86_64-unknown-linux-gnu").unwrap(),
150            None,
151        );
152        assert_eq!(
153            eval(
154                "cfg(target_feature = \"atomics\")",
155                "x86_64-unknown-linux-gnu",
156            )
157            .unwrap(),
158            None,
159        );
160        assert_eq!(
161            eval(
162                "cfg(not(target_feature = \"fxsr\"))",
163                "x86_64-unknown-linux-gnu",
164            )
165            .unwrap(),
166            None,
167        );
168
169        fn eval_unknown(spec: &str, platform: &str) -> Option<bool> {
170            let platform = Platform::new(
171                platform.to_owned(),
172                TargetFeatures::features(["sse", "sse2"].iter().copied()),
173            )
174            .expect("platform should be found");
175            let spec: TargetSpec = spec.parse().unwrap();
176            spec.eval(&platform)
177        }
178
179        assert_eq!(
180            eval_unknown("cfg(target_feature = \"sse\")", "x86_64-unknown-linux-gnu"),
181            Some(true),
182        );
183        assert_eq!(
184            eval_unknown(
185                "cfg(not(target_feature = \"sse\"))",
186                "x86_64-unknown-linux-gnu",
187            ),
188            Some(false),
189        );
190        assert_eq!(
191            eval_unknown("cfg(target_feature = \"fxsr\")", "x86_64-unknown-linux-gnu"),
192            Some(false),
193        );
194        assert_eq!(
195            eval_unknown(
196                "cfg(not(target_feature = \"fxsr\"))",
197                "x86_64-unknown-linux-gnu",
198            ),
199            Some(true),
200        );
201
202        fn eval_all(spec: &str, platform: &str) -> Option<bool> {
203            let platform = Platform::new(platform.to_owned(), TargetFeatures::All)
204                .expect("platform should be found");
205            let spec: TargetSpec = spec.parse().unwrap();
206            spec.eval(&platform)
207        }
208
209        assert_eq!(
210            eval_all("cfg(target_feature = \"sse\")", "x86_64-unknown-linux-gnu"),
211            Some(true),
212        );
213        assert_eq!(
214            eval_all(
215                "cfg(not(target_feature = \"sse\"))",
216                "x86_64-unknown-linux-gnu",
217            ),
218            Some(false),
219        );
220        assert_eq!(
221            eval_all("cfg(target_feature = \"fxsr\")", "x86_64-unknown-linux-gnu"),
222            Some(true),
223        );
224        assert_eq!(
225            eval_all(
226                "cfg(not(target_feature = \"fxsr\"))",
227                "x86_64-unknown-linux-gnu",
228            ),
229            Some(false),
230        );
231    }
232}