#固定 # #声明 # #暴露 #实例 #stack-pinned

bin+lib stackpin

用于在声明时将数据固定到栈上的数据包

2 个版本

0.0.2 2019年10月12日
0.0.1 2019年10月12日

Rust 模式 中排名第 1925

每月下载量 23
用于 2 crates

MIT/Apache

34KB
450

stackpin

此数据包公开了一个 StackPinned 类型,允许在声明时将 !Unpin 数据固定到栈上。

为此,此数据包提供了一个 FromUnpinned 特性和一个 stack_let! 宏,使创建 PinStack 对象(简称为 PinStack)更加安全。

在声明时获取固定实例就像这样简单

stack_let!(unmovable = Unmovable::new_unpinned("Intel the Beagle")); // this creates the unmovable instance on the stack and binds `unmovable` with a `PinStack<Unmovable>`

对于 Unmovable 结构体实现 FromUnpinned<String> 特性。

有关详细信息,请参阅 数据包文档,或直接查看 示例


lib.rs:

stackpin 数据包公开了一个 StackPinned 类型,允许在声明时将 !Unpin 数据固定到栈上。数据包公开了一个特性,FromUnpinned,以及一个宏 stack_let,使创建 StackPinned 实例更加容易。数据包还公开了 PinStack 类型别名,用于 Pin<StackPinned<T>>

这个crate受到了pin-utils crate的启发,主要区别在于

  • pin-utils 提供了一个宏,用于返回一个 Pin<&mut T> 实例,具有包括重新借用在内的“可变引用”语义。而 stackpin crate推广了“根句柄”语义,保证一个消耗 PinStack<T> 的函数只消耗 唯一T 句柄,而不是一个重新借用的引用。
  • stack_let!(mut id : ty = expr) 宏的语法试图模仿一个普通的 let mut id : ty = expr 语句。
  • 提供的 FromUnpinned 特性和 Unpinned 结构体旨在将不可移动的类型与可以用来构建它们的 数据分开。 stackpin 旨在推广一个模型,其中所有不可移动的类型只能通过加锁一次来访问。
  • StackPinned<T> 类型表达了对 T 的析构函数将被运行的强烈保证。
  • stackpin crate 专注于堆栈锁定。 pin-utils crate 还提供了其他工具,如锁定投影。

可堆栈锁定类型

想要从 StackPinned 提供的保证中受益的类型 T 应该是 !Unpin。这是强制执行“将运行释放”保证所必需的。

此外,stackpin crate 推广了一种习惯用法,即“不可移动”类型与可移动类型严格分离,并且最好只能通过 PinStack 来访问。

例如,让我们考虑以下 Unmovable 结构体(来自 pin 模块的文档)

use std::marker::PhantomPinned;
use std::ptr::NonNull;
struct Unmovable {
    // Owned data
    s: String,
    // Self referential pointer meant to point to `s`
    slice: NonNull<String>,
    // Obligatory marker that makes this struct `!Unpin`.
    // Without this, implementing `FromUnpinned` for `Unmovable` would not be safe.
    _pinned: PhantomPinned,
}

重要的是要注意,这个结构体本身并不是不可移动的,因为在 Rust 中没有这样的类型。相反,我们将通过隐私来强制执行这一点:由于该结构体的字段是私有的,因此不能在模块外部创建其实例。同样,不应提供任何公共的“构造函数”函数 pub fn new() -> Unmovable 。

那么,客户端应该如何消费 Unmovable 实例呢?

使用 stackpin 的推荐解决方案是为 Unmovable 实现 FromUnpinned<Data>,其中 Data 是通常用作“构造函数”函数参数的类型。

use stackpin::FromUnpinned;
// An `Unmovable` can be created from a `String`
unsafe impl FromUnpinned<String> for Unmovable {
    // This associated type can be used to retain information between the creation of the instance and its pinning.
    // This allows for some sort of "two-steps initialization" without having to store the initialization part in the
    // type itself.
    // Here, we don't need it, so we just set it to `()`.
    type PinData = ();

    // Simply builds the Unmovable from the String.
    // The implementation of this function is not allowed to consider that the type won't ever move **yet**.
    // (in particular, the `Self` instance is returned by this function)
    // Note, however, that safe users of FromUnpinned will:
    // * Not do anything to with the returned `Self` instance between the call to
    //   `from_unpinned` and the call to `on_pin`.
    // * Not panic between calling the two functions
    // * Always call the second function if the first has been called.
    unsafe fn from_unpinned(s: String) -> (Self, ()) {
        (
            Self {
                s,
                // We will "fix" this dangling pointer once the data will be pinned
                // and guaranteed not to move anymore.
                slice: NonNull::dangling(),
                _pinned: PhantomPinned,
            },
            (),
        )
    }

    // Performs a second initialization step on an instance that is already guaranteed to never move again.
    // This allows to e.g. set self borrow with the guarantee that they will remain valid.
    unsafe fn on_pin(&mut self, _data: ()) {
        // Data will never move again, set the pointer to our own internal String whose address
        // will never change anymore
        self.slice = NonNull::from(&self.s);
    }
}

实现了 FromUnpinned<Data>T 的支持后,现在可以添加一个返回 Unpinned<Data, T> 的 "构造函数"。Unpinned<U, T> 结构体是围绕 U 的简单辅助结构体,它维护目标类型 T。这被 stack_let 宏用于推断用户可能想要产生的 T 类型。

impl Unmovable {
    fn new_unpinned<T: Into<String>>(s: T) -> Unpinned<String, Unmovable> {
       Unpinned::new(s.into())
    }
}

然后,Unmovable 结构体的用户可以通过使用 stack_let 宏简单地构建一个实例。

use stackpin::stack_let;
// ...
stack_let!(unmovable = Unmovable::new_unpinned("Intel the Beagle")); // this creates the unmovable instance on the stack and binds `unmovable` with a `PinStack<Unmovable>`
// ...

无运行时依赖