gpt4 book ai didi

rust - 实现 `std::marker::Unpin` 安全吗?

转载 作者:行者123 更新时间:2023-12-02 01:37:09 25 4
gpt4 key购买 nike

我即将将一些代码从 futures-0.1 转换为 futures-0.3,其中 poll() 方法现在需要固定数据。我的一些结构是不可固定的,这使移植变得复杂。但似乎存在一种简单的方法,即为这些类添加impl Unpin。这安全吗?有哪些替代方案?

示例代码:

extern crate futures;

use std::future::Future;
use std::pin::Pin;
use std::task::{ Poll, Context };

struct InnerData {
_pin: std::marker::PhantomPinned,
}

struct Stream {
}

struct Poller {
_data: InnerData,
file: Stream,
}

impl futures::stream::Stream for Stream {
type Item = ();

fn poll_next(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Option<Self::Item>> {
Poll::Pending
}
}

impl Future for Poller {
type Output = Result<(), ()>;

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>
{
use crate::futures::Stream;

// here, rust fails with
// error[E0277]: the trait bound `std::marker::PhantomPinned: std::marker::Unpin` is not satisfied in `Poller`
Pin::new(&mut self.get_mut().file).poll_next(cx).is_ready();

Poll::Pending
}
}

// Activating this seems to be an easy workaround...
// impl std::marker::Unpin for Poller {}

fn main() {
}

我使用futures-0.3.1rust-1.40.0

最佳答案

Is this safe?

是的,因为标记 PollerUnpin就其域而言不具有传递性。您仍然无法变出固定的_data凭空出现的领域。如果您尝试Pin::new(&mut self.get_mut()._data),则会出现编译器错误。自 new 仅适用于Pin<P>如果<P as Deref>::TargetUnpin :

impl<P> Pin<P> where
P: Deref,
<P as Deref>::Target: Unpin,
{
pub fn new(pointer: P) -> Pin<P>
}

rust Pin documentation有一个部分对此进行了扩展:

Pinning is not structural for field

What that type thinks about pinning is not relevant when no Pin<&mut Field> is ever created.

只有这样做才不安全impl std::marker::Unpin for InnerData {} ,这向编译器 promise 了一些不真实的东西。它不会阻止你写Pin::new(&mut self.get_mut()._data)不再有。

所以这有效:

impl Future for Poller {
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
use futures::stream::Stream as _;
Pin::new(&mut self.get_mut().file).poll_next(cx).is_ready();
Poll::Pending
}
}

impl std::marker::Unpin for Poller {}

What are the alternatives?

有第三方 crate ,例如 pin-project做这个Pin生意更容易一点:

use pin_project::pin_project;  // pin-project = "0.4.6"

#[pin_project]
struct Poller {
_data: InnerData,
#[pin]
file: Stream,
}

impl Future for Poller {
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
use futures::stream::Stream as _;
let this = self.project();
this.file.poll_next(cx).is_ready();
Poll::Pending
}
}

关于rust - 实现 `std::marker::Unpin` 安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59437421/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com