-
-
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 MutUntyped::map_unchanged
#6430
add MutUntyped::map_unchanged
#6430
Conversation
Definitely opposed to alternate solution 1: it exposes far more internals of change detection than I'd like. I trust you that solution 2 is too annoying. |
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.
More pointer shenanigans. It makes sense why this is needed, and the docs are great. Very very grateful for the lifetimed pointer types here.
We can't check whether the types match, because we literally don't store that information on the MutUntyped
:(
I'm on board.
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.
Seems very useful. This will probably simplify some internal code for trait queries.
862e285
to
ceb2fd7
Compare
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.
A few more things, but LGTM. The PR title and description need to be updated.
I'd like to see PR description and title updated + the nit addressed before we merge. |
# Objective `MutUntyped` is a struct that stores a `PtrMut` alongside change tick metadata. Working with this type is cumbersome, and has few benefits over storing the pointer and change ticks separately. Related: #6430 (title is out of date) ## Solution Add a convenience method for transforming an untyped change detection pointer into its typed counterpart. --- ## Changelog - Added the method `MutUntyped::with_type`.
# Objective `MutUntyped` is a struct that stores a `PtrMut` alongside change tick metadata. Working with this type is cumbersome, and has few benefits over storing the pointer and change ticks separately. Related: bevyengine#6430 (title is out of date) ## Solution Add a convenience method for transforming an untyped change detection pointer into its typed counterpart. --- ## Changelog - Added the method `MutUntyped::with_type`.
# Objective `MutUntyped` is a struct that stores a `PtrMut` alongside change tick metadata. Working with this type is cumbersome, and has few benefits over storing the pointer and change ticks separately. Related: bevyengine#6430 (title is out of date) ## Solution Add a convenience method for transforming an untyped change detection pointer into its typed counterpart. --- ## Changelog - Added the method `MutUntyped::with_type`.
MutUntyped::to_typed
MutUntyped::map_unchanged
e283c43
to
caa7122
Compare
Done |
@jakobhellermann once CI is passing I'm comfortable merging this. |
CI is green |
@jakobhellermann if you could remove that unsafe here in the next day or two that would be great. I'll be sure to get this in regardless though; we can make a quick follow-up PR. |
bors r+ |
# Objective `MutUntyped` is the untyped variant of `Mut<T>` that stores a `PtrMut` instead of a `&mut T`. Working with a `MutUntyped` is a bit annoying, because as soon you want to use the ptr e.g. as a `&mut dyn Reflect` you cannot use a type like `Mut<dyn Reflect>` but instead need to carry around a `&mut dyn Reflect` and a `impl FnMut()` to mark the value as changed. ## Solution - Provide a method `map_unchanged` to turn a `MutUntyped` into a `Mut<T>` by mapping the `PtrMut<'a>` to a `&'a mut T` This can be used like this: ```rust // SAFETY: ptr is of type `u8` let val: Mut<u8> = mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::<u8>() }); // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped` let val: Mut<dyn Reflect> = mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }); ``` Note that nothing prevents you from doing ```rust mut_untyped.map_unchanged(|ptr| &mut ()); ``` or using any other mutable reference you can get, but IMO that is fine since that will only result in a `Mut` that will dereference to that value and mark the original value as changed. The lifetimes here prevent anything bad from happening. ## Alternatives 1. Make `Ticks` public and provide a method to get construct a `Mut` from `Ticks` and `&mut T`. More powerful and more easy to misuse. 2. Do nothing. People can still do everything they want, but they need to pass (`&mut dyn Reflect, impl FnMut() + '_)` around instead of `Mut<dyn Reflect>` ## Changelog - add `MutUntyped::map_unchanged` to turn a `MutUntyped` into its typed counterpart
Build failed (retrying...): |
# Objective `MutUntyped` is the untyped variant of `Mut<T>` that stores a `PtrMut` instead of a `&mut T`. Working with a `MutUntyped` is a bit annoying, because as soon you want to use the ptr e.g. as a `&mut dyn Reflect` you cannot use a type like `Mut<dyn Reflect>` but instead need to carry around a `&mut dyn Reflect` and a `impl FnMut()` to mark the value as changed. ## Solution - Provide a method `map_unchanged` to turn a `MutUntyped` into a `Mut<T>` by mapping the `PtrMut<'a>` to a `&'a mut T` This can be used like this: ```rust // SAFETY: ptr is of type `u8` let val: Mut<u8> = mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::<u8>() }); // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped` let val: Mut<dyn Reflect> = mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }); ``` Note that nothing prevents you from doing ```rust mut_untyped.map_unchanged(|ptr| &mut ()); ``` or using any other mutable reference you can get, but IMO that is fine since that will only result in a `Mut` that will dereference to that value and mark the original value as changed. The lifetimes here prevent anything bad from happening. ## Alternatives 1. Make `Ticks` public and provide a method to get construct a `Mut` from `Ticks` and `&mut T`. More powerful and more easy to misuse. 2. Do nothing. People can still do everything they want, but they need to pass (`&mut dyn Reflect, impl FnMut() + '_)` around instead of `Mut<dyn Reflect>` ## Changelog - add `MutUntyped::map_unchanged` to turn a `MutUntyped` into its typed counterpart
Build failed: |
Your method also only works if you a type |
If I have a No |
ah I see what you mean, with this you can do |
2d339c4
to
3c0c068
Compare
Co-authored-by: JoJoJet <[email protected]>
3c0c068
to
251825a
Compare
rebased. Are there any requested changes left? I think they're all addressed |
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 appears complete now, and the PR description looks good.
Looks like CI is failing due to #7905, which renamed the |
@jakobhellermann once this is passing CI I'll merge it in :) |
Adding |
Closing in favor of #9194, which is an adoption of this PR :) |
### **Adopted #6430** # Objective `MutUntyped` is the untyped variant of `Mut<T>` that stores a `PtrMut` instead of a `&mut T`. Working with a `MutUntyped` is a bit annoying, because as soon you want to use the ptr e.g. as a `&mut dyn Reflect` you cannot use a type like `Mut<dyn Reflect>` but instead need to carry around a `&mut dyn Reflect` and a `impl FnMut()` to mark the value as changed. ## Solution * Provide a method `map_unchanged` to turn a `MutUntyped` into a `Mut<T>` by mapping the `PtrMut<'a>` to a `&'a mut T` This can be used like this: ```rust // SAFETY: ptr is of type `u8` let val: Mut<u8> = mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::<u8>() }); // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped` let val: Mut<dyn Reflect> = mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }); ``` Note that nothing prevents you from doing ```rust mut_untyped.map_unchanged(|ptr| &mut ()); ``` or using any other mutable reference you can get, but IMO that is fine since that will only result in a `Mut` that will dereference to that value and mark the original value as changed. The lifetimes here prevent anything bad from happening. ## Alternatives 1. Make `Ticks` public and provide a method to get construct a `Mut` from `Ticks` and `&mut T`. More powerful and more easy to misuse. 2. Do nothing. People can still do everything they want, but they need to pass (`&mut dyn Reflect, impl FnMut() + '_)` around instead of `Mut<dyn Reflect>` ## Changelog - add `MutUntyped::map_unchanged` to turn a `MutUntyped` into its typed counterpart --------- Co-authored-by: Jakob Hellermann <[email protected]> Co-authored-by: JoJoJet <[email protected]>
Objective
MutUntyped
is the untyped variant ofMut<T>
that stores aPtrMut
instead of a&mut T
.Working with a
MutUntyped
is a bit annoying, because as soon you want to use the ptr e.g. as a&mut dyn Reflect
you cannot use a type likeMut<dyn Reflect>
but instead need to carry around a&mut dyn Reflect
and aimpl FnMut()
to mark the value as changed.Solution
map_unchanged
to turn aMutUntyped
into aMut<T>
by mapping thePtrMut<'a>
to a&'a mut T
This can be used like this:
Note that nothing prevents you from doing
or using any other mutable reference you can get, but IMO that is fine since that will only result in a
Mut
that will dereference to that value and mark the original value as changed. The lifetimes here prevent anything bad from happening.Alternatives
Ticks
public and provide a method to get construct aMut
fromTicks
and&mut T
. More powerful and more easy to misuse.&mut dyn Reflect, impl FnMut() + '_)
around instead ofMut<dyn Reflect>
Changelog
MutUntyped::map_unchanged
to turn aMutUntyped
into its typed counterpart