bytemuck
bytemuck copied to clipboard
Raw pointer cast functions
Would it make sense to include cast functions that handle raw pointers?
fn cast_ptr(a: *const A) -> *const Bfn cast_mut_ptr(a: *mut A) -> *mut Bfn 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).
I would not necessarily be opposed to these, but a few notes:
- (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 justas-cast them.) - As has been mentioned in other issues/PRs,
bytemuckalready has a lot of functions (https://github.com/Lokathor/bytemuck/pull/132#issuecomment-1234896922) - If these were added, I would expect the corresponding
try_functions to also exist. - I would expect the ordering of the words in the function names to match the existing functions, i.e. either
ptrbetweensliceandmut(my preference:cast_ptr_mut/cast_slice_ptr_mut) orptraftermut(cast_mut_ptr/cast_slice_mut_ptr). For the second case, IMO it would read better ifcast_ptr/cast_slice_ptrhadconstwhere the*mutversions havemut. - ~~
cast_slice_ptrandcast_slice_ptr_mutcould 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]>::lenis 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_partswas only stabilized in Rust 1.42.0 which is abovebytemuck's MSRV of 1.34.0, so the slice pointer functions would probably have to be behind a feature flag anyway.
- Also, making a raw slice pointer with
- Raw slice pointers are allowed to have element-lengths that would give them a byte-length longer than
usize::MAXbytes, which would introduce an additional failure case tocast_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 intoPodCastError::SizeMismatchI suppose (PodCastErroris not#[non_exhaustive], so a new variant could not be added semver-compatibly), or a new error type could be added similar toCheckedCastError. 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);
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
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.
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