Make #[derive(SchemaRead)] less brittle with generic lifetimes
#4
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
The
SchemaReadtrait is generic over the lifetime'de, to which theReaderparameter is also bound in the trait'sreadfunction.This ensures that, when performing zero-copy deserialization (i.e., returning a reference into the
Reader's byte buffer), theReader's buffer must live at least as long as the destination's (dst) lifetime.This can present a challenge in the implementation of the
SchemaReadderive macro.For example:
The macro must introduce
'deand ensure it outlives'a.wincode/wincode-derive/src/schema_read.rs
Lines 325 to 329 in e2b20cc
Now where this can get tricky is when
readimpls are generated.'deextends'a, but'amay not necessarily extend'de(i.e.,'amay not live as long as'de).The way that the macro currently gets around this is by rebinding a type's field lifetime to
'deduring code generation, which ensures that the bytes read in thereadportion are done so as'de(and as such satisfies the requirement that the read bytes live for'de).wincode/wincode-derive/src/schema_read.rs
Lines 15 to 36 in e2b20cc
This is brittle because it only works for reference types (e.g.,
&'a T). It does not work for types with generic lifetime bounds (e.g.,OtherType<'a>) because they are represented as distinct AST nodes. This is not ideal, because in principle, there's no reason we shouldn't be able to zero-copy deserialize nested types containing references.Summary of changes
This removes the brittle lifetime rebinding done by matching on a single level
Type, and instead replaces that functionality withsyn'sVisitMut, which provides recursive mutable access to the AST nodes that comprise aType.