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