Skip to content

Commit 9f62f84

Browse files
ehusspietroalbini
authored andcommitted
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.
1 parent 1387fd4 commit 9f62f84

File tree

1 file changed

+101
-6
lines changed
  • src/cargo/util/config

1 file changed

+101
-6
lines changed

src/cargo/util/config/de.rs

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,12 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
384384
{
385385
match self.list_iter.next() {
386386
// TODO: add `def` to error?
387-
Some((value, _def)) => seed.deserialize(value.into_deserializer()).map(Some),
387+
Some((value, def)) => {
388+
// This might be a String or a Value<String>.
389+
// ValueDeserializer will handle figuring out which one it is.
390+
let maybe_value_de = ValueDeserializer::new_with_string(value, def);
391+
seed.deserialize(maybe_value_de).map(Some)
392+
}
388393
None => Ok(None),
389394
}
390395
}
@@ -400,7 +405,17 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
400405
struct ValueDeserializer<'config> {
401406
hits: u32,
402407
definition: Definition,
403-
de: Deserializer<'config>,
408+
/// The deserializer, used to actually deserialize a Value struct.
409+
/// This is `None` if deserializing a string.
410+
de: Option<Deserializer<'config>>,
411+
/// A string value to deserialize.
412+
///
413+
/// This is used for situations where you can't address a string via a
414+
/// TOML key, such as a string inside an array. The `ConfigSeqAccess`
415+
/// doesn't know if the type it should deserialize to is a `String` or
416+
/// `Value<String>`, so `ValueDeserializer` needs to be able to handle
417+
/// both.
418+
str_value: Option<String>,
404419
}
405420

406421
impl<'config> ValueDeserializer<'config> {
@@ -428,9 +443,19 @@ impl<'config> ValueDeserializer<'config> {
428443
Ok(ValueDeserializer {
429444
hits: 0,
430445
definition,
431-
de,
446+
de: Some(de),
447+
str_value: None,
432448
})
433449
}
450+
451+
fn new_with_string(s: String, definition: Definition) -> ValueDeserializer<'config> {
452+
ValueDeserializer {
453+
hits: 0,
454+
definition,
455+
de: None,
456+
str_value: Some(s),
457+
}
458+
}
434459
}
435460

436461
impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
@@ -459,9 +484,14 @@ impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
459484
// If this is the first time around we deserialize the `value` field
460485
// which is the actual deserializer
461486
if self.hits == 1 {
462-
return seed
463-
.deserialize(self.de.clone())
464-
.map_err(|e| e.with_key_context(&self.de.key, self.definition.clone()));
487+
if let Some(de) = &self.de {
488+
return seed
489+
.deserialize(de.clone())
490+
.map_err(|e| e.with_key_context(&de.key, self.definition.clone()));
491+
} else {
492+
return seed
493+
.deserialize(self.str_value.as_ref().unwrap().clone().into_deserializer());
494+
}
465495
}
466496

467497
// ... otherwise we're deserializing the `definition` field, so we need
@@ -484,6 +514,71 @@ impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
484514
}
485515
}
486516

517+
// Deserializer is only implemented to handle deserializing a String inside a
518+
// sequence (like `Vec<String>` or `Vec<Value<String>>`). `Value<String>` is
519+
// handled by deserialize_struct, and the plain `String` is handled by all the
520+
// other functions here.
521+
impl<'de, 'config> de::Deserializer<'de> for ValueDeserializer<'config> {
522+
type Error = ConfigError;
523+
524+
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
525+
where
526+
V: de::Visitor<'de>,
527+
{
528+
visitor.visit_str(&self.str_value.expect("string expected"))
529+
}
530+
531+
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
532+
where
533+
V: de::Visitor<'de>,
534+
{
535+
visitor.visit_string(self.str_value.expect("string expected"))
536+
}
537+
538+
fn deserialize_struct<V>(
539+
self,
540+
name: &'static str,
541+
fields: &'static [&'static str],
542+
visitor: V,
543+
) -> Result<V::Value, Self::Error>
544+
where
545+
V: de::Visitor<'de>,
546+
{
547+
// Match on the magical struct name/field names that are passed in to
548+
// detect when we're deserializing `Value<T>`.
549+
//
550+
// See more comments in `value.rs` for the protocol used here.
551+
if name == value::NAME && fields == value::FIELDS {
552+
return visitor.visit_map(self);
553+
}
554+
unimplemented!("only strings and Value can be deserialized from a sequence");
555+
}
556+
557+
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
558+
where
559+
V: de::Visitor<'de>,
560+
{
561+
visitor.visit_string(self.str_value.expect("string expected"))
562+
}
563+
564+
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
565+
where
566+
V: de::Visitor<'de>,
567+
{
568+
visitor.visit_unit()
569+
}
570+
571+
serde::forward_to_deserialize_any! {
572+
i8 i16 i32 i64
573+
u8 u16 u32 u64
574+
option
575+
newtype_struct seq tuple tuple_struct map enum bool
576+
f32 f64 char bytes
577+
byte_buf unit unit_struct
578+
identifier
579+
}
580+
}
581+
487582
/// A deserializer which takes two values and deserializes into a tuple of those
488583
/// two values. This is similar to types like `StrDeserializer` in upstream
489584
/// serde itself.

0 commit comments

Comments
 (0)