-
Notifications
You must be signed in to change notification settings - Fork 123
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 more documentation #298
Comments
Thank you for describing your process!
Yeah, really no appetite to complicate it in the same way. It's good to keep this purely data, not code :) |
This is not true https://serde.rs/field-attrs.html#skip since this will stop serializing of the value but I actually want to serialize it if it is Some(x), so using the serializing_if is the right one in my use case ;). |
Issue has had no activity in the last 180 days and is going to be closed in 7 days if no further activity occurs |
comment |
Hi,
Since I tinkered a lot with how to do my specific stuff, I have to write this issue, I will try to describe what I wished to achieve and what I managed to do, this would be a great starting point for people that like nice dual way serialization/deserialization. At the end I will also mentions current improvement to the pretty config (please READ them), I would love a page dedicated to those specific in the wiki or discussion page (you can take this whole article if you want, I give you all the right on it).
My use case is pretty simple, I have a config file I made manually and I need to load it in a specific structure, then add fields and populate it as it goes then write it back. But since it is half/half manual/automatic work, I need to work with a standard format on both side. However my structure is quite big and doesn't have all its fields everytime, but having such in my config would be tiresome, so I had to jump into serde! Let's take a real use case:
game.ron :
As we can see our structure is semi filled, so if we try to deserialize it we will face some issues (I will use here include_str but as this is a dynamic asset you want to use a bufreader and from_reader.
We get a big error
[/src/util/test.rs:75] &r = Err( Error { code: ExpectedOption, position: Position { line: 4, col: 19, }, }, )
That's actually an easy one, you just need to add those two enable extensions (see docs/Extensions.md) at the top of your file see #281 for why this is not yet in current release.
#![enable(implicit_some,unwrap_newtypes)]
>> game.ronNow we recompile our example and we face our first challenge, we are missing a field (like I said our config data is only filled with the necessary informations.
Ok that's an easy one, you see serde needs to know what to do with missing fields, so we need to add
#[serde(default)]
to thesubject: SubjectMapping,
field (see https://serde.rs/attr-default.html for more informations) but we notice immediatly something we are missing a Default trait for SubjectMapping.Thus we add it:
Ok now that we have that done we move to the next error
Since how has no default option and is not an Option (thus filled with the extension with None) then we need to tinker with serde again and force it to default with
#[serde(default)]
again.Ok we compile that and we have now:
That's a perfect structure, we got it, we can now use it in rust, however I said earlier we actually want to serialize it back to the original form, right? Yeah if we serialize it back we will have a real surprise since we will have litterally all the None in it.
Let's use this function to deserialize then serialize, you will notice we use prettyConfig extensions and some options, all of which are documented, since I don't link numbering on my array I deactivated it and also I made sure to have IMPLICIT_SOME and UNWRAP_NEWTYPES even tho in this process they are not that useful (the structure already has all the option in it and the type are wrapped in their correct structure.
And yeah as expected we don't get the same input at all, it's pretty messy ;).
Ok we need to remove the None element so for instance superseded doesn't need to be in defaults at all. Again we are going to use serde and the skip_serializing_if macro, here with if it is None then we don't show it. ( https://serde.rs/field-attrs.html#skip_serializing_if )
Now if we look at the "default" key serialized we get:
which is already much better, ok let's do that for all the option fields:
You will notice a few things which are now weird, there is still the Some(key) which are annoying (we will fix those) but also we have how:[] which is empty so we could remove it and we have subject:(), action:Some(()) and actions:{}, let's clean that up.
The first one is to remove the Some, this one is tricky since you need to get the value inside, but serde allow to create our own serializer function and since all the None are remove our function can simply be key.unwrap.
We just need to apply it after the skip_serializing (very important since we unwrap without checking).
We replace
#[serde(skip_serializing_if = "Option::is_none")]
with#[serde(skip_serializing_if = "Option::is_none",serialize_with="option_remove_serialize")]
And we get
Ok this is really nice but the some fields are useless, so let's remove them, we use
skip_serializing_if = "Vec::is_empty"
for the how:[] and for the actions: {} we can remove if with #[serde(skip_serializing_if = "HashMap::is_empty")].For the subject:() in default we can define
and call on SubjectMapping with serializing_if
Our final deserialize then re-serialize file looks like that:
Which is almost the same as the original one:
The only difference are now in the fact that the array is not packed the same way, the order is not respected (that's because we use a Hashmap and not a LinkedHashmap use use
linked_hash_map::LinkedHashMap
; from linked-hash-map = {version="0.5.3", features=["serde_impl"]} ) and the top line is not present (this can be added before outputting to the file.We can now use transcoding efficiently to manually edit the file as well as automatically and all of that with the same "formatting" and direct usage of rust structure, welcome to the future !
Here the full end source code:
https://gist.github.com/hube12/c87ccd91c519560b4b1cdcefa2e534af
Please read the following lines for my comment on what to add next to ron-rs:
As I said at the beginning, I would love to see some pretty config options such as with_array_breakdown(false) which would allow same line array, or with_extra_coma(true) to add an extra comma at the end of an enum/struct/tuple. I think that since it was mentionned in earlier issue: #189 , this is not yet possible to recover the name of the structure but It would be a nice feature. Also I know this will be a big no-no but I would love to see super/extends fields like in YAML where << : x can reference &x and so on, same goes for variable like x: 2field.y but since this would cause issues with a constant parser, I don't mind a runtime processing.
The text was updated successfully, but these errors were encountered: