Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SignalVecExt::flatten stops polling after first top-level item if the item is empty #81

Closed
martin-kolarik opened this issue Jan 19, 2024 · 4 comments

Comments

@martin-kolarik
Copy link

If the first polled item of flatten is empty SignalVec, inner polling of this SignalVec ends with Pending, and therefore top-level poll loop does not continue. If top-level SignalVec contains more items in this situation, they are not polled immediately and wait until next wake up.

@Pauan
Copy link
Owner

Pauan commented Jan 24, 2024

Thanks for the report, but I'm having a hard time reproducing it. Could you give an example which fails?

@martin-kolarik
Copy link
Author

martin-kolarik commented Jan 24, 2024

I apologize, I will provide code later, I am a bit short of time now.

It will be something like (not tested):

let a = MutableVec<MutableVec<u32>>::new();
a.lock_mut().push_cloned(MutableVec::new());
a.lock_mut().push_cloned(MutableVec::new_with_values(vec![15]));

let s = a.signal_vec_cloned().map(|v| v.signal_vec()).flatten();

The behavior in handling Flatten then is that the first (top-level) VecDiff::Push is loaded and stored into this.inner, but then polling stops (my continue solves it in the proposed fix), so the next VecDiff::Push carrying vec![15] is delayed till next wakeup.

@martin-kolarik
Copy link
Author

So, here is the code:

use std::future::ready;

use async_std::task::{sleep, spawn};
use futures_signals::signal_vec::{MutableVec, SignalVecExt};

#[async_std::main]
async fn main() {
    let outer: MutableVec<MutableVec<usize>> = MutableVec::new();

    let flattened = outer
        .signal_vec_cloned()
        .map(|inner| inner.signal_vec())
        .flatten();

    spawn(flattened.map(|x| println!("{x}")).for_each(|_| ready(())));

    sleep(std::time::Duration::from_secs(1)).await;

    outer.lock_mut().push_cloned(MutableVec::new());
    outer
        .lock_mut()
        .push_cloned(MutableVec::new_with_values(vec![42]));

    loop {
        sleep(std::time::Duration::from_secs(1)).await;
    }
}

The sleep afer spawn ensures in a dirty way that spawn starts polling before values are inserted.

If flatten implementation uses continue, as in #80, it prints out 42. If flatten uses false, as in current 0.3.33 code, it prints out nothing.

@Pauan Pauan closed this as completed in e3c207d Apr 12, 2024
@Pauan
Copy link
Owner

Pauan commented Apr 12, 2024

Sorry about the delay on this, I've been quite busy. Your example was helpful, and I've fixed this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants