Repository: gtk-rs/gtk3-rs (Rust)

Issue:
clone! macro does not work with async blocks
The content of the async block is not retained by the clone! macro.

Minimal example:
This
```rust
button.connect_clicked(move |button| {
        let main_context = MainContext::default();
        // The main loop executes the asynchronous block
        main_context.spawn_local(glib::clone!(@strong button => async move {
            // Deactivate the button until the operation is done
            button.set_sensitive(false);
            timeout_future_seconds(10).await;
            // Activate the button again
            button.set_sensitive(true);
        }));
    });
```
expands to this
```rust
  button.connect_clicked(move |button| {
        let main_context = MainContext::default();
        main_context.spawn_local({
            let button = button.clone();
            async move { {} }
        });
    });
```


Discussion:
CC @GuillaumeGomez 
Oh, that's funny. Wonder how I'll test this one...
> Oh, that's funny. Wonder how I'll test this one...

What do you mean? :)

Reproducing or adding tests as soon as it is fixed?
We have tests to ensure that it's doing as expected. Meaning I didn't check if the async code was actually being run (which is bad).
How about a test dependency on [smol](https://lib.rs/crates/smol) and then run it there?
Don't worry, I'll find something. Finishing something else first.
glib depends on `futures-executor`, so just use [`futures::executor::block_on`](https://docs.rs/futures/0.3.13/futures/executor/fn.block_on.html)... or just use the GLib main context, which is also a futures executor ;)

Just like with closures, check if the whole thing then evaluates to the expected return value (and also do it for closures).
That's exactly what I was looking for, thanks!



Patch:
diff --git a/glib-macros/src/clone.rs b/glib-macros/src/clone.rs
index 9dfcbbef2c40..5418feef5a53 100644
--- a/glib-macros/src/clone.rs
+++ b/glib-macros/src/clone.rs
@@ -484,8 +484,9 @@ fn check_move_after_async(parts: &mut Peekable<ProcIter>) {
 
 fn check_async_syntax(parts: &mut Peekable<ProcIter>) -> BlockKind {
     check_move_after_async(parts);
-    match parts.next() {
+    match parts.peek() {
         Some(TokenTree::Punct(p)) if p.to_string() == "|" => {
+            parts.next();
             BlockKind::AsyncClosure(get_closure(parts))
         }
         Some(TokenTree::Punct(p)) => {
@@ -533,7 +534,7 @@ fn check_before_closure(parts: &mut Peekable<ProcIter>) -> BlockKind {
         Some(TokenTree::Ident(i)) if i.to_string() == "async" => {
             parts.next();
             check_move_after_async(parts);
-            match parts.next() {
+            match parts.peek() {
                 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
                     BlockKind::ClosureWrappingAsync(closure)
                 }


Test patch:
diff --git a/glib/tests/clone.rs b/glib/tests/clone.rs
index b79f4ae72a54..fb659593af14 100644
--- a/glib/tests/clone.rs
+++ b/glib/tests/clone.rs
@@ -4,6 +4,7 @@ use std::panic;
 use std::rc::Rc;
 use std::sync::{Arc, Mutex};
 
+use futures_executor::block_on;
 use glib::{clone, Downgrade, Object};
 
 struct State {
@@ -490,12 +491,15 @@ fn test_clone_macro_body() {
 
 #[test]
 fn test_clone_macro_async_kinds() {
-    let v = Rc::new(1);
+    let v = Rc::new(RefCell::new(1));
 
     // This one is still a rust unstable feature.
     // let _closure = clone!(@weak v => async move || 0);
-    let _closure = clone!(@weak v => move || async move { 0 });
-    let _closure = clone!(@weak v => async move { 0 });
+    let closure = clone!(@weak v => move || async move { *v.borrow_mut() += 1; });
+    block_on(closure());
+    assert_eq!(*v.borrow(), 2);
+    block_on(clone!(@weak v => async move { *v.borrow_mut() += 1; }));
+    assert_eq!(*v.borrow(), 3);
 }
 
 #[test]