Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created July 1, 2020 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rust-play/87ab93979d770314e6698a9867d1e7e5 to your computer and use it in GitHub Desktop.
Save rust-play/87ab93979d770314e6698a9867d1e7e5 to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
// This is the solution for writing ergonomic async callbacks that borrow their arguments.
// It is a response to https://gist.github.com/rust-play/b89d17f00f58f071555339093d76a0a3.
// Again, thanks go to Alice on https://users.rust-lang.org/t/hrtb-on-multiple-generics/34255 for showing the way.
// That thread was pointed out by @technic93 on https://gitter.im/gotham-rs/gotham?at=5ef9c6f4405be935cdcc4b7b
// and paved the way for implementing router.to_async_borrowing(fn), which is still in progress.
use std::boxed::Box;
use std::future::Future;
use std::pin::Pin;
#[derive(Debug)]
struct MyStruct {
a: usize,
b: usize,
c: String,
// ...
}
trait AsyncCallback<'a> {
type Output: std::future::Future<Output=()> + 'a;
fn call(self, arg: &'a mut MyStruct) -> Self::Output;
}
impl<'a, Fut: 'a, F> AsyncCallback<'a> for F
where
F: FnOnce(&'a mut MyStruct) -> Fut,
Fut: std::future::Future<Output=()>,
{
type Output = Fut;
fn call(self, arg: &'a mut MyStruct) -> Fut {
self(arg)
}
}
struct StructWithCallback {
callback: Box<dyn for<'r> FnMut(&'r mut MyStruct) -> Pin<Box<dyn Future<Output = ()> + 'r>>>,
}
impl StructWithCallback {
fn from_unboxed<F>(cb: F) -> Self
where
for<'a> F: AsyncCallback<'a> + Clone + 'static,
{
Self {
callback: Box::new(move |s| Box::pin(cb.clone().call(s))),
}
}
}
async fn my_function<'r>(my_struct: &'r mut MyStruct) {
println!("in my_function: {:?}", my_struct);
// Change stuff.
my_struct.a += 1;
my_struct.b += 2;
my_struct.c = "a different string".to_string();
}
async fn example() {
let struct_with_callback = StructWithCallback::from_unboxed(my_function);
let mut my_struct = MyStruct {
a: 1,
b: 2,
c: "a string".to_string(),
};
// Invoke the stored callback.
let mut callback = struct_with_callback.callback;
callback(&mut my_struct).await;
// Confirm stuff changed.
println!("after my_function: {:?}", my_struct);
}
fn main() {
let mut rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(example());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment