-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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 a pre-parsed FieldPath for faster repeated uses of GetPath calls #4081
Conversation
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.
Looks good overall. I think it would nice to add some tests for FieldPath
, though, to make sure it works properly (especially after multiple uses) in the future.
Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
Ok(current) | ||
} | ||
|
||
pub fn get_field<'r, 'p, T: Reflect>( |
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.
This needs docs.
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.
Externally, it's very hard to tell the difference between the field
method and the get_field
. I would have expected this to be the fallible version based on the name, but they both return results and have the same type signature.
@DJMcNab comments that get_field appears to do automatic downcasting.
The naming scheme needs to be fixed.
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.
This mirrors the same API for GetPath
, if we update it here, we should update it in both places. The main difference is that one has a concrete type and the other returns a dyn Reflect
reference.
}) | ||
} | ||
|
||
pub fn get_field_mut<'r, 'p, T: Reflect>( |
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.
Docs.
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.
I like the direction here, but have some docs and code quality nits that should be addressed.
Ok(current) | ||
} | ||
|
||
pub fn get_field<'r, 'p, T: Reflect>( |
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.
Externally, it's very hard to tell the difference between the field
method and the get_field
. I would have expected this to be the fallible version based on the name, but they both return results and have the same type signature.
@DJMcNab comments that get_field appears to do automatic downcasting.
The naming scheme needs to be fixed.
}); | ||
impl fmt::Display for FieldPath { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
for (idx, (access, _)) in self.0.iter().enumerate() { |
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.
This should be pulled out into a utility function and tested IMO.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
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.
I would still like more docs, but I won't block on them.
@james7132 @MrGVSV now that #6560 is merged, we should clean this up and merge it as James pointed out there. |
bors try |
tryMerge conflict. |
@james7132 if you're too busy to do so, I can adopt this PR, fix the merge conflicts, and address any remaining issues/reviews. Just let me know! :) |
If you could ,that'd be great. My focus has been elsewhere. |
Closing this as it's now been adopted by #7321. |
# Objective > ℹ️ **This is an adoption of #4081 by @james7132** Fixes #4080. Provide a way to pre-parse reflection paths so as to avoid having to parse at each call to `GetPath::path` (or similar method). ## Solution Adds the `ParsedPath` struct (named `FieldPath` in the original PR) that parses and caches the sequence of accesses to a reflected element. This is functionally similar to the `GetPath` trait, but removes the need to parse an unchanged path more than once. ### Additional Changes Included in this PR from the original is cleaner code as well as the introduction of a new pathing operation: field access by index. This allows struct and struct variant fields to be accessed in a more performant (albeit more fragile) way if needed. This operation is faster due to not having to perform string matching. As an example, if we wanted the third field on a struct, we'd write `#2`—where `#` denotes indexed access and `2` denotes the desired field index. This PR also contains improved documentation for `GetPath` and friends, including renaming some of the methods to be more clear to the end-user with a reduced risk of getting them mixed up. ### Future Work There are a few things that could be done as a separate PR (order doesn't matter— they could be followup PRs or done in parallel). These are: - [x] ~~Add support for `Tuple`. Currently, we hint that they work but they do not.~~ See #7324 - [ ] Cleanup `ReflectPathError`. I think it would be nicer to give `ReflectPathError` two variants: `ReflectPathError::ParseError` and `ReflectPathError::AccessError`, with all current variants placed within one of those two. It's not obvious when one might expect to receive one type of error over the other, so we can help by explicitly categorizing them. --- ## Changelog - Cleaned up `GetPath` logic - Added `ParsedPath` for cached reflection paths - Added new reflection path syntax: struct field access by index (example syntax: `foo#1`) - Renamed methods on `GetPath`: - `path` -> `reflect_path` - `path_mut` -> `reflect_path_mut` - `get_path` -> `path` - `get_path_mut` -> `path_mut` ## Migration Guide `GetPath` methods have been renamed according to the following: - `path` -> `reflect_path` - `path_mut` -> `reflect_path_mut` - `get_path` -> `path` - `get_path_mut` -> `path_mut` Co-authored-by: Gino Valente <gino.valente.code@gmail.com>
# Objective > ℹ️ **This is an adoption of bevyengine#4081 by @james7132** Fixes bevyengine#4080. Provide a way to pre-parse reflection paths so as to avoid having to parse at each call to `GetPath::path` (or similar method). ## Solution Adds the `ParsedPath` struct (named `FieldPath` in the original PR) that parses and caches the sequence of accesses to a reflected element. This is functionally similar to the `GetPath` trait, but removes the need to parse an unchanged path more than once. ### Additional Changes Included in this PR from the original is cleaner code as well as the introduction of a new pathing operation: field access by index. This allows struct and struct variant fields to be accessed in a more performant (albeit more fragile) way if needed. This operation is faster due to not having to perform string matching. As an example, if we wanted the third field on a struct, we'd write `bevyengine#2`—where `#` denotes indexed access and `2` denotes the desired field index. This PR also contains improved documentation for `GetPath` and friends, including renaming some of the methods to be more clear to the end-user with a reduced risk of getting them mixed up. ### Future Work There are a few things that could be done as a separate PR (order doesn't matter— they could be followup PRs or done in parallel). These are: - [x] ~~Add support for `Tuple`. Currently, we hint that they work but they do not.~~ See bevyengine#7324 - [ ] Cleanup `ReflectPathError`. I think it would be nicer to give `ReflectPathError` two variants: `ReflectPathError::ParseError` and `ReflectPathError::AccessError`, with all current variants placed within one of those two. It's not obvious when one might expect to receive one type of error over the other, so we can help by explicitly categorizing them. --- ## Changelog - Cleaned up `GetPath` logic - Added `ParsedPath` for cached reflection paths - Added new reflection path syntax: struct field access by index (example syntax: `foo#1`) - Renamed methods on `GetPath`: - `path` -> `reflect_path` - `path_mut` -> `reflect_path_mut` - `get_path` -> `path` - `get_path_mut` -> `path_mut` ## Migration Guide `GetPath` methods have been renamed according to the following: - `path` -> `reflect_path` - `path_mut` -> `reflect_path_mut` - `get_path` -> `path` - `get_path_mut` -> `path_mut` Co-authored-by: Gino Valente <gino.valente.code@gmail.com>
Objective
Fixes #4080. Implement a pre-parsed version of
GetPath
functions.Solution
Implement
FieldPath
a struct that parses a field path ahead of time and caches the sequence of field accesses to avoid string parsing when fetching a field. Added a few additional changes:FieldPath
lookups, but it can be much more fragile when serialized to assets. Can be used to transform string lookups into index lookups static type information.Future Directions
If we get non-reference bound type information, we can further optimize this by looking up field indexes during parsing using a TypeRegistry.