-
-
Notifications
You must be signed in to change notification settings - Fork 84
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
[Feature] extend TransparentWrapper
conversion functions
#58
Conversation
replace `merge_imports = true` (deprecated) with `imports_granularity = "Crate"`
This looks correct. I'll have @thomcc take a look too, because they wrote this trait. |
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.
Up on line 28 you should add this method to the list of methods that may not be overwridden.
Otherwise it seems fine.
TransparentWrapper::wrap_slice
TransparentWrapper::{wrap_slice, wrap_slice_mut}
I've decided to extend this PR some more, therefore I converted it into a draft. |
TransparentWrapper::{wrap_slice, wrap_slice_mut}
TransparentWrapper
conversion functions
I've now rewritten and extended the PR quite a bit. Please take a look at it again :). I would also like to introduce the Also I would like to add some docs, mentioning the usefulness of this trait for using bytemuck with types from extern crates. |
I believe that the transmute_copy trick used to wrap can also be used to unwrap. |
rewriting some docs for conciseness rename `Wrapped` to `Inner`, because it's hard to visually differentiate between `Wrapper` and `Wrapped`
Implement 3 new wrapping functions on `TransparentWrapper` providing new conversions. - `TransparentWrapper::wrap(s: Inner) -> Self` - `TransparentWrapper::wrap_slice(s: &[Inner]) -> &[Self]` - `TransparentWrapper::wrap_slice_mut(s: &mut [Inner]) -> &mut [Self]`
Implement counterparts to `TransparentWrapper::wrap_{}` functions providing reverse conversions. - `TransparentWrapper::unwrap(self) -> Inner` - `TransparentWrapper::unwrap_ref(&self) -> &Inner` - `TransparentWrapper::unwrap_mut(&mut self) -> &mut Inner` - `TransparentWrapper::unwrap_slice(s: &[Self]) -> &[Inner]` - `TransparentWrapper::unwrap_slice_mut(s: &mut [Self]) -> &mut [Inner]`
This test is only for MIRI to check all trait functions on `TransparentWrapper` if they cause any UB. The output of the functions is not checked.
Okay, another rather big overhaul of this PR is done 😄 . I adjusted the docs a little to be more concise. Also I renamed I've also added the I also added a test which currently just checks for UB using MIRI. Thanks to this I already catched a bug causing UB. |
I'm not sure |
@thomcc I agree, but I haven't come up with a better fitting terminology. It is a wrapper after all :D. |
I've now added some docs and a example mentioning how |
This PR is no longer a draft! I'm pretty happy with it. Now I'm waiting for a review and some feedback on what's left to do :). |
I just noticed, that deriving |
I feel like the derive should continue to fail even then. You can still write it manually. The fact that you didn't just derive it is a good time to say "i know the base type doesn't impl the trait but i trust i can bend the rule in this case" |
@Lokathor Hmm, It's just unfortunate, that in this case you can't have the derive check, if the safety guarantees hold. Does the current proc-macro implementation check all aspects of the unsafe contract? It should, because otherwise there would be a possibility of introducing UB without having an unsafe block... If the derive can check all aspects of the unsafe contract, then you shouldn't need to think about bending the rules, because it's guaranteed to be safe and sound :). |
It may be possible to fix. We could probably finish off the PR noe and file an issue for the derives later. |
Sounds good to me! |
src/lib.rs
Outdated
@@ -30,6 +30,17 @@ | |||
//! these traits are `unsafe`, and you should carefully read the requirements | |||
//! before adding the them to your own types. | |||
//! | |||
//! ## Using Types from Extern Crates |
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 don't think that we should document this idea.
It's possible, but it's kinda extra dodgy, particularly because it runs explicitly against the claimed rules of Pod and Zeroable.
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.
Yeah, I get your point. It's getting kinda convoluted.
But I don't know how obvious this use of TransparentWrapper
is. It is a pretty nice feature to have, so people should know about it.
Maybe we need to reformulate the docs some more? I'll give it a try and if it looks bad, we probably have to remove it...
What is most desirable?
- Mentioning
TransparentWrapper
everywhere where it's relevant (so also inPod
). - Being subtle about it and just mentioning it in it's own docs.
- Not mention it at all.
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 don't think we should mention it, since it's not sound unless you pin the version exactly. If other crates haven't opted into the bytemuck requirements, they're free to break them at any time without a semver-major change.
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.
Yeah, the reason that the docs for Pod and Zeroable require that the field type also is Pod or Zeroable is because then SemVer kicks in, specifically that it's a SemVer Break to remove a trait impl.
If you newtype a struct and declare the wrapper type Pod, then the inner type adds a &'static str
field in a minor update (not unreasonable!) then suddenly you're hosed.
So I think that this should stay as a "secret thing the type system technically allows but officially you shouldn't so legally you can't complain when this blows up in your face (and it easily might)" sort of thing.
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.
Okay, I see. That's a reasonable argument.
In this case I'm going to remove all mentions of this.
I think I'm not really a fan of having this many functions on the trait. It would probably be better to move some/most of them to free functions, since at this point there's a real risk of collision with inherent or deref impls, especially with the generic naming scheme... |
@thomcc |
Methods on `TransparentWrapper` trait are now associated functions. They now take `Self` instead of `self` as argument) - `TransparentWrapper::unwrap(s: Self)` - `TransparentWrapper::unwrap_ref(s: &Self)` - `TransparentWrapper::unwrap_mut(s: &mut Self)`
Anything left to do? |
I haven't had time to get to this. My "weekend" is Sun/Mon, so I'll try to get this merged. |
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'm going to approve and merge now, and I'll think hard for a bit about if there's a better name than unwrap
to use.
I think I also want to sort out how we're going to adapt to min_const_generics being available before the next crates.io release.
Yeah, my first PR was merged 🥳. Thanks :) |
This PR extends the
TransparentWrapper
trait by adding new conversion functions.Namely:
These three missing
wrap_{}
functions.TransparentWrapper::wrap(s: Inner) -> Self
TransparentWrapper::wrap_slice(s: &[Inner]) -> &[Self]
TransparentWrapper::wrap_slice_mut(s: &mut [Inner]) -> &mut [Self]
These five
unwrap_{}
functions, which are the counterparts of thewrap_{}
functions. They just invert the conversion.TransparentWrapper::unwrap(self) -> Inner
TransparentWrapper::unwrap_ref(&self) -> &Inner
TransparentWrapper::unwrap_mut(&mut self) -> &mut Inner
TransparentWrapper::unwrap_slice(s: &[Self]) -> &[Inner]
TransparentWrapper::unwrap_slice_mut(s: &mut [Self]) -> &mut [Inner]
This is useful for implementing
Zeroable
andPod
on types from extern crates in order to usebytemuck::{}
functions likebytemuck::cast_slice
using the new-ype pattern andTransparentWrapper
.The goal of this PR is to support all
bytemuck::{}
functions.This is possible with this PR:
This PR also includes a test, which uses the exact example code from above. This is for MIRI to check for any potential UB.
As you can see, there currently isn't any checking done on the output of the functions. This is something left todo.
Can somebody please check the soundness of the implementation, because I have very little expertise with unsafe code.
I've written up some docs on how this trait can be used in combination with the newtype pattern to use the bytemuck functions on foreign types from external crates.
I also adjusted
rustfmt.toml
in the first commit, because of the deprecation ofmerge_imports = true
. It is being replaced byimports_granularity = "Crate"
. Furthermore I rancargo +nightly fmt
to format the codebase. I hope these two changes are fine.I'm open to suggestions!
This is my first PR ever 🥳 .