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