Skip to content

Commit d7408c4

Browse files
committed
docs(gctx): explain Value deserialization step-by-step
1 parent 423f51a commit d7408c4

File tree

1 file changed

+23
-13
lines changed

1 file changed

+23
-13
lines changed

src/cargo/util/context/value.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,29 @@
1616
//!
1717
//! ## How `Value<T>` deserialization works
1818
//!
19-
//! We define that `Value<T>` deserialization asks the deserializer for a very
20-
//! special [struct name](NAME) and [struct field names](FIELDS). In doing so,
21-
//! the deserializer will recognize this and synthesize a magical value for the
22-
//! `definition` field when we deserialize it. This protocol is how we're able
23-
//! to have a channel of information flowing from the configuration deserializer
24-
//! into the deserialization implementation here.
19+
//! `Value<T>` uses a custom protocol to inject source location information
20+
//! into serde's deserialization process:
2521
//!
26-
//! You'll want to also check out the implementation of `ValueDeserializer` in
27-
//! the [`de`] module. Also note that the names below are intended to be invalid
28-
//! Rust identifiers to avoid conflicts with other valid structures.
22+
//! **Magic identifiers**: `Value<T>::deserialize` requests a struct with special
23+
//! [name](NAME) and [field names](FIELDS) that use invalid Rust syntax to avoid
24+
//! conflicts. This signals to Cargo's deserializer that location tracking is needed.
2925
//!
30-
//! Finally the `definition` field is transmitted as a tuple of i32/string,
31-
//! which is effectively a tagged union of [`Definition`] itself. You should
32-
//! update both places here and in the impl of [`serde::de::MapAccess`] for
33-
//! `ValueDeserializer` when adding or modifying enum variants of [`Definition`].
26+
//! **Custom deserializer response**: When Cargo's deserializer sees these magic
27+
//! identifiers, it switches to `ValueDeserializer` (from the [`de`] module)
28+
//! instead of normal struct deserialization.
29+
//!
30+
//! **Two-field protocol**: `ValueDeserializer` presents exactly two fields
31+
//! through map visiting:
32+
//! * The actual value (deserialized normally)
33+
//! * The definition context (encoded as a `(u32, String)` tuple acting as a
34+
//! tagged union of [`Definition`] variants)
35+
//!
36+
//! This allows `Value<T>` to capture both the deserialized data and where it
37+
//! came from.
38+
//!
39+
//! **Note**: When modifying [`Definition`] variants, be sure to update both
40+
//! the `Definition::deserialize` implementation here and the
41+
//! `MapAccess::next_value_seed` implementation in `ValueDeserializer`.
3442
//!
3543
//! [`de`]: crate::util::context::de
3644
@@ -55,6 +63,8 @@ pub struct Value<T> {
5563

5664
pub type OptValue<T> = Option<Value<T>>;
5765

66+
// The names below are intended to be invalid Rust identifiers
67+
// to avoid conflicts with other valid structures.
5868
pub(crate) const VALUE_FIELD: &str = "$__cargo_private_value";
5969
pub(crate) const DEFINITION_FIELD: &str = "$__cargo_private_definition";
6070
pub(crate) const NAME: &str = "$__cargo_private_Value";

0 commit comments

Comments
 (0)