Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add std::any::Provider support to Serializer #2420

Closed

Commits on Apr 4, 2023

  1. Add std::any::Provider support

    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
    bryanburgers committed Apr 4, 2023
    Configuration menu
    Copy the full SHA
    5d308fa View commit details
    Browse the repository at this point in the history