Expand description
Functions for semi-safely casting various things to each other.
We mostly use this for slices of geometry and instance data, since you want
to be able to write simple Rust struct
s to manage your shader data, which
we then read out as f32
slices or Vec
s.
Given a struct
like
#[repr(C)]
struct MyStruct(u32, u32);
the following casts are supported and safe:
cast_slice::<MyStruct, u32>(..)
cast_slice::<u32, MyStruct>(..)
if the slice has the rightlen
cast_slice::<MyStruct, u8>(..)
cast_vec::<MyStruct, u32>(..)
cast_vec::<u32, MyStruct>(..)
if the Vec has the rightlen
andcapacity
The following casts cause a panic:
cast_slice::<u8, MyStruct>(..)
“from” alignment is not a multiple of “to” alignmentcast_slice::<MyStruct, u64>(..)
“from” alignment is not a multiple of “to” alignmentcast_vec::<MyStruct, u64>(..)
“from” alignment is different from “to” alignmentcast_vec::<MyStruct, u8>(..)
“from” alignment is different from “to” alignment
The following casts are unsafe but DON’T cause a panic. Please just don’t do them.
cast_slice::<u32, Option<u32>>
or any other data structure that can’t be arbitrarily initializedcast_slice::<u32, (u32, u32)>
doesn’t use#[repr(C)]
, so might behave unexpectedlycast_vec
with a custom allocator (requires the unstable allocator_api feature)
TODO(JP): We should check that you’re casting to a struct that can be initialized with
arbitrary byte data. Ideally Rust should implement something like an
Arbitrary
trait.
We currently use 'static + Copy
as a proxy for such a trait, since at least this disallows
anything that implements Drop
or has (non-static) references. We should also update
places like crate::Area::get_slice
when improving this.
Even better could be to add a custom derive
macro to make sure that a struct only contains
a certain type of scalar, e.g. #[derive(OnlyScalars<f32>)]
for a typical geometry or instance
struct. Then we can prevent a bunch of runtime panics at compile time.
We can also use something like https://docs.rs/repr-trait/latest/repr_trait/trait.C.html
to make sure the data is properly represented using #[repr(C)]
.
See:
- https://users.rust-lang.org/t/why-does-vec-from-raw-parts-require-same-size-and-not-same-size-capacity/73036
- https://github.com/nabijaczleweli/safe-transmute-rs/issues/16#issuecomment-471066699
- https://rawcdn.githack.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/fn.transmute_vec.html
- https://github.com/rust-lang/rust/blob/190feb65290d39d7ab6d44e994bd99188d339f16/src/libstd/sys/windows/alloc.rs#L46-L57
- https://github.com/rust-lang/rust/blob/b6f580acc0ce233d5c4d1f9680d354fded88b824/library/std/src/sys/common/alloc.rs#L30
Functions
Cast a slice from one type to another.