blob: afb6e27e7fc1f487f7576f2d9ff2aa2bd8df702c [file] [log] [blame] [edit]
//! [![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&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//! <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 either of `#[repr(C)]` or `#[repr(transparent)]` is required in
//! order for the conversion to be sound. The derive macro will refuse to
//! compile if neither is 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`]: https://doc.rust-lang.org/std/ops/trait.Index.html
//!
//! ```
//! # 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]
//! }
//! }
//! ```
#![doc(html_root_url = "https://docs.rs/ref-cast/1.0.6")]
#![no_std]
mod layout;
mod trivial;
pub use ref_cast_impl::RefCast;
/// Safely cast `&T` to `&U` where the struct `U` contains a single field of
/// type `T`.
///
/// ```
/// # use ref_cast::RefCast;
/// #
/// // `&String` can be cast to `&U`.
/// #[derive(RefCast)]
/// #[repr(transparent)]
/// struct U(String);
///
/// // `&T` can be cast to `&V<T>`.
/// #[derive(RefCast)]
/// #[repr(transparent)]
/// struct V<T> {
/// t: T,
/// }
/// ```
///
/// See the crate-level documentation for usage examples!
pub trait RefCast {
type From: ?Sized;
fn ref_cast(from: &Self::From) -> &Self;
fn ref_cast_mut(from: &mut Self::From) -> &mut Self;
}
// Not public API.
#[doc(hidden)]
pub mod private {
pub use crate::layout::{assert_layout, Layout, LayoutUnsized};
pub use crate::trivial::assert_trivial;
}