什么时候可以将会员价值从固定的未来中转移出来? [英] When is it safe to move a member value out of a pinned future?

查看:63
本文介绍了什么时候可以将会员价值从固定的未来中转移出来?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个将来的组合器,该组合器需要使用它提供的值.对于期货0.1, Future::poll 取了self: &mut Self,这实际上意味着我的组合器包含一个Option,并且在潜在的未来结算时我在其上调用了Option::take.

I'm writing a future combinator that needs to consume a value that it was provided with. With futures 0.1, Future::poll took self: &mut Self, which effectively meant that my combinator contained an Option and I called Option::take on it when the underlying future resolves.

Future::poll 标准库中的方法取而代之的是self: Pin<&mut Self>,因此我一直在阅读有关安全使用Pin所需的保证的信息.

The Future::poll method in the standard library takes self: Pin<&mut Self> instead, so I've been reading about the guarantees required in order to safely make use of Pin.

Drop保证(强调我的意思):

From the pin module documentation on the Drop guarantee (emphasis mine):

具体而言,对于固定的数据,您必须保持不变,即从固定到调用drop为止,其内存不会失效.可以通过释放来使内存无效,也可以通过None 替换Some(v)或调用Vec::set_len从向量中杀死"某些元素来使内存无效.

Concretely, for pinned data you have to maintain the invariant that its memory will not get invalidated from the moment it gets pinned until when drop is called. Memory can be invalidated by deallocation, but also by replacing a Some(v) by None, or calling Vec::set_len to "kill" some elements off of a vector.

投影和结构固定(重点是我的):

在固定类型时,您不得提供任何其他可能导致数据从字段中移出的操作.例如,如果包装器包含Option<T>,并且存在类型为fn(Pin<&mut Wrapper<T>>) -> Option<T>仿冒操作,则可以使用该操作将T从固定的Wrapper<T>中移出-这意味着固定不可能是结构性的.

You must not offer any other operations that could lead to data being moved out of the fields when your type is pinned. For example, if the wrapper contains an Option<T> and there is a take-like operation with type fn(Pin<&mut Wrapper<T>>) -> Option<T>, that operation can be used to move a T out of a pinned Wrapper<T> -- which means pinning cannot be structural.

但是,现有的

f方法由 unsafe_unpinned 宏,其外观大致类似于:

The f method is generated by the unsafe_unpinned macro and looks roughly like:

fn f<'a>(self: Pin<&'a mut Self>) -> &'a mut Option<F> {
    unsafe { &mut Pin::get_unchecked_mut(self).f }
}

似乎 Map违反了pin文档中描述的要求,但是我相信Map组合器的作者知道他们在做什么,并且该代码是安全的.

It appears that Map violates the requirements that are described in the pin documentation, but I believe that the authors of the Map combinator know what they are doing and that this code is safe.

什么逻辑允许他们安全地执行此操作?

What logic allows them to perform this operation in a safe manner?

推荐答案

这全部与结构钉扎有关.

It is all about structural pinning.

首先,我将使用语法P<T>来表示类似impl Deref<Target = T>的东西-某些(智能)指针类型P,其将Deref::deref指向T. Pin仅对此类(智能)指针应用"/有意义.

First, I will use the syntax P<T> to mean something like impl Deref<Target = T> — some (smart) pointer type P that Deref::derefs to a T. Pin only "applies" to / makes sense on such (smart) pointers.

假设我们有:

struct Wrapper<Field> {
    field: Field,
}

最初的问题是

是否可以通过将Pin<P<_>>Wrapper投射到其field来从Pin<P<Wrapper<Field>>>中获得Pin<P<Field>>?

Can we get a Pin<P<Field>> from a Pin<P<Wrapper<Field>>>, by "projecting" our Pin<P<_>> from the Wrapper to its field?

这需要基本投影P<Wrapper<Field>> -> P<Field>,这仅适用于:

This requires the basic projection P<Wrapper<Field>> -> P<Field>, which is only possible for:

  • 共享引用(P<T> = &T).鉴于Pin<P<T>>始终 deref s到T.

唯一引用(P<T> = &mut T).

对于这种类型的投影,我将使用语法&[mut] T.

I will use the syntax &[mut] T for this type of projection.

问题现在变成:

我们可以从Pin<&[mut] Wrapper<Field>>转到Pin<&[mut] Field>吗?

从文档中可能不清楚的一点是,这取决于Wrapper的创建者!

The point that may be unclear from the documentation is that it is up to the creator of Wrapper to decide!

对于每个结构字段,库作者有两种可能的选择.

There are two possible choices for the library author for each struct field.

例如, pin_utils::unsafe_pinned! 宏用于定义此类投影(Pin<&mut Wrapper<Field>> -> Pin<&mut Field>).

要使Pin投影更声音:

  • 仅当具有结构化Pin投影的所有字段都实现Unpin时,整个结构才必须实现Unpin.

  • the whole struct must only implement Unpin when all the fields for which there is a structural Pin projection implement Unpin.

  • 不允许任何实现使用unsafe将此类字段移出Pin<&mut Wrapper<Field>>(或在Self = Wrapper<Field>时为Pin<&mut Self>).例如, Option::take()被禁止.
  • no implementation is allowed to use unsafe to move such fields out of a Pin<&mut Wrapper<Field>> (or Pin<&mut Self> when Self = Wrapper<Field>). For instance, Option::take() is forbidden.

仅当Drop::drop不移动任何具有结构投影的字段时,整个结构才可以实现Drop.

the whole struct may only implement Drop if Drop::drop does not move any of the fields for which there is a structural projection.

结构不能为#[repr(packed)](上一项的推论).

the struct cannot be #[repr(packed)] (a corollary of the previous item).

在给定的

In your given future::Map example, this is the case of the future field of the Map struct.

例如, pin_utils::unsafe_unpinned! 宏用于定义此类投影(Pin<&mut Wrapper<Field>> -> &mut Field).

在这种情况下,该字段不会被Pin<&mut Wrapper<Field>>固定.

In this case, that field is not considered pinned by a Pin<&mut Wrapper<Field>>.

  • Field是否为Unpin无关紧要.

    允许
  • 实现使用unsafe将此类字段移出Pin<&mut Wrapper<Field>>.例如,允许 Option::take() .
  • implementations are allowed to use unsafe to move such fields out of a Pin<&mut Wrapper<Field>>. For instance, Option::take() is allowed.

Drop::drop移动此类字段,

在给定的

In your given future::Map example, this is the case of the f field of the Map struct.

impl<Fut, F> Map<Fut, F> {
    unsafe_pinned!(future: Fut); // pin projection -----+
    unsafe_unpinned!(f: Option<F>); // not pinned --+   |
//                                                  |   |
//                 ...                              |   |
//                                                  |   |
    fn poll (mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
        //                                          |   |
        match self.as_mut().future().poll(cx) { // <----+ required here
            Poll::Pending => Poll::Pending, //      |
            Poll::Ready(output) => { //             |
                let f = self.f().take() // <--------+ allows this

这篇关于什么时候可以将会员价值从固定的未来中转移出来?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆