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

Async system interaction. #35

Open
semtexzv opened this issue Nov 26, 2024 · 2 comments
Open

Async system interaction. #35

semtexzv opened this issue Nov 26, 2024 · 2 comments

Comments

@semtexzv
Copy link

I'm working on an app, that requires doing some async stuff. Currently there is no way to interact between these 2 systems.
Even a simple mechanism for posting messages to change state would be very helpful.

@fwcd
Copy link
Owner

fwcd commented Nov 26, 2024

Nuit's state management is a bit different from other GUI frameworks that rely on message passing (e.g. Elm-inspired ones), but if you have an idea of how to make it work, feel free to contribute!

@semtexzv
Copy link
Author

I think it'll have to be callback based (to include State changes). What I'd do for SwiftUI:

  1. Start a thread pool (or single background thread) tokio executor to execute long running operations.
  2. Implement a new spawn method that posts long running work onto background executor, and processes the result on main thread.
pub fn spawn<Item, Fut, Fun>(fut: Fut, fun: Fun)
where
    Fut: Future<Output =Item> + Send + 'static,
    Fun: FnOnce(Item) + 'static,
{
    // copied from dispatch crate
    fn context_and_function<F>(closure: F) -> (*mut c_void, dispatch_function_t)
    where F: FnOnce() {
        extern fn work_execute_closure<F>(context: Box<F>) where F: FnOnce() {
            (*context)();
        }

        let closure = Box::new(closure);
        let func: extern fn(Box<F>) = work_execute_closure::<F>;
        unsafe {
            (mem::transmute(closure), mem::transmute(func))
        }
    }

    // Somehow assert we're on main thread before spawning onto background queue.
    tokio::spawn(async move {
        let item = fut.await;

        let (context, work) = context_and_function(fun);
        unsafe {
            dispatch_async_f(dispatch_get_main_queue(), context, work);
        }
    })
}

Example use:

#[derive(Bind)]
struct Sample {
    running: State<bool>,
    result: State<Option<String>>,
}

impl View for Sample {
    type Body = impl View;

    fn body(&self) -> Self::Body {
        let text = if self.running.get() { "Run" } else { "Cancel" };

        let running = self.running.clone();
        let result = self.result.clone();
        Button::with_text(text, move || {
            running.set(false);
            nuit::spawn(make_long_running_operation(), |val| {
                result.set(val);
                running.set(false);
            })
        })
    }
}

My question here is, would this work with state tracking and accurately cause the tree to be re-evaluated?

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