-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Feat/5764 map paths in bevy reflect #5812
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
Feat/5764 map paths in bevy reflect #5812
Conversation
These methods use the same code (duplicated) and we should make sure they behave the same (modulo _mut). This also found a minor "bug" where an error was reported different between the implementations. We may want to derive the two tests with some kind of macro to make sure they stay the same?
This adds some parser code to be able to parse access to maps via the reflection get_path and get_path_mut API. The current implementation only supports maps with String keys, dues to lack of type casting from the read ident to the map key. Needs some more logic there.
crates/bevy_reflect/src/path.rs
Outdated
if let Some(Token::SingleQuote) = next_token(path, &mut index) { | ||
} else { | ||
return Err(ReflectPathError::ExpectedToken { | ||
index: current_index, | ||
token: "'", | ||
}); | ||
} |
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.
an if/else
branch with one of the branches being empty is a little odd. This could be condensed to
if !matches!(Some(Token::SingleQuote), next_token(path, &mut index)) {
return Err(..);
}
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.
You are correct, that read better indeed. I just used the empty if-branch because it was already used further down in the function to check for the CloseBracked token. I changed all cases to if !matched!
now to keep them consistent
crates/bevy_reflect/src/path.rs
Outdated
if let Some(Token::SingleQuote) = next_token(path, &mut index) { | ||
} else { | ||
return Err(ReflectPathError::ExpectedToken { | ||
index: current_index, | ||
token: "'", | ||
}); | ||
} |
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.
ditto here with the if !matches!(..)
syntax.
@@ -136,12 +141,48 @@ impl GetPath for dyn Reflect { | |||
index: current_index, | |||
}) | |||
} | |||
}, | |||
Some(Token::SingleQuote) => { |
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.
Also notably, the two match branches in path()
and path_mut()
are exactly the same (minus the get
/get_mut
call on the map. It's probably worth DRY'ing this out into a similar function to reduce code duplication.
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 moved the code to find the complete quoted identifier to its own function, which only leaves the match reflect_ref
vs match reflect_mut
part in those branches. Not sure if it possible/feasible to further reduce duplication here without creating some kind ob abstraction over mutability?
Some parts could easily be factored our to reduce code duplication. Also improved readability by cleaning up empty if-branches, as suggested by QA.
We want to report the correct error locations so users understand these errors correctly.
Thanks clippy!
# Objective Currently, arrays cannot indexed using the reflection path API. This change makes them behave like lists so `x.get_path("list[0]")` will behave the same way, whether x.list is a "List" (e.g. a Vec) or an array. ## Solution When syntax is encounterd `[ <idx> ]` we check if the referenced type is either a `ReflectRef::List` or `ReflectRef::Array` (or `ReflectMut` for the mutable case). Since both provide the identical API for accessing entries, we do the same for both, although it requires code duplication as far as I can tell. This was born from working on #5764, but since this seems to be an easier fix (and I am not sure if I can actually solve #5812) I figured it might be worth to split this out.
Closing this as I cannot finish it right now. |
# Objective Currently, arrays cannot indexed using the reflection path API. This change makes them behave like lists so `x.get_path("list[0]")` will behave the same way, whether x.list is a "List" (e.g. a Vec) or an array. ## Solution When syntax is encounterd `[ <idx> ]` we check if the referenced type is either a `ReflectRef::List` or `ReflectRef::Array` (or `ReflectMut` for the mutable case). Since both provide the identical API for accessing entries, we do the same for both, although it requires code duplication as far as I can tell. This was born from working on bevyengine#5764, but since this seems to be an easier fix (and I am not sure if I can actually solve bevyengine#5812) I figured it might be worth to split this out.
# Objective Currently, arrays cannot indexed using the reflection path API. This change makes them behave like lists so `x.get_path("list[0]")` will behave the same way, whether x.list is a "List" (e.g. a Vec) or an array. ## Solution When syntax is encounterd `[ <idx> ]` we check if the referenced type is either a `ReflectRef::List` or `ReflectRef::Array` (or `ReflectMut` for the mutable case). Since both provide the identical API for accessing entries, we do the same for both, although it requires code duplication as far as I can tell. This was born from working on bevyengine#5764, but since this seems to be an easier fix (and I am not sure if I can actually solve bevyengine#5812) I figured it might be worth to split this out.
# Objective Currently, arrays cannot indexed using the reflection path API. This change makes them behave like lists so `x.get_path("list[0]")` will behave the same way, whether x.list is a "List" (e.g. a Vec) or an array. ## Solution When syntax is encounterd `[ <idx> ]` we check if the referenced type is either a `ReflectRef::List` or `ReflectRef::Array` (or `ReflectMut` for the mutable case). Since both provide the identical API for accessing entries, we do the same for both, although it requires code duplication as far as I can tell. This was born from working on bevyengine#5764, but since this seems to be an easier fix (and I am not sure if I can actually solve bevyengine#5812) I figured it might be worth to split this out.
Objective
I aimed to solve #5764 here, implementing a way to access map entries using bevy_reflects
get_path
andget_path_mut
.Solution
The implementation is incomplete, only allowing to access entries in maps with
String
s as key. I wasnt able to come up with a proper solution yet on how to get from having a&str ident
to aK map_key
for aMap<K, V>
.The current implementation uses the
m['key']
syntax for specifiing the map key, but it should be easy to adapt it to a different syntax, if required.I added a new
SingleQuote
Token
variant, which is returned bynext_token
when it encounters a'
.Then extended the
get_path
andget_path_mut
methods to support aSingleQuote
token after aOpenBracket
token instead of anIdent
. If thats encountered, we expect the next token to be anIdent
(the key) and then a closingSingleQuote
, and we expect thecurrent
reflect node to be aMap
.Resolving the
map_key
from the readident
seems to only challenging part here and thus its the only part I was not able to solve (or I might have missed other stuff?). I opted for going for "String keys only for the first draft", but of course I do not expect this to be merged like this.Everything after that is basically a mirror of the behaviour for lists.
Additionally I split/copied the test for get_path into a second one for get_path_mut which basically tests the exact same stuff but using the
_mut
variant to make sure both behave the same, since their code is roughly identical and seems prone to minor differences which may cause subtle bugs/inconsistencies.Changelog
TODO
I plan on doing some experiments on how the
&str ident => K map_key
resolution could work, but if anyone got a good idea on how this can be done, I'd very happy to read that!