Skip to content

Instantly share code, notes, and snippets.

@tgockel
Created January 22, 2026 20:08
Show Gist options
  • Select an option

  • Save tgockel/b61b5edda9638abbf6c1a52eb26c8545 to your computer and use it in GitHub Desktop.

Select an option

Save tgockel/b61b5edda9638abbf6c1a52eb26c8545 to your computer and use it in GitHub Desktop.
Rust code to allow binding a member function that requires `&mut self` when you don't want to keep the temporary around.
//! This demonstrates how to transform an async member function that needs a `&mut self` into a
//! future that can just be `await`ed.
use std::{marker::PhantomData, pin::Pin, task::{Context, Poll}};
#[derive(Default)]
struct Foo(());
impl Foo {
pub async fn foo(&mut self) -> i32 {
1
}
}
fn bind_async_mut<'a, F, C, Fut, R>(
func: F,
context: C,
) -> BoundFn<C, F, Fut>
where
F: Fn(&'a mut C) -> Fut,
Fut: Future<Output = R>,
C: 'a,
{
BoundFn { context, func, _future_type: PhantomData }
}
struct BoundFn<C, F, Fut> {
context: C,
func: F,
_future_type: PhantomData<Fut>,
}
impl<'a, C, F, Fut> IntoFuture for BoundFn<C, F, Fut>
where
F: Fn(&'a mut C) -> Fut,
Fut: Future,
C: 'a,
{
type Output = Fut::Output;
type IntoFuture = BoundFnFuture<C, Fut>;
fn into_future(self) -> Self::IntoFuture {
let mut context = Box::pin(self.context);
let fut = unsafe {
let context_ptr = context.as_mut().get_unchecked_mut() as *mut C;
(self.func)(&mut *context_ptr)
};
BoundFnFuture { context, fut }
}
}
#[pin_project::pin_project]
struct BoundFnFuture<C, Fut> {
context: Pin<Box<C>>,
#[pin]
fut: Fut,
}
impl<C, Fut> Future for BoundFnFuture<C, Fut>
where
Fut: Future,
{
type Output = Fut::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.as_mut().project().fut.poll(cx)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment