bytemuck icon indicating copy to clipboard operation
bytemuck copied to clipboard

Raw pointer cast functions

Open bravely-beep opened this issue 1 year ago • 4 comments

Would it make sense to include cast functions that handle raw pointers?

  • fn cast_ptr(a: *const A) -> *const B
  • fn cast_mut_ptr(a: *mut A) -> *mut B
  • fn cast_slice_ptr(a: *const [A]) -> *const [B]
  • fn cast_mut_slice_ptr(a: *mut [A]) -> *mut [B]

This would be useful when working with data that is unsafe to take references to (e.g. volatile IO memory).

bravely-beep avatar Jul 27 '23 10:07 bravely-beep

I would not necessarily be opposed to these, but a few notes:

  1. (I assume their failure conditions and semantics would be mostly the same as cast_ref/cast_mut/cast_slice/cast_slice_mut? Otherwise I don't really see the point; if they are meant to always succeed you can just as-cast them.)
  2. As has been mentioned in other issues/PRs, bytemuck already has a lot of functions (https://github.com/Lokathor/bytemuck/pull/132#issuecomment-1234896922)
  3. If these were added, I would expect the corresponding try_ functions to also exist.
  4. I would expect the ordering of the words in the function names to match the existing functions, i.e. either ptr between slice and mut (my preference: cast_ptr_mut/cast_slice_ptr_mut) or ptr after mut (cast_mut_ptr/cast_slice_mut_ptr). For the second case, IMO it would read better if cast_ptr/cast_slice_ptr had const where the *mut versions have mut.
  5. ~~cast_slice_ptr and cast_slice_ptr_mut could not (currently) be (fully) implemented on stable AFAIK, since there is no (fully "blessed") way to get the length of a general slice pointer on stable (<*const [T]>::len is unstable. There are some partial workarounds/polyfills listed on the tracking issue but none are completely general and safe.).~~
    • Also, making a raw slice pointer with std::ptr::slice_from_raw_parts was only stabilized in Rust 1.42.0 which is above bytemuck's MSRV of 1.34.0, so the slice pointer functions would probably have to be behind a feature flag anyway.
  6. Raw slice pointers are allowed to have element-lengths that would give them a byte-length longer than usize::MAX bytes, which would introduce an additional failure case to cast_slice_ptr(_mut) that doesn't exist for other casts: "Casting this slice pointer from the source to destination type would overflow the element-length of the slice", though this could reasonably be folded into PodCastError::SizeMismatch I suppose (PodCastError is not #[non_exhaustive], so a new variant could not be added semver-compatibly), or a new error type could be added similar to CheckedCastError. Example:
let too_long: *const [u32] = std::ptr::slice_from_raw_parts(std::ptr::null(), usize::MAX);
let what_error_should_this_return: Result<*const [u8], PodCastError> = try_cast_slice_ptr(too_long);

zachs18 avatar Jul 28 '23 03:07 zachs18

Yeah, there's a lot more small design work than it might seem at first.

Personally, for volatile access i have the voladdress crate, which has always served my needs well enough to not bother with raw pointers in bytemuck

Lokathor avatar Jul 28 '23 07:07 Lokathor

If I may, I would suggest to leave slice pointer casts out for now, but add support for NonNull pointers.

I'm doing this in some of my projects, and I'm basically copy-pasting cast_ref and friends. These would be trivial additions.

simonask avatar Feb 13 '24 15:02 simonask

there is no (fully "blessed") way to get the length of a general slice pointer on stable.

Since Rust 1.75.0, with the stabilization of wrapping_byte_add it is possible to write a correct polyfill of <*mut [T]>::len on stable.

https://github.com/rust-lang/rust/issues/71146#issuecomment-1871542032

zachs18 avatar Feb 20 '24 04:02 zachs18