私は誰かが.shutdown()
を呼び出すことを可能にする構造体を作成しようとしています。これは、未来を解決します(そうでなければ保留中です)。一度しか呼び出せません。 Future
トレイトの実装では、poll
が定義されていないというエラーが表示されますが、 ドキュメント (impl Future
の下)に存在します)。
impl
としてstd::future::Future
を使用していますが、プレビュートレイトをスコープに含めるuse futures::prelude::*
を追加しようとしました。 RLSとrustcの両方から、インポートが使用されていないことが通知されるので、それは問題ではありません。
私はnotを使用していることに注意してください。これは、任意のスレッドから呼び出せるようにするために、単純なブールフラグを使用しています。これは、ここでは重要ではない実装の詳細です。
use futures::channel::oneshot; // [email protected]
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
pub struct ShutdownHandle {
sender: oneshot::Sender<()>,
receiver: oneshot::Receiver<()>,
}
impl ShutdownHandle {
pub fn new() -> Self {
let (sender, receiver) = oneshot::channel();
Self { sender, receiver }
}
pub fn shutdown(self) -> Result<(), ()> {
self.sender.send(())
}
}
impl Future for ShutdownHandle {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.receiver.poll(&mut cx).map(|_| ())
}
}
fn main() {
let runner = ShutdownHandle::new();
assert!(runner.shutdown().is_ok());
}
次のエラーが表示されます。
error[E0599]: no method named `poll` found for type `futures_channel::oneshot::Receiver<()>` in the current scope
--> src/main.rs:28:23
|
28 | self.receiver.poll(&mut cx).map(|_| ())
| ^^^^
何が欠けていますか?確かに、ポーリングを「パススルー」する方法はいくつかあります。毎晩使用しています(2019-07-18)。
確かに、Receiver
はFuture
を実装していません。のみPin<&mut Receiver>
します。タイプからフィールドへの固定をprojectする必要があります。
Unpin
を実装しない場合impl Future for ShutdownHandle {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
// I copied this code from Stack Overflow without reading the text that
// told me how to verify that this code uses `unsafe` correctly.
unsafe { self.map_unchecked_mut(|s| &mut s.receiver) }.poll(cx).map(|_| ())
}
}
ここでpin
を使用するための要件を完全に理解するには、 unsafe
module を読む必要があります。
pin_project などのヘルパーライブラリを使用して、より複雑なタイプのプロジェクションを処理します。
#[unsafe_project(Unpin)]
pub struct ShutdownHandle {
#[pin]
sender: oneshot::Sender<()>,
#[pin]
receiver: oneshot::Receiver<()>,
}
impl Future for ShutdownHandle {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.project();
this.receiver.poll(cx).map(|_| ())
}
}
Unpin
を実装する場合ÖmerErdenが指摘 先物プレビュークレートが提供するもの FutureExt::poll_unpin
。このメソッドは Unpin
を実装する型への変更可能な参照を受け取り、それを使用して新しいPin
を作成します。
oneshot::Receiver
はUnpin
を実装しています。これはここで使用できます:
impl Future for ShutdownHandle {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.receiver.poll_unpin(cx).map(|_| ())
}
}