mirror of https://github.com/rust-lang/cargo
Add support for deserializing Vec<Value<String>> in config.
This adds the ability to track the definition location of a string in a TOML array.
This commit is contained in:
parent
c9bff1ec6d
commit
95c98116e3
|
@ -384,7 +384,12 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
|
|||
{
|
||||
match self.list_iter.next() {
|
||||
// TODO: add `def` to error?
|
||||
Some((value, _def)) => seed.deserialize(value.into_deserializer()).map(Some),
|
||||
Some((value, def)) => {
|
||||
// This might be a String or a Value<String>.
|
||||
// ValueDeserializer will handle figuring out which one it is.
|
||||
let maybe_value_de = ValueDeserializer::new_with_string(value, def);
|
||||
seed.deserialize(maybe_value_de).map(Some)
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +405,17 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
|
|||
struct ValueDeserializer<'config> {
|
||||
hits: u32,
|
||||
definition: Definition,
|
||||
de: Deserializer<'config>,
|
||||
/// The deserializer, used to actually deserialize a Value struct.
|
||||
/// This is `None` if deserializing a string.
|
||||
de: Option<Deserializer<'config>>,
|
||||
/// A string value to deserialize.
|
||||
///
|
||||
/// This is used for situations where you can't address a string via a
|
||||
/// TOML key, such as a string inside an array. The `ConfigSeqAccess`
|
||||
/// doesn't know if the type it should deserialize to is a `String` or
|
||||
/// `Value<String>`, so `ValueDeserializer` needs to be able to handle
|
||||
/// both.
|
||||
str_value: Option<String>,
|
||||
}
|
||||
|
||||
impl<'config> ValueDeserializer<'config> {
|
||||
|
@ -428,9 +443,19 @@ impl<'config> ValueDeserializer<'config> {
|
|||
Ok(ValueDeserializer {
|
||||
hits: 0,
|
||||
definition,
|
||||
de,
|
||||
de: Some(de),
|
||||
str_value: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn new_with_string(s: String, definition: Definition) -> ValueDeserializer<'config> {
|
||||
ValueDeserializer {
|
||||
hits: 0,
|
||||
definition,
|
||||
de: None,
|
||||
str_value: Some(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
|
||||
|
@ -459,9 +484,14 @@ impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
|
|||
// If this is the first time around we deserialize the `value` field
|
||||
// which is the actual deserializer
|
||||
if self.hits == 1 {
|
||||
return seed
|
||||
.deserialize(self.de.clone())
|
||||
.map_err(|e| e.with_key_context(&self.de.key, self.definition.clone()));
|
||||
if let Some(de) = &self.de {
|
||||
return seed
|
||||
.deserialize(de.clone())
|
||||
.map_err(|e| e.with_key_context(&de.key, self.definition.clone()));
|
||||
} else {
|
||||
return seed
|
||||
.deserialize(self.str_value.as_ref().unwrap().clone().into_deserializer());
|
||||
}
|
||||
}
|
||||
|
||||
// ... otherwise we're deserializing the `definition` field, so we need
|
||||
|
@ -484,6 +514,71 @@ impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
|
|||
}
|
||||
}
|
||||
|
||||
// Deserializer is only implemented to handle deserializing a String inside a
|
||||
// sequence (like `Vec<String>` or `Vec<Value<String>>`). `Value<String>` is
|
||||
// handled by deserialize_struct, and the plain `String` is handled by all the
|
||||
// other functions here.
|
||||
impl<'de, 'config> de::Deserializer<'de> for ValueDeserializer<'config> {
|
||||
type Error = ConfigError;
|
||||
|
||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_str(&self.str_value.expect("string expected"))
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_string(self.str_value.expect("string expected"))
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
// Match on the magical struct name/field names that are passed in to
|
||||
// detect when we're deserializing `Value<T>`.
|
||||
//
|
||||
// See more comments in `value.rs` for the protocol used here.
|
||||
if name == value::NAME && fields == value::FIELDS {
|
||||
return visitor.visit_map(self);
|
||||
}
|
||||
unimplemented!("only strings and Value can be deserialized from a sequence");
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_string(self.str_value.expect("string expected"))
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_unit()
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
i8 i16 i32 i64
|
||||
u8 u16 u32 u64
|
||||
option
|
||||
newtype_struct seq tuple tuple_struct map enum bool
|
||||
f32 f64 char bytes
|
||||
byte_buf unit unit_struct
|
||||
identifier
|
||||
}
|
||||
}
|
||||
|
||||
/// A deserializer which takes two values and deserializes into a tuple of those
|
||||
/// two values. This is similar to types like `StrDeserializer` in upstream
|
||||
/// serde itself.
|
||||
|
|
Loading…
Reference in New Issue