Skip to content

Implement a #[jomini(collect_with)] attribute for JominiDeserialize.#235

Open
jcranmer wants to merge 2 commits intorakaly:masterfrom
jcranmer:collect_with
Open

Implement a #[jomini(collect_with)] attribute for JominiDeserialize.#235
jcranmer wants to merge 2 commits intorakaly:masterfrom
jcranmer:collect_with

Conversation

@jcranmer
Copy link

This fixes issue #232, although I can't exactly guarantee that performance will be as good as it was before.

I've done some local testing with melted saves via a modified eu4save, using this for collecting trade node data. I haven't done any testing with binary saves, so I can't confirm whether or not it works there.

Copy link
Contributor

@nickbabcock nickbabcock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heck yeah, super excited!

///
/// - `#[jomini(token=value)]`
///
/// I don't know what this does. It needs documentation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// I don't know what this does. It needs documentation.
/// Annotating all fields with this enables the binary deserializer to map u16 tokens directly to struct fields,
/// bypassing the intermediate string lookup and comparisons.

/// This attribute will discard any prior value of the field when it is
/// encountered. It is mutually exclusive with `#[jomini(duplicated)]`.
///
/// - `#[jomini(token=value)]`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it should be possible to use both token= and collect_with= (like in the case with EU4 trade node where the collected fields are strings -- and should not be interpreted as u16), so it'd be nice to have a test confirming this.

eu4 trade node reference where token= and collect_with= could be useful.

     90969:   id:0x15e={
     90975:     id:0x2835='african_great_lakes'
     90981:     id:0x2da5=f32:0x2092
     91008:     id:0x2aa8=f32:0x2092
     [...]
     91118:     'PIR'={
     91133:       id:0x2846=f32:0x3e8
     91139:     }

Can be left as a todo 🤔

where __D: ::serde::Deserializer<'de> {
#[allow(non_camel_case_types)]
enum __Field {
enum __Field<'de> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #232 I mentioned how I was wary of potential performance impacts and thought it should be mitigated by emitting an "unknown"-aware Field and one that isn't based on the presence of collect_with.

I run some tests with eu4save, and there doesn't appear to be any performance impact, so I say we don't worry about it 😄

#match_arm => Ok(#field_ident)
}
});
let field_enum_match2 = field_enum_match.clone();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collecting into a vec and then using the same reference seems preferable.

"MEE": 5
}"#;

let m: Model = serde_json::from_str(data).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test will fail when using serde_json::from_reader(data.as_bytes()), due to the fields being ephemeral strings

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ephemeral strings can be fixed with use of Cow<'a, str> instead of &'a str I think, but I would expect performance implications from that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah Cow sounds good, so perhaps we should only emit the Cow-based __Field when collect_with is present.

@jcranmer
Copy link
Author

Sorry for the delay in responding to the review comments, I instead got busy, uh, playing the game instead. 😅

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants