Code shared from the Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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