fizyk20 / generic-array

Generic array types in Rust
MIT License
404 stars 77 forks source link

Unchecked versions of GenericArray::from_[mut_]slice #124

Open eggyal opened 2 years ago

eggyal commented 2 years ago

Minor point, but would it be possible to expose an unsafe version of these functions that doesn't perform any length-check?

novacrazy commented 2 years ago

Not exactly ergonomic, but you could do something like this in your own code where necessary:

use generic_array::{GenericArray, typenum::{U24, Unsigned}};

pub fn from_mut_slice(x: &mut [u8]) -> &mut GenericArray<u8, U24> {
    if x.len() != U24::USIZE {
        unsafe { std::hint::unreachable_unchecked() }
    }
    GenericArray::from_mut_slice(x)
}
novacrazy commented 2 years ago

Additional notes based on deleted comment:

If the goal is optimization, then the unreachable_unchecked tells the compiler there is no other option than to succeed and will remove the panic machinery.

Click here to open example ```rust pub fn version_a(x: &mut [u8]) -> &mut GenericArray { if x.len() != U24::USIZE { unsafe { std::hint::unreachable_unchecked() } } GenericArray::from_mut_slice(x) } pub fn version_b(x: &mut [u8]) -> &mut GenericArray { GenericArray::from_mut_slice(x) } ``` compiles down to ```asm playground::version_a: movq %rdi, %rax retq playground::version_b: subq $56, %rsp movq %rsi, (%rsp) cmpq $24, %rsi jne .LBB4_1 movq %rdi, %rax addq $56, %rsp retq .LBB4_1: movq $0, 8(%rsp) movq %rsp, %rdi leaq 8(%rsp), %rsi callq core::panicking::assert_failed ud2 ```

If the goal is to just be unsafe for the sake of being unsafe, that's just asking for trouble.

eggyal commented 2 years ago

Thank you, this does (unergonomically, as you say) compile down to what I need. However, it also relies on:

  1. GenericArray::from_mut_slice being inlined (its #[inline] attribute is only a hint, which the compiler can ignore); and

  2. an optimisation pass recognising that both tests (that in my fn and that in GenericArray::from_mut_slice) can thus be omitted.

I'm quite happy with this workaround if exposing _unchecked methods is unacceptable to this library. Feel free to close. Thanks again!

novacrazy commented 1 year ago

As of 1.0, unsafe { GenericArray::try_from_mut_slice(slice).unwrap_unchecked() } should be sufficient. Still relies on the optimizations, but I've marked everything involved with that as #[inline(always)].