cargo/util/context/
value.rs1use crate::util::context::GlobalContext;
46use serde::de;
47use std::cmp::Ordering;
48use std::fmt;
49use std::marker;
50use std::mem;
51use std::path::{Path, PathBuf};
52
53#[derive(Debug, PartialEq, Clone)]
56pub struct Value<T> {
57 pub val: T,
59 pub definition: Definition,
62}
63
64pub type OptValue<T> = Option<Value<T>>;
65
66pub(crate) const VALUE_FIELD: &str = "$__cargo_private_value";
69pub(crate) const DEFINITION_FIELD: &str = "$__cargo_private_definition";
70pub(crate) const NAME: &str = "$__cargo_private_Value";
71pub(crate) static FIELDS: [&str; 2] = [VALUE_FIELD, DEFINITION_FIELD];
72
73#[derive(Clone, Debug, Eq)]
75pub enum Definition {
76 BuiltIn,
77 Path(PathBuf),
79 Environment(String),
81 Cli(Option<PathBuf>),
84}
85
86impl PartialOrd for Definition {
87 fn partial_cmp(&self, other: &Definition) -> Option<Ordering> {
88 Some(self.cmp(other))
89 }
90}
91
92impl Ord for Definition {
93 fn cmp(&self, other: &Definition) -> Ordering {
94 if mem::discriminant(self) == mem::discriminant(other) {
95 Ordering::Equal
96 } else if self.is_higher_priority(other) {
97 Ordering::Greater
98 } else {
99 Ordering::Less
100 }
101 }
102}
103
104impl Definition {
105 pub fn root<'a>(&'a self, gctx: &'a GlobalContext) -> &'a Path {
110 match self {
111 Definition::Path(p) | Definition::Cli(Some(p)) => p.parent().unwrap().parent().unwrap(),
112 Definition::Environment(_) | Definition::Cli(None) | Definition::BuiltIn => gctx.cwd(),
113 }
114 }
115
116 pub fn is_higher_priority(&self, other: &Definition) -> bool {
120 matches!(
121 (self, other),
122 (Definition::Cli(_), Definition::Environment(_))
123 | (Definition::Cli(_), Definition::Path(_))
124 | (Definition::Cli(_), Definition::BuiltIn)
125 | (Definition::Environment(_), Definition::Path(_))
126 | (Definition::Environment(_), Definition::BuiltIn)
127 | (Definition::Path(_), Definition::BuiltIn)
128 )
129 }
130}
131
132impl PartialEq for Definition {
133 fn eq(&self, other: &Definition) -> bool {
134 mem::discriminant(self) == mem::discriminant(other)
139 }
140}
141
142impl fmt::Display for Definition {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 match self {
145 Definition::Path(p) | Definition::Cli(Some(p)) => p.display().fmt(f),
146 Definition::Environment(key) => write!(f, "environment variable `{}`", key),
147 Definition::Cli(None) => write!(f, "--config cli option"),
148 Definition::BuiltIn => write!(f, "default"),
149 }
150 }
151}
152
153impl<T> From<T> for Value<T> {
154 fn from(val: T) -> Self {
155 Self {
156 val,
157 definition: Definition::BuiltIn,
158 }
159 }
160}
161
162impl<'de, T> de::Deserialize<'de> for Value<T>
163where
164 T: de::Deserialize<'de>,
165{
166 fn deserialize<D>(deserializer: D) -> Result<Value<T>, D::Error>
167 where
168 D: de::Deserializer<'de>,
169 {
170 struct ValueVisitor<T> {
171 _marker: marker::PhantomData<T>,
172 }
173
174 impl<'de, T> de::Visitor<'de> for ValueVisitor<T>
175 where
176 T: de::Deserialize<'de>,
177 {
178 type Value = Value<T>;
179
180 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
181 formatter.write_str("a value")
182 }
183
184 fn visit_map<V>(self, mut visitor: V) -> Result<Value<T>, V::Error>
185 where
186 V: de::MapAccess<'de>,
187 {
188 let value = visitor.next_key::<ValueKey>()?;
189 if value.is_none() {
190 return Err(de::Error::custom("value not found"));
191 }
192 let val: T = visitor.next_value()?;
193
194 let definition = visitor.next_key::<DefinitionKey>()?;
195 if definition.is_none() {
196 return Err(de::Error::custom("definition not found"));
197 }
198 let definition: Definition = visitor.next_value()?;
199 Ok(Value { val, definition })
200 }
201 }
202
203 deserializer.deserialize_struct(
204 NAME,
205 &FIELDS,
206 ValueVisitor {
207 _marker: marker::PhantomData,
208 },
209 )
210 }
211}
212
213struct FieldVisitor {
214 expected: &'static str,
215}
216
217impl<'de> de::Visitor<'de> for FieldVisitor {
218 type Value = ();
219
220 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
221 formatter.write_str("a valid value field")
222 }
223
224 fn visit_str<E>(self, s: &str) -> Result<(), E>
225 where
226 E: de::Error,
227 {
228 if s == self.expected {
229 Ok(())
230 } else {
231 Err(de::Error::custom("expected field with custom name"))
232 }
233 }
234}
235
236struct ValueKey;
237
238impl<'de> de::Deserialize<'de> for ValueKey {
239 fn deserialize<D>(deserializer: D) -> Result<ValueKey, D::Error>
240 where
241 D: de::Deserializer<'de>,
242 {
243 deserializer.deserialize_identifier(FieldVisitor {
244 expected: VALUE_FIELD,
245 })?;
246 Ok(ValueKey)
247 }
248}
249
250struct DefinitionKey;
251
252impl<'de> de::Deserialize<'de> for DefinitionKey {
253 fn deserialize<D>(deserializer: D) -> Result<DefinitionKey, D::Error>
254 where
255 D: de::Deserializer<'de>,
256 {
257 deserializer.deserialize_identifier(FieldVisitor {
258 expected: DEFINITION_FIELD,
259 })?;
260 Ok(DefinitionKey)
261 }
262}
263
264impl<'de> de::Deserialize<'de> for Definition {
265 fn deserialize<D>(deserializer: D) -> Result<Definition, D::Error>
266 where
267 D: de::Deserializer<'de>,
268 {
269 let (discr, value) = <(u32, String)>::deserialize(deserializer)?;
270 match discr {
271 0 => Ok(Definition::BuiltIn),
272 1 => Ok(Definition::Path(value.into())),
273 2 => Ok(Definition::Environment(value)),
274 3 => {
275 let path = (value.len() > 0).then_some(value.into());
276 Ok(Definition::Cli(path))
277 }
278 _ => panic!("unexpected discriminant {discr} value {value}"),
279 }
280 }
281}