custom.rs |
|
1159 |
layout.rs |
|
1592 |
lib.rs |
[![github]](https://github.com/dtolnay/ref-cast) [![crates-io]](https://crates.io/crates/ref-cast) [![docs-rs]](https://docs.rs/ref-cast)
[github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
[crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
[docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
<br>
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.
[`Index`]: core::ops::Index
```
# const MAP_WIDTH: usize = 4;
#
# struct Tile(u8);
#
# struct TileMap {
# storage: Vec<Tile>,
# }
#
struct Column<'a> {
tilemap: &'a TileMap,
x: usize,
}
# mod index1 {
# use super::{TileMap, Column, MAP_WIDTH};
#
# trait Index<Idx> {
# fn index(&self, idx: Idx) -> Column;
# }
#
// 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 }
}
}
# }
# mod index2 {
# use super::{Column, Tile, MAP_WIDTH};
# use std::ops::Index;
#
impl<'a> Index<usize> for Column<'a> {
# type Output = Tile;
fn index(&self, y: usize) -> &Tile {
&self.tilemap.storage[y * MAP_WIDTH + self.x]
}
}
# }
#
# fn main() {}
```
Here is a working approach using `RefCast`.
```
# use ref_cast::RefCast;
# use std::ops::Index;
#
# const MAP_WIDTH: usize = 4;
#
# struct Tile(u8);
#
# struct TileMap {
# storage: Vec<Tile>,
# }
#
#[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]
}
}
``` |
5141 |
trivial.rs |
|
323 |