From eb99d4ac892f489103e22eafbbf78c38b2615606 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sat, 18 Jul 2020 00:55:26 -0400 Subject: [PATCH] More notes on implementing `Future` --- _posts/2020-07-08-on-implementing-futures.md | 88 +++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/_posts/2020-07-08-on-implementing-futures.md b/_posts/2020-07-08-on-implementing-futures.md index 164fa01..0cd8175 100644 --- a/_posts/2020-07-08-on-implementing-futures.md +++ b/_posts/2020-07-08-on-implementing-futures.md @@ -133,6 +133,56 @@ error[E0277]: the trait bound `&R3: futures_io::if_std::AsyncBufRead` is not sat I need to reduce this example though. +NOTE: Should also add something about how `AsyncBufRead` isn't implemented for `&R3`, but _is_ after +deref. The errors become a lot more obvious if you try to deref `self.reader`: + +```rust +use futures_io::AsyncBufRead; +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +fn poll_once(mut reader: Pin<&mut R1>, cx: &mut Context<'_>) -> Poll<()> { + reader.as_mut().poll_fill_buf(cx); + return Poll::Ready(()); +} + +struct MyStruct<'a, R2: ?Sized> { + reader: &'a R2, +} + +impl Future for MyStruct<'_, R3> { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + poll_once(Pin::new(&mut *self.reader), cx) + } +} +``` + +```text +error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<&mut MyStruct<'_, R3>>` as mutable + --> src/lib.rs:19:28 + | +12 | reader: &'a R2, + | ------ help: consider changing this to be mutable: `&'a mut R2` +... +19 | poll_once(Pin::new(&mut *self.reader), cx) + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable + --> src/lib.rs:19:34 + | +18 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + | ---- help: consider changing this to be mutable: `mut self` +19 | poll_once(Pin::new(&mut *self.reader), cx) + | ^^^^ cannot borrow as mutable +``` + +Now, we can see that `self` can't be borrowed as mutable (it needs to be marked +`mut self: Pin<&mut Self>`) and that the reader can't be borrowed as mutable (the struct definition +needs `&'a mut R2`). + # Don't feel bad about requiring `Unpin` Principle: don't require it unless you need to, but don't hesitate to add it if the compiler thinks @@ -181,8 +231,44 @@ help: consider further restricting this bound | ^^^^^^^^^^^^^^^^^^^^ ``` -# Don't feel bad about fallbacks +# Know what the escape hatches are When used sparingly, either `#[async_trait]` or `Box::pin(async move {})` can enable async functionality in code that will later not need the allocations. Use the escape hatch when you need to such that you can continue making incremental improvements later. + +Specific trick: use `BoxFuture` for opaque type erasure: + +```rust +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; +use futures::future::BoxFuture; + +async fn my_function() {} + +struct MyStruct> { + f: F +} + +fn another_function() -> MyStruct> { + MyStruct { f: Box::pin(async { my_function().await }) } +} +``` + +NOTE: Should also add something about owned data structures need to implemented `Unpin`: + +```rust + +struct First { + value: T, +} + +// To get access to `T` through `self`, `T` must implement `Unpin` + +struct Second { + values: Vec +} + +// Same thing - `T` must implement `Unpin` to get access to `values` +```