Skip to content

Commit e0667f5

Browse files
committed
Add comments of Value<T>'s deserialization protocol
1 parent 2387e1a commit e0667f5

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/cargo/util/config/de.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
112112
where
113113
V: de::Visitor<'de>,
114114
{
115+
// Match on the magical struct name/field names that are passed in to
116+
// detect when we're deserializing `Value<T>`.
117+
//
118+
// See more comments in `value.rs` for the protocol used here.
115119
if name == value::NAME && fields == value::FIELDS {
116120
return visitor.visit_map(ValueDeserializer { hits: 0, de: self });
117121
}
@@ -340,6 +344,13 @@ impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
340344
}
341345
}
342346

347+
/// This is a deserializer that deserializes into a `Value<T>` for
348+
/// configuration.
349+
///
350+
/// This is a special deserializer because it deserializes one of its struct
351+
/// fields into the location that this configuration value was defined in.
352+
///
353+
/// See more comments in `value.rs` for the protocol used here.
343354
struct ValueDeserializer<'config> {
344355
hits: u32,
345356
de: Deserializer<'config>,
@@ -396,6 +407,9 @@ impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
396407
}
397408
}
398409

410+
/// A deserializer which takes two values and deserializes into a tuple of those
411+
/// two values. This is similar to types like `StrDeserializer` in upstream
412+
/// serde itself.
399413
struct Tuple2Deserializer<T, U>(T, U);
400414

401415
impl<'de, T, U> de::Deserializer<'de> for Tuple2Deserializer<T, U>

src/cargo/util/config/value.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,51 @@
1+
//! Deserialization of a `Value<T>` type which tracks where it was deserialized
2+
//! from.
3+
//!
4+
//! Often Cargo wants to report semantic error information or other sorts of
5+
//! error information about configuration keys but it also may wish to indicate
6+
//! as an error context where the key was defined as well (to help user
7+
//! debugging). The `Value<T>` type here can be used to deserialize a `T` value
8+
//! from configuration, but also record where it was deserialized from when it
9+
//! was read.
10+
111
use crate::util::config::Config;
212
use serde::de;
313
use std::fmt;
414
use std::marker;
515
use std::mem;
616
use std::path::{Path, PathBuf};
717

18+
/// A type which can be deserialized as a configuration value which records
19+
/// where it was deserialized from.
820
#[derive(Debug, PartialEq, Clone)]
921
pub struct Value<T> {
22+
/// The inner value that was deserialized.
1023
pub val: T,
24+
/// The location where `val` was defined in configuration (e.g. file it was
25+
/// defined in, env var etc).
1126
pub definition: Definition,
1227
}
1328

1429
pub type OptValue<T> = Option<Value<T>>;
1530

31+
// Deserializing `Value<T>` is pretty special, and serde doesn't have built-in
32+
// support for this operation. To implement this we extend serde's "data model"
33+
// a bit. We configure deserialization of `Value<T>` to basically only work with
34+
// our one deserializer using configuration.
35+
//
36+
// We define that `Value<T>` deserialization asks the deserializer for a very
37+
// special struct name and struct field names. In doing so the deserializer will
38+
// recognize this and synthesize a magical value for the `definition` field when
39+
// we deserialize it. This protocol is how we're able to have a channel of
40+
// information flowing from the configuration deserializer into the
41+
// deserialization implementation here.
42+
//
43+
// You'll want to also check out the implementation of `ValueDeserializer` in
44+
// `de.rs`. Also note that the names below are intended to be invalid Rust
45+
// identifiers to avoid how they might conflict with other valid structures.
46+
// Finally the `definition` field is transmitted as a tuple of i32/string, which
47+
// is effectively a tagged union of `Definition` itself.
48+
1649
pub(crate) const VALUE_FIELD: &str = "$__cargo_private_value";
1750
pub(crate) const DEFINITION_FIELD: &str = "$__cargo_private_definition";
1851
pub(crate) const NAME: &str = "$__cargo_private_Value";

0 commit comments

Comments
 (0)