-
-
Notifications
You must be signed in to change notification settings - Fork 139
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
Implement miniserde-based deserialization #523
Conversation
OK. Flagging is a hard one. I can see a world where people would want to store the stripe structs verbatim so having The motivation here is that I'd like to see if I can do some graph analysis and split these crates up also. If we can do individual clients and split the apis into a few crates that would be lovely since you could then opt-in to serde for a subset of the API which may be even more helpful still. We just need to be careful here so I will call that a stretch goal. The compile time improvements we have seen so far are more more more than enough. 13MB is 'large' but not obscene. It is very common for web servers to hit that just with tokio and a framework so I don't think it is an issue. |
Implementation details all look solid to me. |
BTW I sent you a maintainer invite. Master needs a PR but you can push / merge freely to next |
Thanks, have accepted! |
I like this approach! I think in that case this would benefit from a bunch more testing to minimize the chance these |
That would be wonderful - there's some basic graph analysis implemented to help infer crates, but could certainly be fleshed out. The main annoyance I saw was that there's one huge connected component (which right now gets shoved into |
d8adc6e
to
7f9d426
Compare
Rebased and implemented the alternative mentioned above about speaking |
Added some basic testing using the OpenAPI provided fixtures in the last commit. There are still some tweaks I'd like to make ( |
42cf51c
to
4cc2678
Compare
After using this, thought it might be better to split the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy with this now!
Add fixture testing and serialize object keys Fix object keys in tests Add object field for serialization without adding field Split serde gate into serialize and deserialize
befa0d9
to
f568feb
Compare
Built on #452, only the last commit is new. Very much a first pass, still some questions to answer. Initial results look promising and hopeful that profiling will reveal some other low-hanging fruit to further improve compile time.
For some quite unscientific timings, a clean release build of
examples/endpoints
goes from ~4m to 50s withmin-ser
enabled. More importantly though, the actual time to build just the binary goes from 75s to 7s, so incremental builds for code depending onasync-stripe
should be much faster.Stripped binary size of the
examples/endpoints
binary also went from ~70MB to ~20MB. There's likely room for further binary size improvement since a fat LTO build shrunk this further to ~13 MB.Feature Flags
The most important question to answer is how to expose the option of using
miniserde
. This PR takes the cautious approach of adding amin-ser
feature which skips implementingserde::Deserialize
and instead always implementsminiserde::Deserialize
where necessary for requests. The advantage with this approach is thatmin-ser
could left as an "experimental" feature flag, making an initial release less breaking by requiring explicitly opting intomin-ser
. There are some annoyances with this approach, thoughmin-ser
is not additive - it removes functionality, so using it can be unintuitive (and might lead to similar feature incompatibility pains as the currentruntime*
features.StripeDeserialize
trait, added to abstract over the fact that a request might need eitherserde
orminiserde
to deserialize. Also, some types become feature flag dependent, e.g. a field might beminiserde::Value
orserde_json::Value
, which can't be shown easily in docs. (And we have to add a bunch ofcfg
blocks)The other alternative would be to always use
miniserde
for library functionality (deserializing requests, webhooks, etc.). Then an additional additiveserde-deserialize
flag could be added to ask forserde::Deserialize
to be derived on all types (useful for testing purposes). This would solve the complexity issues above at the cost of makingminiserde
impossible to opt out of.Implementation Details
As seen by the diff, this adds a bunch of generated code :) . This new code is essentially using our codegen mechanism to mimic what the
miniserde
derive is already doing to allow deserialization cases thatminiserde
cannot support:Expandable<T>
:Deserialize
forT
so that we can publicly expose the underlyingBuilder
type so thatExpandable<T>
can use the same underlying implementation asT
."Union of objects" types where the type is determined with the
"object"
field.serde(tag = "x")
works - the data gets deserialized into an untyped JSON representation, which can then be converted to the correct variant using the"object"
key.miniserde
provides a convenientminiserde::Value
for this purpose, but we then need to also generate impls forValue -> T
for eachT
that we need to deserialize."Deleted or not" types where the type is determined by whether there is a
deleted: true
field."object"
case above, just discriminating between variants using the"deleted"
boolean instead.