#cast #struct #conversion #transparent #field #single #safely

no-std ref-cast

安全地将 &T 强制转换为 &U,其中结构体 U 只包含一个类型为 T 的字段。

33 个版本 (稳定)

1.0.23 2024 年 5 月 7 日
1.0.22 2024 年 1 月 2 日
1.0.21 2023 年 12 月 13 日
1.0.20 2023 年 8 月 17 日
0.2.0 2017 年 10 月 28 日

Rust 模式 中排名 #30

Download history 167124/week @ 2024-05-02 181282/week @ 2024-05-09 179656/week @ 2024-05-16 208182/week @ 2024-05-23 215521/week @ 2024-05-30 200620/week @ 2024-06-06 193366/week @ 2024-06-13 209334/week @ 2024-06-20 197551/week @ 2024-06-27 183952/week @ 2024-07-04 201911/week @ 2024-07-11 212424/week @ 2024-07-18 211419/week @ 2024-07-25 181668/week @ 2024-08-01 193456/week @ 2024-08-08 185383/week @ 2024-08-15

每月下载量 814,055
用于 1,809 个crate(直接使用 78 个)

MIT/Apache

18KB
214 代码行

RefCast

github crates.io docs.rs build status

安全地将 &T 强制转换为 &U,其中结构体 U 只包含一个类型为 T 的字段。

[dependencies]
ref-cast = "1.0"

基本示例

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);
}

请注意,为了使转换正确,需要 #[repr(transparent)]。如果没有这个属性,derive 宏将拒绝编译。

实际示例

假设我们有一个多维数组,由于性能原因以行主序的形式存储在扁平缓冲区中,但我们想提供一个以列主序工作的索引操作,因为这在我们的应用程序上下文中更直观。

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]`.

Rust 中 Index 特性的签名要求输出必须是借用的类型。所以下面这样的方法是不行的。

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]
    }
}

以下是使用 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]
    }
}

许可

根据您的选择,受 Apache 许可证 2.0 版MIT 许可证 的许可。
除非您明确表示,否则您提交的任何贡献,根据 Apache-2.0 许可证定义,都应作为上述的双重许可,而无需任何额外的条款或条件。

依赖项

~250–690KB
~16K SLoC