I found this previous discussion and it raises a question: I want a deserializer to support both (speaking toml here) count = 42 and count = "100K", and parse a toml into:
I asked some related questions recently on here, and got the help I needed.
However, I wanted to change Config to contain count: Option<u64> instead. This didn't work, and adding default did not help. I assumed I needed to add a custom deserializer for Option<u64>, and indeed that does work. However, in the playground for the post referenced at the top of this post, there's no "duplicate" deserializer (one for none-Option and one for Option).
What is the magic sauce that makes Option Just Work(tm) in this code? The post explicitly says its a newtype. So is there an orphan rule coming in to play that's causing the limitation?
The playground you linked doesn’t use serde(with_deserializer = …) but a newtype pattern with its own Serialize. You could do the same, wrapping the u64 in a newtype, and that newtype can then work bare, or wrapped in Option. The “magic sauce” is that Deserialize<'_> for Option is generic
impl<'de, T> Deserialize<'de> for Option<T>
where
T: Deserialize<'de>,
and calls back to the Deserialize<'_> for T inside, so Option<Newtype> will call the Newtype’s special impl as well.
If you prefer not to change the contained type, there’s another option: look into the “serde_with” crate is designed specifically to offer trait infrastructure for composable custom de-/serializers (for potentially external / pre-existing types). Like for Option, the same principle applies, they just provide a generic trait implementation to allow you to lift your custom deserializer around the option.