-
Notifications
You must be signed in to change notification settings - Fork 316
/
cargo.rs
153 lines (130 loc) · 3.86 KB
/
cargo.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use crate::gen::{CfgEvaluator, CfgResult};
use once_cell::sync::OnceCell;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::{BTreeMap as Map, BTreeSet as Set};
use std::env;
static ENV: OnceCell<CargoEnv> = OnceCell::new();
struct CargoEnv {
features: Set<Name>,
cfgs: Map<Name, String>,
}
pub(super) struct CargoEnvCfgEvaluator;
impl CfgEvaluator for CargoEnvCfgEvaluator {
fn eval(&self, name: &str, query_value: Option<&str>) -> CfgResult {
let env = ENV.get_or_init(CargoEnv::load);
if name == "feature" {
if let Some(query_value) = query_value {
CfgResult::from(env.features.contains(Lookup::new(query_value)))
} else {
let msg = "expected `feature = \"...\"`".to_owned();
CfgResult::Undetermined { msg }
}
} else {
match env.cfgs.get(Lookup::new(name)) {
Some(cargo_value) => {
if let Some(query_value) = query_value {
CfgResult::from(cargo_value.split(',').any(|value| value == query_value))
} else {
CfgResult::True
}
}
None => CfgResult::False,
}
}
}
}
impl CargoEnv {
fn load() -> Self {
const CARGO_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
const CARGO_CFG_PREFIX: &str = "CARGO_CFG_";
let mut features = Set::new();
let mut cfgs = Map::new();
for (k, v) in env::vars_os() {
let k = match k.to_str() {
Some(k) => k,
None => continue,
};
let v = match v.into_string() {
Ok(v) => v,
Err(_) => continue,
};
if let Some(feature_name) = k.strip_prefix(CARGO_FEATURE_PREFIX) {
let feature_name = Name(feature_name.to_owned());
features.insert(feature_name);
} else if let Some(cfg_name) = k.strip_prefix(CARGO_CFG_PREFIX) {
let cfg_name = Name(cfg_name.to_owned());
cfgs.insert(cfg_name, v);
}
}
CargoEnv { features, cfgs }
}
}
struct Name(String);
impl Ord for Name {
fn cmp(&self, rhs: &Self) -> Ordering {
Lookup::new(&self.0).cmp(Lookup::new(&rhs.0))
}
}
impl PartialOrd for Name {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
impl Eq for Name {}
impl PartialEq for Name {
fn eq(&self, rhs: &Self) -> bool {
Lookup::new(&self.0).eq(Lookup::new(&rhs.0))
}
}
#[repr(transparent)]
struct Lookup(str);
impl Lookup {
fn new(name: &str) -> &Self {
unsafe { &*(name as *const str as *const Self) }
}
}
impl Borrow<Lookup> for Name {
fn borrow(&self) -> &Lookup {
Lookup::new(&self.0)
}
}
impl Ord for Lookup {
fn cmp(&self, rhs: &Self) -> Ordering {
self.0
.bytes()
.map(CaseAgnosticByte)
.cmp(rhs.0.bytes().map(CaseAgnosticByte))
}
}
impl PartialOrd for Lookup {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
impl Eq for Lookup {}
impl PartialEq for Lookup {
fn eq(&self, rhs: &Self) -> bool {
self.0
.bytes()
.map(CaseAgnosticByte)
.eq(rhs.0.bytes().map(CaseAgnosticByte))
}
}
struct CaseAgnosticByte(u8);
impl Ord for CaseAgnosticByte {
fn cmp(&self, rhs: &Self) -> Ordering {
self.0.to_ascii_lowercase().cmp(&rhs.0.to_ascii_lowercase())
}
}
impl PartialOrd for CaseAgnosticByte {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
impl Eq for CaseAgnosticByte {}
impl PartialEq for CaseAgnosticByte {
fn eq(&self, rhs: &Self) -> bool {
self.cmp(rhs) == Ordering::Equal
}
}