Turn a `Serializer` and a `Deserializer` into a [`std::any::Provider`]
in a backward compatible way.
This allows specialization between a `Serializer` and a `Serialize`, and
between a `Deserializer` and a `Deserialize`.
The one particular use case I have in mind is for [`serde_dynamo`].
DynamoDB supports lists of generic items – which is what `serde_dynamo`
currently uses to serialize e.g. a `Vec<String>`. However, DynamoDB also
supports specialized types like [String Set] that it would be nice to be
able to opt in to.
Using [`std::any::Provider`], this could look something like this:
/// A specialized serializer
///
/// This would most likely be used with `#[serde(with = "string_set")]`
struct StringSet<T>(T);
impl<T> Serialize for StringSet<T> where T: Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if let Some(string_set_serializer) = std::any::request_value::<serde_dynamo::StringSetSerializer>(&serializer.provider()) {
self.0.serialize(string_set_serializer)
} else {
self.0.serialize(serializer)
}
}
}
/// In user code, a struct that wants `strings` to be serialized
/// using a DynamoDb string set *if* the serializer is
/// `serde_dynamo`
#[derive(Debug, Serialize, Deserialize)]
struct Subject {
strings: StringSet<Vec<String>>,
}
With this set up, `Subject.strings` would be serialized as normal using
`serde_json`
{
"strings": ["one", "two"]
}
but when using `serde_dynamo`, `Subject.strings` would use the specific
`StringSetSerializer` to get custom behavior.
This is a very specific example where `serde_dynamo` would likely
provide both the `StringSet` wrapper and the `StringSetSerializer`.
There *may* also be situations where the ecosystem would develop common
practices. One example is the `Serializer::is_human_readable` function.
If this existed before that was introduced, it's *possible* the
serializers could have provided `struct IsHumanReadable(bool)` and
serializers could have used that to determine how to display timestamps.
Links regarding [`std::any::Provider`]:
* `std::any::Provider` RFC: https://rust-lang.github.io/rfcs/3192-dyno.html
* `std::any::Provider` tracking issue: rust-lang/rust#96024
[`std::any::Provider`]: https://doc.rust-lang.org/nightly/core/any/trait.Provider.html
[`serde_dynamo`]: https://docs.rs/serde_dynamo
[String Set]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html