I'm serialising/deserialising paths specified in a config file. These paths are typed std::ffi::OsString. I noticed that when dumping out to a JSON file it looks like this:
{
"root": {
"Unix": [
47,
104,
111
]
}
}
Rather than human readable/writable like this:
{ "root": "/tmp" }
I understand why the numbers are used (JSON is usually expected to be UTF-8 encoded nowadays, so you either need numbers like that or base64 or something similar).
Without losing the benefit of UTF-16 support, considering most paths do not have that requirements, how do I configure serde to decay std::ffi::OsString into String when no UTF-16 is found?
I don't believe you can "configure" it to do that. Support for serializing OsString is baked into serde itself, and you can't change that (I mean, not without submitting changes to serde).
What you can do is take the structure that wraps this OsString and use the with field attribute to override the serialization/deserialization code for that specific field. You'll then need to implement appropriate serialize/deserialize functions that checks if a path is valid as a string and serialize it as such, else fall back to the existing format.
That said, a word of warning: those numbers are not because of UTF-16. Those numbers are because paths are not guaranteed to be any kind of valid string at all in the first place. Valid UTF-16 can absolutely be encoded as UTF-8, so even if they were UTF-16 that wouldn't be an issue. What's more, I don't believe raw paths are guaranteed to be portable between systems; that's likely why "Unix" is in the serialized form: to prevent it from being deserialized on a different OS.
My intuition is that you should either accept that paths are platform-dependent blobs of bytes, or just serialize them as strings and reject paths that involve invalid UTF sequences. Either way, the method is the same: using an appropriate serde attribute on the root field.