ghost-cell:基于 Rust 的安全零成本借用检查范式项目

An implementation of Joshua Yanovski's Ghost Cell paper.

分支1Tags7
文件最后提交记录最后更新时间
4 年前
2 年前
5 年前
2 年前
5 年前
5 年前
4 年前
2 年前

GhostCell 论文中提出的一种新颖、安全且零成本的借用检查范式。

动机

许多数据结构(如链表、二叉树或 B 树)使用别名指针实现起来最为简便。

传统上,这意味着要使用运行时借用检查才能对这些结构进行修改,或者为了追求性能而使用 unsafe

GhostCell 通过标记(brands) 将数据与其修改权限分离,并使用唯一的 GhostToken 来表示这种权限。该标记通过标记(brand) 在编译时与多个 GhostCell 相关联。

安全性

在 GhostCell 论文中,德国 MPI-SWS 的 Joshua Yanovski 及其同事利用他们在 RustBelt 项目 中开发的分离逻辑,正式证明了 GhostCell 的安全性。我个人对此深信不疑。

官方实现可在 https://gitlab.mpi-sws.org/FP/ghostcell/-/tree/master/ghostcell 找到,其中还包含示例。目前我已了解到该实现,不久后将对其进行升级。

使用风险自负!

(如有任何问题,请务必报告)

成熟度

这顶多算是一个 Alpha 质量的版本。

文档:

  • 所有方法均有文档说明。
  • 所有非平凡方法均提供示例。

测试:

  • 所有非平凡方法均通过示例进行测试。
  • 所有具有安全不变量的方法均配有编译失败测试。
  • 包括示例在内的整个测试套件均在 Miri 下运行。

如何使用?

让我们从一个独立的示例开始:

use ghost_cell::{GhostToken, GhostCell};

fn demo(n: usize) {
    let value = GhostToken::new(|mut token| {
        let cell = GhostCell::new(42);

        let vec: Vec<_> = (0..n).map(|_| &cell).collect();

        *vec[n / 2].borrow_mut(&mut token) = 33;

        *cell.borrow(&token)
    });

    assert_eq!(value, 33);
}

GhostToken 采用目前已知的最佳方式生成唯一生命周期,因此可将其用作一种标记(brand),具体方法是将以下两者结合:

  • GhostToken::new 方法内部创建的局部变量。
  • 一个必须对所有生命周期都有效的闭包。

这意味着存在两项限制:

  • 闭包必须对生命周期具有协变性,这一点在闭包本身已包含引用时并不总能良好兼容。
  • 闭包不能返回任何带有标记的项。

接下来,在闭包内部,任何 GhostCell 都可以且仅能与一个 GhostToken 相关联,该标记将对其借用权限进行编码:

  • &GhostToken<'brand> 是使用 GhostCell<'brand, T>::borrow 的关键——注意此处匹配的 'brand——并允许获取 &T 引用。
  • &mut GhostToken<'brand> 是使用 GhostCell<'brand, T>::borrow_mut 的关键,并允许获取 &mut T 引用。

使用 borrowborrow_mut 会同时借用单元格和标记。

那又如何?

GhostCell 是一种安全且零成本的单元格。它支持通过编译时检查的借用规则实现别名。

StaticRc 结合使用,能够以安全、稳定的 Rust 编写双向链表、二叉树以及带有父指针的 B 树等数据结构。

其他单元格

目前还存在其他一些单元格,它们功能相似,但各有不同的取舍:

  • 标准库中的 CellRefCell
  • qcell crate 中的多种单元格,其中 LCell 是基于与 GhostCell 作者的讨论而设计的,两者理念相似。

就这样吧!

感谢您的阅读。

项目介绍

An implementation of Joshua Yanovski's Ghost Cell paper.

定制我的领域