Lokathor / bytemuck

A crate for mucking around with piles of bytes
https://docs.rs/bytemuck
Apache License 2.0
718 stars 78 forks source link

`const`-ify casting functions #280

Open kovaxis opened 2 days ago

kovaxis commented 2 days ago

I don't know if it's possible, but it would be great if the bytemuck::cast* functions where const fn so that we could include_bytes! into a struct or a list of structs.

zachs18 commented 2 days ago

The by-value bytemuck::cast could probably be made const (under a feature gate), like bytemuck::must_cast, though this would AFAICT require changing how the panic message is made for cast[^2].

The by-immutable-ref cast_ref and cast_slice would have the issue that converting pointers to integers (to check alignment) is not necessarily possible in const eval.[^1] (Though the size checks are dependant on pointer addresses, so could be implemented in consteval just fine (except for [^2]).)

Note that the by-immutable-ref must_cast_ref and must_cast_slice functions are const, and they can be because they are intentionally more conservative in that they only accept casts that cannot fail (e.g. &[u16] -> &[u8] is fine, but not &[u8] -> &[u16] since the input pointer could be unaligned, which we can't check in const eval, and &[u8] -> &[[u8; 2]] is not fine, since the length could be odd, though this could be checked in const-eval, just not in the type system).

Because of this, must_cast_slice is probably not useful for include_bytes!ing struct data. However, include_bytes! gives an array, so theoretically you could use by-value must_cast if you know the length of the data.

[^1]: cast_mut and cast_slice_mut have the same issue, and also they are also blocked on feature(const_mut_refs) which IIUC is planned to become stable in Rust 1.83.0.

[^2]: since you can't do panic!("{}", non_string_literal) in const fn, which is currently used, so without something like const_eval_select on stable the runtime impl would have to be the same as the const impl.

Lokathor commented 2 days ago

What I've done for byte including before is https://docs.rs/gba/latest/gba/struct.Align4.html and also https://docs.rs/gba/latest/gba/macro.include_aligned_bytes.html

the included bytes are actually an array to start, so the Align4 can take the array by value, align it to 4 (which adds padding if it's not a multiple of 4 in length!), and then your data could be transmuted to u32 or whatever.