Unable to use impl Sink<T>::start_send - rust

I wanted to implement the futures::Sink trait in my struct and kept getting yelled at by the compiler telling me to import and implement the trait. So I came up with this example which surprisingly (to me at least) still doesn't work:
use futures::Sink;
use std::pin::Pin;
use std::task::{Context, Poll};
struct Dummy;
impl Sink<tungstenite::Message> for Dummy {
type Error = tungstenite::Error;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn start_send(self: Pin<&mut Self>, item: tungstenite::Message) -> Result<(), Self::Error> {
todo!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
}
#[tokio::main]
async fn main() {
let mut dummy = Dummy;
dummy.start_send(tungstenite::Message::Text("".to_owned()));
}
I get:
error[E0599]: no method named `start_send` found for struct `Dummy` in the current scope
--> src/main.rs:29:11
|
5 | struct Dummy;
| ------------- method `start_send` not found for this
...
29 | dummy.start_send(tungstenite::Message::Text("".to_owned()));
| ^^^^^^^^^^ method not found in `Dummy`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `start_send`, perhaps you need to implement it:
candidate #1: `futures::Sink`
error: aborting due to previous error
I'm not making a generic struct, there are no bounds issues, no lifetimes. It's just a direct trait impl which the compiler refuses to recognize.
cargo tree | grep futures says all versions are v0.3.13, and here's the docs
I even tried Pin::new(&mut dummy).start_send because of the signature, but still nothing<. I have no idea what's going on here, or what kind of silly mistake did I make...
(By the way, I had a go at the similar impl Stream before this one and had no issues whatsoever)

I even tried Pin::new(&mut dummy).start_send because of the signature, but still nothing<. I have no idea what's going on here, or what kind of silly mistake did I make...
I also tried wrapping it in a Pin, since the start_send() takes in a Pin<&mut Self> as self, and this does seem to work for me.
use futures::sink::Sink;
use std::pin::Pin;
use std::task::{Context, Poll};
struct Message {}
struct Dummy;
impl Sink<Message> for Dummy {
type Error = ();
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn start_send(self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
todo!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
}
#[tokio::main]
async fn main() {
let mut dummy = Dummy;
let pin_dummy = Pin::new(&mut dummy);
pin_dummy.start_send(Message {});
}
Rust Playground

Related

Is there a way to add a cleanup routine to a Future?

Is there a way to add code to a Future/async fn in Rust such that it will always run when the execution of the Future is terminating, whether this is because the Future is being dropped or because it has finished normally?
I found this implemented by the future-utils crate called Finally but it relies on an older version of the Future trait before it was stabilized in the standard library. I was bamboozled thinking it was the futures-utils crate, which IS up to date, but doesn't have this functionality.
Regardless, here's an implementation that will call a function when a future is dropped:
[dependencies]
pin-project = "1.0.12"
//! on_drop.rs
use std::future::Future;
use std::mem::ManuallyDrop;
use std::pin::Pin;
use std::task::{Poll, Context};
use pin_project::{pin_project, pinned_drop};
#[pin_project(PinnedDrop)]
pub struct OnDrop<Fut, F> where F: FnOnce() {
#[pin]
future: Fut,
drop_fn: ManuallyDrop<F>,
}
impl <Fut, F> OnDrop<Fut, F>
where F: FnOnce()
{
pub fn new(future: Fut, drop_fn: F) -> Self {
Self {
future,
drop_fn: ManuallyDrop::new(drop_fn),
}
}
}
impl<Fut, F> Future for OnDrop<Fut, F>
where
F: FnOnce(),
Fut: Future,
{
type Output = Fut::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
this.future.poll(cx)
}
}
#[pinned_drop]
impl<Fut, F> PinnedDrop for OnDrop<Fut, F>
where F: FnOnce()
{
fn drop(self: Pin<&mut Self>) {
let mut this = self.project();
// SAFETY: we always construct `drop_fn` with a value and this is the
// only place we take the value out of it, when the value is being
// dropped.
let drop_fn = unsafe { ManuallyDrop::take(&mut this.drop_fn) };
drop_fn();
}
}
pub trait FutureOnDropExt {
fn on_drop<F: FnOnce()>(self, drop_fn: F) -> OnDrop<Self, F>
where
Self: Sized;
}
impl<Fut> FutureOnDropExt for Fut where Fut: Future {
fn on_drop<F: FnOnce()>(self, drop_fn: F) -> OnDrop<Self, F>
where
Self: Sized
{
OnDrop::new(self, drop_fn)
}
}
And can be used like:
//! main.rs
mod on_drop;
use on_drop::FutureOnDropExt;
fn main() {
async { println!("this doesn't print since we don't poll") }
.on_drop(|| println!("this does print when dropped"));
}
this does print when dropped
I took a quick look to see if anyone had suggested this for the futures crate but didn't see anything relevant. If you have a genuine use-case for this, I'd suggest proposing such an adapter. Either it could be added in the future, or sparking the idea may find there is a flaw in the technique or a better solution to achieve your goals.

How can I wrap a dynamically typed stream for API convenience?

I'm looking to implement a wrapper struct for any stream that returns a certain type, to cut down on the dynamic keywords littering my application. I've come across BoxStream, but have no idea how to make use of it in Stream::poll_next. Here's what I have so far:
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::prelude::stream::BoxStream;
use futures::Stream;
pub struct Row;
pub struct RowCollection<'a> {
stream: BoxStream<'a, Row>,
}
impl RowCollection<'_> {
pub fn new<'a>(stream: BoxStream<Row>) -> RowCollection {
RowCollection { stream }
}
}
impl Stream for RowCollection<'_> {
type Item = Row;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
// I have no idea what to put here, but it needs to get the information from self.stream and return appropriate value
}
}
Dependencies:
futures = "0.3"
Since Box implements Unpin, then BoxStream implements Unpin, and so will RowCollection.
Because of this, you can make use of Pin::get_mut which will give you a &mut RowCollection. From that, you can get a &mut BoxStream. You can re-pin that via Pin::new and then call poll_next on it. This is called pin-projection.
impl Stream for RowCollection<'_> {
type Item = Row;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Pin::new(&mut self.get_mut().stream).poll_next(cx)
}
}
See also:
No method named `poll` found for a type that implements `Future`

How do I pin project an element of a vector?

Following code does not compile because the element pulled from the vector does not implement the Pin<> type.
The error is in ele.poll() call
#[pin_project]
pub struct FifoCompletions<T, F>
where
F: Future<Output = Result<T, Error>>
{
#[pin]
pending: VecDeque<F>,
}
impl <T, F> FifoCompletions<T, F>
where
F: Future<Output = Result<T, Error>>
{
pub fn push(&mut self, f: F) {
self.pending.push_back(f);
}
}
impl <T, F> Future for FifoCompletions<T, F>
where
F: Future<Output = Result<T, Error>>
{
type Output = Result<T, Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
while !this.pending.is_empty() {
match this.pending.front_mut() {
None => unreachable!(),
Some(ele) => {
let output = ready!(ele.poll(cx));
}
}
}
Poll::Pending
}
}
Error message is
no method named `poll` found for mutable reference `&mut F` in the current scope
method not found in `&mut F`
help: items from traits can only be used if the type parameter is bounded by the traitrustc(E0599)
sm.rs(66, 45): method not found in `&mut F`
Here's the literal answer to your question:
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
pub struct Completions<F>
where
F: Future<Output = ()>,
{
pending: Vec<F>,
}
impl<F> Future for Completions<F>
where
F: Future<Output = ()>,
{
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// I copied this from Stack Overflow without reading the prose
// that describes why this is or is not safe.
// ... It's probably not safe.
let first = unsafe { self.map_unchecked_mut(|this| &mut this.pending[0]) };
first.poll(cx)
}
}
However, this is very likely to be unsafe and introduce undefined behavior. The problem is that the requirements for pinning are complex and nuanced. Specifically, once pinned, a value may never be moved in memory, including when it is dropped. From the docs, emphasis mine:
This can be tricky, as witnessed by VecDeque<T>: the destructor of VecDeque<T> can fail to call drop on all elements if one of the destructors panics. This violates the Drop guarantee, because it can lead to elements being deallocated without their destructor being called. (VecDeque<T> has no pinning projections, so this does not cause unsoundness.)
I checked with taiki-e, the author of the pin-project crate. A lightly-edited quote:
Operations such as Vec(Deque)'s push, insert, remove, etc. can move elements. If you want to pin elements, these methods should not be called without Unpin after they have been pinned. The pin API actually blocks this.
If the destructor moves elements, it is unsound to pin the element returned by accessors like get_mut, front_mut without Unpin.
Make the element Unpin or use a collection that can handle !Unpin futures like FutureUnordered instead of VecDeque.
Applied directly, the safest way to do this is:
use pin_project::pin_project; // 1.0
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
#[pin_project]
pub struct Completions<F>
where
F: Unpin,
F: Future<Output = ()>,
{
#[pin]
pending: Vec<F>,
}
impl<F> Future for Completions<F>
where
F: Unpin,
F: Future<Output = ()>,
{
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let pending = this.pending.get_mut();
let first = Pin::new(&mut pending[0]);
first.poll(cx)
}
}
See also:
No method named `poll` found for a type that implements `Future`
When is it safe to move a member value out of a pinned future?

how to pin RefCell contents?

I have a struct MyAsyncStream and tokio::io::AsyncWrite implementation for it:
impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for MyAsyncStream<S> {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize>> {
....
}
I also have MyAsyncStreamWrapper:
struct MyAsyncStreamWrapper{inner: MyAsyncStream}
Now I want to implement AnotherTrait trait for MyAsyncStreamWrapper, with the following method:
impl AnotherTrait for MyAsyncStreamWrapper {
fn poll_send_to<B>(self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
Pin::new(&mut self.inner).poll_write(cx, buf)
}
....
}
In this method implementation, I want to call poll_write on the inner. But, unfortunately they are different on self mutability: Pin<&mut Self> vs Pin<&Self>. As expected it does not compile.
Is there an idiomatic "workaround" for such case? My idea is to wrap inner into Mutex so I could have mutable MyAsyncStream in the non-mutable context:
MyAsyncStreamWrapper{inner: Mutex<RefCell<MyAsyncStream>>}
...
fn poll_send_to<B>(mut self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
let rc = self.stream.lock().unwrap();
let ref mut inner = rc.borrow();
let pin = Pin::new(inner);
pin.poll_write(cx, buf);
}
...
But, unfortunately, it also does not compile, with the following error:
pin.poll_write(cx, buf);
^^^^^^^^^^ method not found in `std::pin::Pin<&mut std::cell::RefMut<'_, MyAsyncStream>>`
What is the right way to go?
Dereference then re-borrow seems to work:
use std::cell::RefCell;
use std::pin::Pin;
use std::sync::Mutex;
fn main() {
let a = Mutex::new(RefCell::new(42));
let rc = a.lock().unwrap();
let mut inner = rc.borrow_mut();
let pinned = Pin::new(&mut *inner);
print_type_name(pinned);
}
fn print_type_name<T>(_: T) {
println!("{}", std::any::type_name::<T>());
}
It outputs that the type is core::pin::Pin<&mut i32>.
That being said, using blocking synchronization primitives like Mutex in asynchronous context is probably not a good idea. If possible it is better to let poll_send_to take a Pin<&mut Self> parameter.

How do I use Pin with Tokio's Sink?

I would like to create a method sending some data on a struct which implements Tokio's Sink, but I'm having problems working with Pin as self. In essence, I need something like this:
fn send_data(&mut self, data: Item, cx: &mut Context) -> Poll<Result<(), Error>> {
futures_core::ready!(something.poll_ready(cx))?;
something.start_send(data)?;
futures_core::ready!(something.poll_close(cx))
}
The problem is that each call to poll_ready(), start_send() and poll_close() takes self: Pin<&mut Self> and I don't know what something in my use case should be. If I try to use let something = Pin::new(self); then something gets moved after the call to poll_ready() and I cannot use it for subsequent calls (self is also gone at this point). How do I work around this problem?
use futures_core;
use std::pin::Pin;
use tokio::prelude::*; // 0.3.0-alpha.1
struct Test {}
impl Sink<i32> for Test {
type Error = ();
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn start_send(self: Pin<&mut Self>, item: i32) -> Result<(), Self::Error> {
Ok(())
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
}
impl Test {
fn send_data(&mut self, data: i32, cx: &mut Context) -> Poll<Result<(), Error>> {
// what should "something" here be?
futures_core::ready!(something.poll_ready(cx))?;
something.start_send(data)?;
futures_core::ready!(something.poll_close(cx))
}
}
I am very new to Rust myself (just started this week), but I solved a very similar problem earlier today by doing the following:
Create a pinned version of something: let mut something_pinned = Box::pin(something);
Call .as_mut() before each call to poll_ready, start_send, and poll_close.
So in your send_data, it should look something like:
futures_core::ready!(something_pinned.as_mut().poll_ready(cx))?;
something_pinned.as_mut().start_send(data)?;
futures_core::ready!(something_pinned.as_mut().poll_close(cx))
Also, I think you're generally supposed to store "memory" of which of your sub-poll steps have already been completed, eg. so that when your function gets re-called, it doesn't call start_send additional times after having already seen it succeed/become-ready. (though maybe it doesn't cause any actual problems to call it redundantly in this case)

Resources