## Crate ref_cast

Source
Expand description

This crate provides a derive macro for generating safe conversions from `&T` to `&U` where the struct `U` contains a single field of type `T`.

## §Basic example

    use ref_cast::RefCast;

    #[derive(RefCast)]
    #[repr(transparent)]
    struct U(String);

    fn main() {
        let s = String::new();

        // Safely cast from `&String` to `&U`.
        let u = U::ref_cast(&s);
    }

Note that `#[repr(transparent)]` is required in order for the conversion to be sound. The derive macro will refuse to compile if that is not present.

## §Realistic example

Suppose we have a multidimensional array represented in a flat buffer in row-major order for performance reasons, but we want to expose an indexing operation that works in column-major order because it is more intuitive in the context of our application.

    const MAP_WIDTH: usize = 4;

    struct Tile(u8);

    struct TileMap {
        storage: Vec<Tile>,
    }

    // `tilemap[x][y]` should give us `tilemap.storage[y * MAP_WIDTH + x]`.

The signature of the `Index` trait in Rust is such that the output is forced to be borrowed from the type being indexed. So something like the following is not going to work.

    struct Column<'a> {
        tilemap: &'a TileMap,
        x: usize,
    }

    // Does not work! The output of Index must be a reference that is
    // borrowed from self. Here the type Column is not a reference.
    impl Index<usize> for TileMap {
        fn index(&self, x: usize) -> Column {
            assert!(x < MAP_WIDTH);
            Column { tilemap: self, x }
        }
    }

    impl<'a> Index<usize> for Column<'a> {
        fn index(&self, y: usize) -> &Tile {
            &self.tilemap.storage[y * MAP_WIDTH + self.x]
        }
    }

Here is a working approach using `RefCast`.

    #[derive(RefCast)]
    #[repr(transparent)]
    struct Strided([Tile]);

    // Implement `tilemap[x][y]` as `tilemap[x..][y * MAP_WIDTH]`.
    impl Index<usize> for TileMap {
        type Output = Strided;
        fn index(&self, x: usize) -> &Self::Output {
            assert!(x < MAP_WIDTH);
            Strided::ref_cast(&self.storage[x..])
        }
    }

    impl Index<usize> for Strided {
        type Output = Tile;
        fn index(&self, y: usize) -> &Self::Output {
            &self.0[y * MAP_WIDTH]
        }
    }

## Traits§

RefCast
  Safely cast `&T` to `&U` where the struct `U` contains a single field of type `T`.

## Attribute Macros§

ref_cast_custom
  Create a function for a RefCast-style reference cast. Call site gets control of the visibility, function name, argument name, `const`ness, unsafety, and documentation.

## Derive Macros§

RefCast
  Derive the `RefCast` trait.
RefCastCustom
  Derive that makes the `ref_cast_custom` attribute able to generate freestanding reference casting functions for a type.