bytemuck

repository·main·Indexed 21 days ago

https://github.com/lokathor/bytemuck

A utility crate for safely performing bitwise reinterpretation (bit casting) between different Rust data types and slices. It is widely used in the graphics community for preparing data buffers for GPU consumption. The crate provides functions like cast_slice and cast_slice_mut, as well as the bytemuck_derive crate for automatically implementing safety traits such as Pod, Zeroable, AnyBitPattern, and NoUninit.

Tokens
6.9K
Snippets
23
Records
40
Agent score
77%

What's inside bytemuck

  1. Use bytemuck_derive for automatic trait implementation

    main
    The bytemuck_derive crate provides procedural macros to automatically implement the traits required by bytemuck. Instead of manually implementing traits like Pod (Plain Old Data) or Zeroable, you can use derive macros to let the compiler handle the boilerplate, ensuring your types meet the necessary safety requirements for bitwise operations.
  2. What is bytemuck and how does it work?

    main

    bytemuck is a crate designed for performing safe "bit cast" operations between data types. A bit cast takes a value and reinterprets its underlying bits as a different type without changing the bits themselves.

    Key distinctions:

    • It is not like the as keyword.
    • It is not like the From trait.
    • It is most similar to f32::to_bits, but generalized to allow conversions between various data types.
  3. Cast slices of data using cast_slice and cast_slice_mut

    main

    When working with slices, bytemuck provides cast_slice and cast_slice_mut to reinterpret a span of memory as a different type.

    Unlike a direct bitcast of a single value, these functions adjust the slice length if the element size of the new type differs from the original. This is commonly used in 3D graphics to cast slices of vertex or color data into u8 slices for GPU upload.

  4. Requirements for deriving Contiguous

    main

    To derive Contiguous on an enum, the following conditions must be met:

    • Type: Must be a fieldless enum.
    • Representation: Must have an explicit #[repr(Int)] (e.g., #[repr(u8)]).
    • Discriminants: All enum discriminants must be contiguous (e.g., if the min is 0 and max is 2, there must be exactly 3 variants).
  5. Requirements for deriving Zeroable

    main

    To derive Zeroable on a type, the following conditions must be met:

    • Structs: All fields must implement Zeroable.
    • Enums: Must have an explicit #[repr(C)], #[repr(Int)], or #[repr(C, discriminant)] annotation. Additionally, the enum must have a variant with a discriminant of 0.
    • Unions: Unions are always considered Zeroable by default.
  6. Use `BoxBytes` to manage arbitrary alignment allocations

    main

    BoxBytes is a type that represents a heap allocation of [u8] but preserves the original Layout (alignment and size) of the allocation. This is useful when you want to treat a Box<T> as a byte slice without losing its alignment properties.

    Key Operations:

    • Convert Box<T> to BoxBytes: Use box_bytes_of(input: Box<T>) or BoxBytes::from(value). This works for Sized + NoUninit types, slices [T], and str.
    • Convert BoxBytes back to Box<T>: Use try_from_box_bytes(input: BoxBytes) -> Result<Box<T>, (PodCastError, BoxBytes)>. This is safe if the alignment and size match.
    • Unwrap conversion: Use from_box_bytes<T>(input: BoxBytes) -> Box<T> which panics on error.

    Accessing data: BoxBytes implements Deref<Target = [u8]> and DerefMut.

    pub struct BoxBytes {
      ptr: NonNull<u8>,
      layout: Layout,
    }
    
    pub fn box_bytes_of<T: sealed::BoxBytesOf + ?Sized>(input: Box<T>) -> BoxBytes
    pub fn try_from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(input: BoxBytes) -> Result<Box<T>, (PodCastError, BoxBytes)>
    pub fn from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(input: BoxBytes) -> Box<T>
  7. Requirements for deriving CheckedBitPattern

    main

    To derive CheckedBitPattern, the following conditions must be met:

    • Structs: Must be #[repr(C)] or #[repr(transparent)]. Structs containing generic parameters are not supported.
    • Enums:
      • If fieldless: Must be #[repr(C)] or #[repr(Int)].
      • If containing fields: Must be #[repr(C)] or #[repr(Int)].
    • Unions: Deriving CheckedBitPattern for unions is not supported.
  8. How bit-casting works in bytemuck

    main

    bytemuck provides utilities for casting between plain data types (bit-casting). The library categorizes data into five basic forms, each with corresponding casting functions:

    FormFunctionDescription
    TcastCasts a value by copying it to a new location
    &Tcast_refCasts a shared reference
    &mut Tcast_mutCasts a mutable reference
    &[T]cast_sliceCasts a shared slice
    &mut [T]cast_slice_mutCasts a mutable slice

    Safety Traits

    To maintain memory safety, these functions are guarded by marker traits:

    • NoUninit: Ensures the type does not contain uninitialized memory.
    • AnyBitPattern: Ensures the type can be safely reinterpreted as any bit pattern.
    • Pod: A combination of NoUninit and AnyBitPattern. Most casting functions require Pod or its constituent traits.
    • Zeroable: Indicates a type can be safely initialized with all-zero bits.

    Error Handling

    • Panicking versions: Functions like cast or cast_ref will panic if the cast is invalid (e.g., size mismatch or alignment issues).
    • Result versions: Functions prefixed with try_ (e.g., try_cast, try_cast_slice) return a Result<T, PodCastError> instead of panicking.
    • Static verification: If the must_cast feature is enabled, you can use must_ functions which cause a compilation error if the cast cannot be statically verified as valid.
    // Example of casting a value
    let val: u32 = 42;
    let f: f32 = bytemuck::cast(val);
    
    // Example of casting a slice
    let bytes: &[u8] = &[1, 2, 3, 4];
    let vals: &[u32] = bytemuck::cast_slice(bytes);
  9. Requirements for deriving AnyBitPattern

    main

    To derive AnyBitPattern on a type, the following conditions must be met:

    • Structs: All fields must implement AnyBitPattern.
    • Enums: Deriving AnyBitPattern for enums is not supported.
    • Unions: Unions are always considered AnyBitPattern by default.
    • Note: Deriving AnyBitPattern implies the type also implements Zeroable.
  10. Understanding repr(C) and integer discriminants in bytemuck

    main

    To ensure bit-pattern safety, bytemuck relies on stable memory layouts. When deriving traits for enums, the following repr patterns are handled:

    • #[repr(C)]: Uses the C representation. For enums with fields, bytemuck generates an internal fieldless repr(C) enum to safely calculate the discriminant size.
    • #[repr(integer)] (e.g., #[repr(u8)]): Uses a specific integer type for the discriminant.
    • #[repr(C, integer)]: A combination of C representation and a specific integer discriminant.

    These attributes allow the derive macro to correctly validate that the enum's memory layout is predictable and contains no unexpected padding.

  11. How bytemuck ensures types have no padding

    main

    When you derive traits like Pod or AnyBitPattern using bytemuck_derive, the macro automatically generates a compile-time assertion to ensure your type has no padding.

    It calculates the sum of the sizes of all fields (and the enum discriminant, if applicable) and asserts that this sum equals the total size_of the type. If padding is detected, the compiler will emit an error with the message: derive(<TRAIT_NAME>) was applied to a type with padding.

  12. Requirements for deriving Pod

    main

    To derive Pod on a type, the following conditions must be met:

    • Structs: Must be #[repr(C)] or #[repr(transparent)]. If the struct contains generic parameters, it must be either #[repr(C, packed)] or #[repr(transparent)] because padding requirements for generic structs cannot be verified.
    • Enums: Deriving Pod for enums is not supported.
    • Unions: Deriving Pod for unions is not supported.
    • Fields: All fields within the struct must also implement Pod.