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 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).
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,
bytemuck
already 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
ptr
betweenslice
andmut
(my preference:cast_ptr_mut
/cast_slice_ptr_mut
) orptr
aftermut
(cast_mut_ptr
/cast_slice_mut_ptr
). For the second case, IMO it would read better ifcast_ptr
/cast_slice_ptr
hadconst
where the*mut
versions havemut
. - ~~
cast_slice_ptr
andcast_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 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::MAX
bytes, 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::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 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