cargo/util/context/
value.rs
1use 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 Path(PathBuf),
60 Environment(String),
62 Cli(Option<PathBuf>),
65}
66
67impl PartialOrd for Definition {
68 fn partial_cmp(&self, other: &Definition) -> Option<Ordering> {
69 Some(self.cmp(other))
70 }
71}
72
73impl Ord for Definition {
74 fn cmp(&self, other: &Definition) -> Ordering {
75 if mem::discriminant(self) == mem::discriminant(other) {
76 Ordering::Equal
77 } else if self.is_higher_priority(other) {
78 Ordering::Greater
79 } else {
80 Ordering::Less
81 }
82 }
83}
84
85impl Definition {
86 pub fn root<'a>(&'a self, gctx: &'a GlobalContext) -> &'a Path {
91 match self {
92 Definition::Path(p) | Definition::Cli(Some(p)) => p.parent().unwrap().parent().unwrap(),
93 Definition::Environment(_) | Definition::Cli(None) => gctx.cwd(),
94 }
95 }
96
97 pub fn is_higher_priority(&self, other: &Definition) -> bool {
101 matches!(
102 (self, other),
103 (Definition::Cli(_), Definition::Environment(_))
104 | (Definition::Cli(_), Definition::Path(_))
105 | (Definition::Environment(_), Definition::Path(_))
106 )
107 }
108}
109
110impl PartialEq for Definition {
111 fn eq(&self, other: &Definition) -> bool {
112 mem::discriminant(self) == mem::discriminant(other)
117 }
118}
119
120impl fmt::Display for Definition {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self {
123 Definition::Path(p) | Definition::Cli(Some(p)) => p.display().fmt(f),
124 Definition::Environment(key) => write!(f, "environment variable `{}`", key),
125 Definition::Cli(None) => write!(f, "--config cli option"),
126 }
127 }
128}
129
130impl<'de, T> de::Deserialize<'de> for Value<T>
131where
132 T: de::Deserialize<'de>,
133{
134 fn deserialize<D>(deserializer: D) -> Result<Value<T>, D::Error>
135 where
136 D: de::Deserializer<'de>,
137 {
138 struct ValueVisitor<T> {
139 _marker: marker::PhantomData<T>,
140 }
141
142 impl<'de, T> de::Visitor<'de> for ValueVisitor<T>
143 where
144 T: de::Deserialize<'de>,
145 {
146 type Value = Value<T>;
147
148 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
149 formatter.write_str("a value")
150 }
151
152 fn visit_map<V>(self, mut visitor: V) -> Result<Value<T>, V::Error>
153 where
154 V: de::MapAccess<'de>,
155 {
156 let value = visitor.next_key::<ValueKey>()?;
157 if value.is_none() {
158 return Err(de::Error::custom("value not found"));
159 }
160 let val: T = visitor.next_value()?;
161
162 let definition = visitor.next_key::<DefinitionKey>()?;
163 if definition.is_none() {
164 return Err(de::Error::custom("definition not found"));
165 }
166 let definition: Definition = visitor.next_value()?;
167 Ok(Value { val, definition })
168 }
169 }
170
171 deserializer.deserialize_struct(
172 NAME,
173 &FIELDS,
174 ValueVisitor {
175 _marker: marker::PhantomData,
176 },
177 )
178 }
179}
180
181struct FieldVisitor {
182 expected: &'static str,
183}
184
185impl<'de> de::Visitor<'de> for FieldVisitor {
186 type Value = ();
187
188 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
189 formatter.write_str("a valid value field")
190 }
191
192 fn visit_str<E>(self, s: &str) -> Result<(), E>
193 where
194 E: de::Error,
195 {
196 if s == self.expected {
197 Ok(())
198 } else {
199 Err(de::Error::custom("expected field with custom name"))
200 }
201 }
202}
203
204struct ValueKey;
205
206impl<'de> de::Deserialize<'de> for ValueKey {
207 fn deserialize<D>(deserializer: D) -> Result<ValueKey, D::Error>
208 where
209 D: de::Deserializer<'de>,
210 {
211 deserializer.deserialize_identifier(FieldVisitor {
212 expected: VALUE_FIELD,
213 })?;
214 Ok(ValueKey)
215 }
216}
217
218struct DefinitionKey;
219
220impl<'de> de::Deserialize<'de> for DefinitionKey {
221 fn deserialize<D>(deserializer: D) -> Result<DefinitionKey, D::Error>
222 where
223 D: de::Deserializer<'de>,
224 {
225 deserializer.deserialize_identifier(FieldVisitor {
226 expected: DEFINITION_FIELD,
227 })?;
228 Ok(DefinitionKey)
229 }
230}
231
232impl<'de> de::Deserialize<'de> for Definition {
233 fn deserialize<D>(deserializer: D) -> Result<Definition, D::Error>
234 where
235 D: de::Deserializer<'de>,
236 {
237 let (discr, value) = <(u32, String)>::deserialize(deserializer)?;
238 match discr {
239 0 => Ok(Definition::Path(value.into())),
240 1 => Ok(Definition::Environment(value)),
241 2 => {
242 let path = (value.len() > 0).then_some(value.into());
243 Ok(Definition::Cli(path))
244 }
245 _ => panic!("unexpected discriminant {discr} value {value}"),
246 }
247 }
248}