Skip to content
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

[WIP] Implement Fill for some MaybeUninit types #1241

Closed
wants to merge 1 commit into from
Closed

[WIP] Implement Fill for some MaybeUninit types #1241

wants to merge 1 commit into from

Conversation

AngelicosPhosphoros
Copy link

It can be beneficial for users to avoid initialization in hot code.
Also, init elimination is hard for LLVM because some of Fill::try_fill for some types marked as #[inline(never)].

It can be beneficial for users to avoid initialization in hot code.
Also, init elimination is hard for LLVM because some of `Fill::try_fill` for some types marked as `#[inline(never)]`.
@AngelicosPhosphoros
Copy link
Author

AngelicosPhosphoros commented Jul 8, 2022

I want to add MaybeUninit impls for u16, u32, u64, usize, u128, etc but this would require some API changes for RngCore trait because RngCore::try_fill_bytes accepts &mut [u8] but not &mut [MaybeUninit<u8>].

How is better to implement this? Can I change existing APIs or should I just add new (especially for inner parts like rng_core which still available to end-users).

Also, would need to add such method to getrandom too.

Another option is to accept *mut T instead of &mut [MaybeUninit<T>] but this is more C-style IMHO.

Copy link
Member

@dhardy dhardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also #1080. I have yet to be convinced that we need to be able to write to un-init memory directly.

Comment on lines +523 to +524
// Safe to assume init because inner values have uninit type.
mem::MaybeUninit::uninit().assume_init()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you read the doc on assume_init? This is not safe.

It sounds like you want to cast [MaybeUninit<T>; N] to &mut [T]. This is explicitly not allowed by the Rust memory model.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, you are wrong.

This code is same as in MaybeUninit docs actually.
https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element

And I make an array of MaybeUninits which can be created from uninit array.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. It's just your comment that is wrong then: the reason it is safe is that the outer type is an array of MaybeUninit.

@dhardy
Copy link
Member

dhardy commented Jul 9, 2022

It can be beneficial for users to avoid initialization in hot code.

Benchmarks please. If you're introducing new unsafe code purely for performance reasons, then strong justification is required.

@dhardy
Copy link
Member

dhardy commented Jul 9, 2022

I want to add MaybeUninit impls for u16, u32, u64, usize, u128, etc but this would require some API changes for RngCore trait because RngCore::try_fill_bytes accepts &mut [u8] but not &mut [MaybeUninit].

This was discussed before, in #1080 I think (possibly elsewhere too). Summary: strong justification is required.

But I agree that new API in rand_core::RngCore is required to do this properly.

@AngelicosPhosphoros AngelicosPhosphoros changed the title Implement Fill for some MaybeUninit types (Need help) [WIP] Implement Fill for some MaybeUninit types Jul 9, 2022
Copy link
Member

@dhardy dhardy left a 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 close this PR as "not very useful" (see individual comments).

Note that it doesn't really address #1080 anyway, which requires requires changes allowing RngCore fill an uninitialized byte-array directly (the element-wise fill used here probably negates any potential performance benefits).

Comment on lines +399 to +422
macro_rules! impl_fill_delegate_to_maybe_uninit{
() => {};
($t:ty) => {
impl Fill for [$t] {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
Fill::try_fill(
unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr()
as *mut mem::MaybeUninit<$t>,
self.len()
)
},
rng,
)
}
}
};
($t:ty, $($tt:ty,)*) => {
impl_fill_delegate_to_maybe_uninit!($t);
impl_fill_delegate_to_maybe_uninit!($($tt,)*);
};
}

impl_fill_delegate_to_maybe_uninit!(bool, char, f32, f64,);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part doesn't make much sense to me: replacing what was a safe impl of Fill for [bool] (etc.) with an unsafe one which lowers to [MaybeUninit<bool>] (etc.).

Comment on lines -322 to 333
impl Fill for [$t] {
impl Fill for [mem::MaybeUninit<$t>] {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
for elt in self.iter_mut() {
*elt = rng.gen();
*elt = mem::MaybeUninit::new(rng.gen());
}
Ok(())
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementing Fill for [MaybeUninit<bool>] (etc.) is okay in itself, but I don't think it very useful. In order to use it with uninitialized memory, assume_init is needed somewhere, which thus requires the user use unsafe code (and based on the assumption that fill succeeded). I mean, users can use this API correctly, but not easily, and it isn't difficult to implement equivalent functionality in userspace anyway.

@dhardy dhardy closed this Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants