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

Option<Vec> support #8

Open
Ten0 opened this issue Jan 17, 2023 · 3 comments
Open

Option<Vec> support #8

Ten0 opened this issue Jan 17, 2023 · 3 comments

Comments

@Ten0
Copy link

Ten0 commented Jan 17, 2023

It would be nice to have a way to make it work with Option as well, either via serde_with's serde_as framework, or via a dedicated function

@daboross
Copy link
Owner

I'd agree with this, but I'm also not sure the best way to handle it.

One way is just an option module, so you could do #[serde(with = "tuple_vec_map::option")] - relatively elegant, would just work, but isn't very extensible.

I'm curious about serde_as, but I haven't figured out exactly how it works. Do you know if there's something we would need to do in particular in this crate to be usable with it, or is it only usable with things created within serde_with?

@Ten0
Copy link
Author

Ten0 commented Feb 10, 2023

It would have to be added as a dependency but then that would work out of the box I think. I guess that could also be PR-ed there.

Alternately there could be a design inspired by serde_bytes, where their function applies for several different types via an internal Deserialize trait.

Alternately again, one could write a function that takes any Serialize/returns any Deserialize<'de>, and write a struct that wraps the original (de)serializer, and implements (De)Serialize, converting the top-level map into a seq (resp. seq into a map). This could then use the deserialize_option hint to properly propagate some/none. This would be arguably less type-safe, as we would only require a deserialize impl, but that would also be more flexible as that would allow for any output type that supports sequences of tuples, not only Vecs. That would not seem to really be less typesafe than serde otherwise is anyway though, as you need your struct to match the data anyway, and there are already a bunch of always-erroring combinations that serde lets through at compile time depending on the format so you should generally test deserialization anyway.
If you want to go for this, this may help making it less boilerplate-ish: https://crates.io/crates/serde_serializer_quick_unsupported

@daboross
Copy link
Owner

Alternately there could be a design inspired by serde_bytes, where their function applies for several different types via an internal Deserialize trait.

Oh, interesting. I quite like this!

Alternately again, one could write a function that takes any Serialize/returns any Deserialize<'de>, and write a struct that wraps the original (de)serializer, and implements (De)Serialize, converting the top-level map into a seq (resp. seq into a map). This could then use the deserialize_option hint to properly propagate some/none. This would be arguably less type-safe, as we would only require a deserialize impl, but that would also be more flexible as that would allow for any output type that supports sequences of tuples, not only Vecs. That would not seem to really be less typesafe than serde otherwise is anyway though, as you need your struct to match the data anyway, and there are already a bunch of always-erroring combinations that serde lets through at compile time depending on the format so you should generally test deserialization anyway.
If you want to go for this, this may help making it less boilerplate-ish: https://crates.io/crates/serde_serializer_quick_unsupported

Interesting - this could definitely be more general. I'd probably prioritize type-safety, though. As you note, serde in general isn't the most type safe system, but generally if you take the recommended paths, and only ever convert data to/from the same structs, it's just about as type safe as a serialization system can get.

Granted, this wouldn't necessarily have to change that - I mean it could be something like "the outermost sequence of tuples found is converted into a map", and if there is none, silently fail doing nothing. Still, I think a type error would be better.

And maybe we could allow for something like arbitrary sequence types by doing a blanket implementation of tuple_vec_map::Deserialize for T where T: IntoIterator<Item=(K, V)>? I'm not 100% sure if the type system will allow that, but might as well check. I know I originally tried to go more generic, then went back to Vec when some of the current functions weren't possible to write, but I can't remember the exact constraints.


Back to serde_with, I've looked through their documentation more, and haven't really found how I would add in a new transformation as a crate depending on serde_with. Regardless, though, I'm against adding dependencies to such a simple crate as this unless necessary, so I'll look into the alternatives you suggest more!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants