我准备将一些代码从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.1
和rust-1.40.0
。
答案 0 :(得分:0)
这样安全吗?
是的,因为将Poller
标记为Unpin
就其字段而言不是可传递的。您仍然无法凭空想到一个固定的_data
字段。如果您尝试Pin::new(&mut self.get_mut()._data)
会导致编译器错误,因为new
仅在Pin<P>
为<P as Deref>::Target
时才可用于Unpin
:
impl<P> Pin<P> where
P: Deref,
<P as Deref>::Target: Unpin,
{
pub fn new(pointer: P) -> Pin<P>
}
Rust Pin
documentation的一个部分对此进行了扩展:
对于
field
,钉扎不是结构性的当从未创建过
Pin<&mut Field>
时,该类型对固定的想法就无关紧要。
只有执行impl std::marker::Unpin for InnerData {}
才是不安全的,这会向编译器承诺不正确的内容。它将无法阻止您再写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 {}
有哪些替代方案?
有些{@ {1}}这样的第三方板条箱可以使此pin-project
业务变得更轻松:
Pin