99//! from configuration, but also record where it was deserialized from when it
1010//! was read.
1111//!
12- //! ## How `Value<T>` deserialization works
13- //!
1412//! Deserializing `Value<T>` is pretty special, and serde doesn't have built-in
1513//! support for this operation. To implement this we extend serde's "data model"
1614//! a bit. We configure deserialization of `Value<T>` to basically only work with
1715//! our one deserializer using configuration.
1816//!
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.
17+ //! ## How `Value<T>` deserialization works
18+ //!
19+ //! `Value<T>` uses a custom protocol to inject source location information
20+ //! into serde's deserialization process:
21+ //!
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.
25+ //!
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)
2535//!
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.
36+ //! This allows `Value<T>` to capture both the deserialized data and where it
37+ //! came from.
2938//!
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`].
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
5664pub 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.
5868pub ( crate ) const VALUE_FIELD : & str = "$__cargo_private_value" ;
5969pub ( crate ) const DEFINITION_FIELD : & str = "$__cargo_private_definition" ;
6070pub ( crate ) const NAME : & str = "$__cargo_private_Value" ;
0 commit comments