Skip to content

Commit c762238

Browse files
committed
refactor: split two code paths in ValueDeserializer to enum
The MapAccess and Deserializer impls in ValueDeserializer are actually tow distinct code paths. It is better to extract them to two different value sources.
1 parent df4f7fc commit c762238

File tree

1 file changed

+69
-40
lines changed
  • src/cargo/util/context

1 file changed

+69
-40
lines changed

src/cargo/util/context/de.rs

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -441,18 +441,34 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
441441
{
442442
match self.list_iter.next() {
443443
// TODO: add `def` to error?
444-
Some(CV::String(value, def)) => {
444+
Some(val @ CV::String(..)) => {
445445
// This might be a String or a Value<String>.
446-
// ValueDeserializer will handle figuring out which one it is.
447-
let maybe_value_de = ValueDeserializer::new_with_string(value, def);
448-
seed.deserialize(maybe_value_de).map(Some)
446+
// ArrayItemDeserializer will handle figuring out which one it is.
447+
seed.deserialize(ArrayItemDeserializer::new(val)).map(Some)
449448
}
450449
Some(val) => Err(ConfigError::expected(&self.key, "list of string", &val)),
451450
None => Ok(None),
452451
}
453452
}
454453
}
455454

455+
/// Source of data for [`ValueDeserializer`]
456+
enum ValueSource<'gctx> {
457+
/// The deserializer used to actually deserialize a Value struct.
458+
Deserializer {
459+
de: Deserializer<'gctx>,
460+
definition: Definition,
461+
},
462+
/// A [`ConfigValue`](CV).
463+
///
464+
/// This is used for situations where you can't address a string via a TOML key,
465+
/// such as a string inside an array.
466+
/// The [`ConfigSeqAccess`] doesn't know if the type it should deserialize to
467+
/// is a `String` or `Value<String>`,
468+
/// so [`ArrayItemDeserializer`] needs to be able to handle both.
469+
ConfigValue(CV),
470+
}
471+
456472
/// This is a deserializer that deserializes into a `Value<T>` for
457473
/// configuration.
458474
///
@@ -462,18 +478,7 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
462478
/// See more comments in `value.rs` for the protocol used here.
463479
struct ValueDeserializer<'gctx> {
464480
hits: u32,
465-
definition: Definition,
466-
/// The deserializer, used to actually deserialize a Value struct.
467-
/// This is `None` if deserializing a string.
468-
de: Option<Deserializer<'gctx>>,
469-
/// A string value to deserialize.
470-
///
471-
/// This is used for situations where you can't address a string via a
472-
/// TOML key, such as a string inside an array. The `ConfigSeqAccess`
473-
/// doesn't know if the type it should deserialize to is a `String` or
474-
/// `Value<String>`, so `ValueDeserializer` needs to be able to handle
475-
/// both.
476-
str_value: Option<String>,
481+
source: ValueSource<'gctx>,
477482
}
478483

479484
impl<'gctx> ValueDeserializer<'gctx> {
@@ -498,20 +503,24 @@ impl<'gctx> ValueDeserializer<'gctx> {
498503
(_, None) => env_def,
499504
}
500505
};
506+
501507
Ok(ValueDeserializer {
502508
hits: 0,
503-
definition,
504-
de: Some(de),
505-
str_value: None,
509+
source: ValueSource::Deserializer { de, definition },
506510
})
507511
}
508512

509-
fn new_with_string(s: String, definition: Definition) -> ValueDeserializer<'gctx> {
513+
fn with_cv(cv: CV) -> ValueDeserializer<'gctx> {
510514
ValueDeserializer {
511515
hits: 0,
512-
definition,
513-
de: None,
514-
str_value: Some(s),
516+
source: ValueSource::ConfigValue(cv),
517+
}
518+
}
519+
520+
fn definition(&self) -> &Definition {
521+
match &self.source {
522+
ValueSource::Deserializer { definition, .. } => definition,
523+
ValueSource::ConfigValue(cv) => cv.definition(),
515524
}
516525
}
517526
}
@@ -542,19 +551,19 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
542551
// If this is the first time around we deserialize the `value` field
543552
// which is the actual deserializer
544553
if self.hits == 1 {
545-
if let Some(de) = &self.de {
546-
return seed
554+
return match &self.source {
555+
ValueSource::Deserializer { de, definition } => seed
547556
.deserialize(de.clone())
548-
.map_err(|e| e.with_key_context(&de.key, Some(self.definition.clone())));
549-
} else {
550-
return seed
551-
.deserialize(self.str_value.as_ref().unwrap().clone().into_deserializer());
552-
}
557+
.map_err(|e| e.with_key_context(&de.key, Some(definition.clone()))),
558+
ValueSource::ConfigValue(cv) => {
559+
seed.deserialize(ArrayItemDeserializer::new(cv.clone()))
560+
}
561+
};
553562
}
554563

555564
// ... otherwise we're deserializing the `definition` field, so we need
556565
// to figure out where the field we just deserialized was defined at.
557-
match &self.definition {
566+
match self.definition() {
558567
Definition::Path(path) => {
559568
seed.deserialize(Tuple2Deserializer(0i32, path.to_string_lossy()))
560569
}
@@ -572,25 +581,45 @@ impl<'de, 'gctx> de::MapAccess<'de> for ValueDeserializer<'gctx> {
572581
}
573582
}
574583

575-
// Deserializer is only implemented to handle deserializing a String inside a
576-
// sequence (like `Vec<String>` or `Vec<Value<String>>`). `Value<String>` is
577-
// handled by deserialize_struct, and the plain `String` is handled by all the
578-
// other functions here.
579-
impl<'de, 'gctx> de::Deserializer<'de> for ValueDeserializer<'gctx> {
584+
/// A deserializer for individual [`ConfigValue`](CV) items in arrays
585+
///
586+
/// This deserializer is only implemented to handle deserializing a String
587+
/// inside a sequence (like `Vec<String>` or `Vec<Value<String>>`).
588+
/// `Value<String>` is handled by `deserialize_struct` in [`ValueDeserializer`],
589+
/// and the plain `String` is handled by all the other functions here.
590+
#[derive(Clone)]
591+
struct ArrayItemDeserializer {
592+
cv: CV,
593+
}
594+
595+
impl ArrayItemDeserializer {
596+
fn new(cv: CV) -> Self {
597+
Self { cv }
598+
}
599+
600+
fn into_inner(self) -> String {
601+
match self.cv {
602+
CV::String(s, _def) => s,
603+
_ => unreachable!("string expected"),
604+
}
605+
}
606+
}
607+
608+
impl<'de> de::Deserializer<'de> for ArrayItemDeserializer {
580609
type Error = ConfigError;
581610

582611
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
583612
where
584613
V: de::Visitor<'de>,
585614
{
586-
visitor.visit_str(&self.str_value.expect("string expected"))
615+
visitor.visit_str(&self.into_inner())
587616
}
588617

589618
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
590619
where
591620
V: de::Visitor<'de>,
592621
{
593-
visitor.visit_string(self.str_value.expect("string expected"))
622+
visitor.visit_string(self.into_inner())
594623
}
595624

596625
fn deserialize_struct<V>(
@@ -607,7 +636,7 @@ impl<'de, 'gctx> de::Deserializer<'de> for ValueDeserializer<'gctx> {
607636
//
608637
// See more comments in `value.rs` for the protocol used here.
609638
if name == value::NAME && fields == value::FIELDS {
610-
return visitor.visit_map(self);
639+
return visitor.visit_map(ValueDeserializer::with_cv(self.cv));
611640
}
612641
unimplemented!("only strings and Value can be deserialized from a sequence");
613642
}
@@ -616,7 +645,7 @@ impl<'de, 'gctx> de::Deserializer<'de> for ValueDeserializer<'gctx> {
616645
where
617646
V: de::Visitor<'de>,
618647
{
619-
visitor.visit_string(self.str_value.expect("string expected"))
648+
visitor.visit_string(self.into_inner())
620649
}
621650

622651
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>

0 commit comments

Comments
 (0)