#生命周期 #引用 #所有权

no-std cryo

安全地扩展引用的生命周期。

16 个版本

0.3.1 2021 年 10 月 26 日
0.2.7 2021 年 10 月 25 日
0.2.2 2021 年 5 月 8 日
0.1.6 2020 年 1 月 8 日
0.1.2 2018 年 11 月 13 日

#1060 in Rust 模式

Download history 4/week @ 2024-03-07 2/week @ 2024-03-14 14/week @ 2024-03-28 17/week @ 2024-04-04

每月 414 次下载
interlock 中使用

MIT/Apache

49KB
691

Cryo — Extend the lifetime of a reference. Safely.

docs.rs

需要 Rust 1.34.0 或更高版本。

此软件包提供了一个类似于 RefCell 的单元格类型 Cryo,但它通过运行时检查机制约束其借用值的生命周期,擦除了编译时生命周期信息。从 Cryo 创建的锁保护器 CryoRef'static,因此可以用于需要 'static 类型的各种情况,包括

  • CryoRef 暂时存储在兼容 std::any::Any 的容器中。
  • 捕获一个引用以创建一个 Objective-C 块

这是通过,当 Cryo 被丢弃时,不允许当前线程的执行继续(至少¹)直到所有指向即将过期的 Cryo 的引用都被丢弃,这样它们就不会比 Cryo 活得更久。这是通过底层的 读写锁 实现的。

¹ SyncLock 在锁定失败时阻止当前线程的执行。另一方面,LocalLock 由于它是为单线程用例设计的,因此会引发恐慌,否则会导致死锁。

示例

with_cryoCryoLocalLock (单线程锁实现,默认使用)

use std::{thread::spawn, pin::Pin};

let cell: usize = 42;

// `with_cryo` uses `LocalLock` by default
with_cryo(&cell, |cryo: Pin<&Cryo<'_, usize, _>>| {
    // Borrow `cryo` and move it into a `'static` closure.
    let borrow: CryoRef<usize, _> = cryo.borrow();
    let closure: Box<dyn Fn()> =
        Box::new(move || { assert_eq!(*borrow, 42); });
    closure();
    drop(closure);

    // Compile-time lifetime works as well.
    assert_eq!(*cryo.get(), 42);

    // When `cryo` is dropped, it will block until there are no other
    // references to `cryo`. In this case, the program will leave
    // this block immediately because `CryoRef` has already been dropped.
});

with_cryoCryoSyncLock (线程安全锁实现)

use std::{thread::spawn, pin::Pin};

let cell: usize = 42;

// This time we are specifying the lock implementation
with_cryo((&cell, lock_ty::<SyncLock>()), |cryo| {
    // Borrow `cryo` and move it into a `'static` closure.
    // `CryoRef` can be sent to another thread because
    // `SyncLock` is thread-safe.
    let borrow: CryoRef<usize, _> = cryo.borrow();
    spawn(move || { assert_eq!(*borrow, 42); });

    // Compile-time lifetime works as well.
    assert_eq!(*cryo.get(), 42);

    // When `cryo` is dropped, it will block until there are no other
    // references to `cryo`. In this case, the program will not leave
    // this block until the thread we just spawned completes execution.
});

with_cryoCryoMutSyncLock

with_cryo((&mut cell, lock_ty::<SyncLock>()), |cryo_mut| {
    // Borrow `cryo_mut` and move it into a `'static` closure.
    let mut borrow: CryoMutWriteGuard<usize, _> = cryo_mut.write();
    spawn(move || { *borrow = 1; });

    // When `cryo_mut` is dropped, it will block until there are no other
    // references to `cryo_mut`. In this case, the program will not leave
    // this block until the thread we just spawned completes execution
});
assert_eq!(cell, 1);

不要做这些

// The following statement will DEADLOCK because it attempts to drop
// `Cryo` while a `CryoRef` is still referencing it, and `Cryo`'s
// destructor will wait for the `CryoRef` to be dropped first (which
// will never happen)
let borrow = with_cryo((&cell, lock_ty::<SyncLock>()), |cryo| cryo.borrow());
// The following statement will ABORT because it attempts to drop
// `Cryo` while a `CryoRef` is still referencing it, and `Cryo`'s
// destructor will panic, knowing no amount of waiting would cause
// the `CryoRef` to be dropped
let borrow = with_cryo(&cell, |cryo| cryo.borrow());

注意事项

  • 虽然它可以延长引用的有效寿命,但不适用于嵌套引用。例如,当 &'a NonStaticType<'b> 传递给 Cryo 的构造函数时,借用类型是 CryoRef<NonStaticType<'b>>,它仍然部分绑定到原始的生命周期。

详细信息

功能标志

  • std(默认启用)启用 SyncLock

  • lock_api 启用对所有实现 lock_api::RawRwLock 的类型的 Lock 的泛型实现,例如 spin::RawRwLockparking_lot::RawRwLock

  • atomic(默认启用)启用需要完全原子操作的功能,这些操作不支持某些目标(检测此类目标仍不稳定(#32976))。此功能将在 #32976 稳定后弃用。

开销

Cryo<T, SyncLock> 的创建、销毁、借用和取消借用在最佳情况下各需要一或两个原子操作。

SyncLockLocalLock 都不需要动态内存分配。

命名法

来自 cryopreservation

许可:MIT/Apache-2.0

依赖项

~55KB