Module zaplib::cast

source · []
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 structs to manage your shader data, which we then read out as f32 slices or Vecs.

Given a struct like

#[repr(C)]
struct MyStruct(u32, u32);

the following casts are supported and safe:

  1. cast_slice::<MyStruct, u32>(..)
  2. cast_slice::<u32, MyStruct>(..) if the slice has the right len
  3. cast_slice::<MyStruct, u8>(..)
  4. cast_vec::<MyStruct, u32>(..)
  5. cast_vec::<u32, MyStruct>(..) if the Vec has the right len and capacity

The following casts cause a panic:

  1. cast_slice::<u8, MyStruct>(..) “from” alignment is not a multiple of “to” alignment
  2. cast_slice::<MyStruct, u64>(..) “from” alignment is not a multiple of “to” alignment
  3. cast_vec::<MyStruct, u64>(..) “from” alignment is different from “to” alignment
  4. cast_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.

  1. cast_slice::<u32, Option<u32>> or any other data structure that can’t be arbitrarily initialized
  2. cast_slice::<u32, (u32, u32)> doesn’t use #[repr(C)], so might behave unexpectedly
  3. cast_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:

Functions

Cast a slice from one type to another.

Cast a Vec from one type to another.