cargo/util/config/
value.rs1use crate::util::config::Config;
12use serde::de;
13use std::fmt;
14use std::marker;
15use std::mem;
16use std::path::{Path, PathBuf};
17
18#[derive(Debug, PartialEq, Clone)]
21pub struct Value<T> {
22 pub val: T,
24 pub definition: Definition,
27}
28
29pub type OptValue<T> = Option<Value<T>>;
30
31pub(crate) const VALUE_FIELD: &str = "$__cargo_private_value";
50pub(crate) const DEFINITION_FIELD: &str = "$__cargo_private_definition";
51pub(crate) const NAME: &str = "$__cargo_private_Value";
52pub(crate) static FIELDS: [&str; 2] = [VALUE_FIELD, DEFINITION_FIELD];
53
54#[derive(Clone, Debug, Eq)]
56pub enum Definition {
57 Path(PathBuf),
59 Environment(String),
61 Cli,
63}
64
65impl Definition {
66 pub fn root<'a>(&'a self, config: &'a Config) -> &'a Path {
71 match self {
72 Definition::Path(p) => p.parent().unwrap().parent().unwrap(),
73 Definition::Environment(_) | Definition::Cli => config.cwd(),
74 }
75 }
76
77 pub fn is_higher_priority(&self, other: &Definition) -> bool {
81 match (self, other) {
82 (Definition::Cli, Definition::Environment(_)) => true,
83 (Definition::Cli, Definition::Path(_)) => true,
84 (Definition::Environment(_), Definition::Path(_)) => true,
85 _ => false,
86 }
87 }
88}
89
90impl PartialEq for Definition {
91 fn eq(&self, other: &Definition) -> bool {
92 mem::discriminant(self) == mem::discriminant(other)
97 }
98}
99
100impl fmt::Display for Definition {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 match self {
103 Definition::Path(p) => p.display().fmt(f),
104 Definition::Environment(key) => write!(f, "environment variable `{}`", key),
105 Definition::Cli => write!(f, "--config cli option"),
106 }
107 }
108}
109
110impl<'de, T> de::Deserialize<'de> for Value<T>
111where
112 T: de::Deserialize<'de>,
113{
114 fn deserialize<D>(deserializer: D) -> Result<Value<T>, D::Error>
115 where
116 D: de::Deserializer<'de>,
117 {
118 struct ValueVisitor<T> {
119 _marker: marker::PhantomData<T>,
120 }
121
122 impl<'de, T> de::Visitor<'de> for ValueVisitor<T>
123 where
124 T: de::Deserialize<'de>,
125 {
126 type Value = Value<T>;
127
128 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
129 formatter.write_str("a value")
130 }
131
132 fn visit_map<V>(self, mut visitor: V) -> Result<Value<T>, V::Error>
133 where
134 V: de::MapAccess<'de>,
135 {
136 let value = visitor.next_key::<ValueKey>()?;
137 if value.is_none() {
138 return Err(de::Error::custom("value not found"));
139 }
140 let val: T = visitor.next_value()?;
141
142 let definition = visitor.next_key::<DefinitionKey>()?;
143 if definition.is_none() {
144 return Err(de::Error::custom("definition not found"));
145 }
146 let definition: Definition = visitor.next_value()?;
147 Ok(Value { val, definition })
148 }
149 }
150
151 deserializer.deserialize_struct(
152 NAME,
153 &FIELDS,
154 ValueVisitor {
155 _marker: marker::PhantomData,
156 },
157 )
158 }
159}
160
161struct FieldVisitor {
162 expected: &'static str,
163}
164
165impl<'de> de::Visitor<'de> for FieldVisitor {
166 type Value = ();
167
168 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
169 formatter.write_str("a valid value field")
170 }
171
172 fn visit_str<E>(self, s: &str) -> Result<(), E>
173 where
174 E: de::Error,
175 {
176 if s == self.expected {
177 Ok(())
178 } else {
179 Err(de::Error::custom("expected field with custom name"))
180 }
181 }
182}
183
184struct ValueKey;
185
186impl<'de> de::Deserialize<'de> for ValueKey {
187 fn deserialize<D>(deserializer: D) -> Result<ValueKey, D::Error>
188 where
189 D: de::Deserializer<'de>,
190 {
191 deserializer.deserialize_identifier(FieldVisitor {
192 expected: VALUE_FIELD,
193 })?;
194 Ok(ValueKey)
195 }
196}
197
198struct DefinitionKey;
199
200impl<'de> de::Deserialize<'de> for DefinitionKey {
201 fn deserialize<D>(deserializer: D) -> Result<DefinitionKey, D::Error>
202 where
203 D: de::Deserializer<'de>,
204 {
205 deserializer.deserialize_identifier(FieldVisitor {
206 expected: DEFINITION_FIELD,
207 })?;
208 Ok(DefinitionKey)
209 }
210}
211
212impl<'de> de::Deserialize<'de> for Definition {
213 fn deserialize<D>(deserializer: D) -> Result<Definition, D::Error>
214 where
215 D: de::Deserializer<'de>,
216 {
217 let (discr, value) = <(u32, String)>::deserialize(deserializer)?;
218 match discr {
219 0 => Ok(Definition::Path(value.into())),
220 1 => Ok(Definition::Environment(value)),
221 2 => Ok(Definition::Cli),
222 _ => panic!("unexpected discriminant {} value {}", discr, value),
223 }
224 }
225}