Casts

Casts are a superset of coercions: every coercion can be explicitlyinvoked via a cast. However some conversions require a cast.While coercions are pervasive and largely harmless, these “true casts”are rare and potentially dangerous. As such, casts must be explicitly invokedusing the as keyword: expr as Type.

True casts generally revolve around raw pointers and the primitive numerictypes. Even though they’re dangerous, these casts are infallible at runtime.If a cast triggers some subtle corner case no indication will be given thatthis occurred. The cast will simply succeed. That said, casts must be validat the type level, or else they will be prevented statically. For instance,7u8 as bool will not compile.

That said, casts aren’t unsafe because they generally can’t violate memorysafety on their own. For instance, converting an integer to a raw pointer canvery easily lead to terrible things. However the act of creating the pointeritself is safe, because actually using a raw pointer is already marked asunsafe.

Here’s an exhaustive list of all the true casts. For brevity, we will use *to denote either a *const or *mut, and integer to denote any integralprimitive:

  • *T as *U where T, U: Sized
  • *T as *U TODO: explain unsized situation
  • *T as integer
  • integer as *T
  • number as number
  • field-less enum as integer
  • bool as integer
  • char as integer
  • u8 as char
  • &[T; n] as *const T
  • fn as *T where T: Sized
  • fn as integer

Note that lengths are not adjusted when casting raw slices -*const [u16] as *const [u8] creates a slice that only includeshalf of the original memory.

Casting is not transitive, that is, even if e as U1 as U2 is a validexpression, e as U2 is not necessarily so.

For numeric casts, there are quite a few cases to consider:

  • casting between two integers of the same size (e.g. i32 -> u32) is a no-op
  • casting from a larger integer to a smaller integer (e.g. u32 -> u8) willtruncate
  • casting from a smaller integer to a larger integer (e.g. u8 -> u32) will
    • zero-extend if the source is unsigned
    • sign-extend if the source is signed
  • casting from a float to an integer will round the float towards zero
  • casting from an integer to float will produce the floating pointrepresentation of the integer, rounded if necessary (rounding tonearest, ties to even)
  • casting from an f32 to an f64 is perfect and lossless
  • casting from an f64 to an f32 will produce the closest possible value(rounding to nearest, ties to even)