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

Why does AsyncOperationCompletedHandler::new require Send? #63

Open
chris-morgan opened this issue Feb 6, 2019 · 3 comments
Open

Why does AsyncOperationCompletedHandler::new require Send? #63

chris-morgan opened this issue Feb 6, 2019 · 3 comments

Comments

@chris-morgan
Copy link

AsyncOperationCompletedHandler::new::<_F_> includes Send in its bounds for _F_, and I’m not sure why it does, or whether it should in fact.

For “I’m not sure why”: AsyncOperationCompletedHandler is explicitly marked !Send and !Sync, so why would its callback need to be Send?

For “I’m not sure whether it should”: my concrete use case is WebViewControl, which requires a single-threaded apartment anyway. Given that WebViewControl instantiation is done asynchronously and you can’t use blocking_get() for reasons I won’t contemplate, the Send bound on the callback is very debilitating; it actively blocks what seems to me the most likely way you want to use it.

I have not investigated in any depth, but my intuition says that IAsyncOperation would always be at least effectively single-threaded.

Have I missed something? Is there a reason why that Send bound is there?

@Boddlnagg
Copy link
Collaborator

Short answer: I do not know.

I think that I added the Send bound to all those callbacks just as a precursory safety measure. It's possible that it's totally unnecessary. I would like to think more about all this async stuff anyway, because I'd like to see if it can be combined with Rust's new async/await feature. I could really need some helping hands there, though :-)

@chris-morgan
Copy link
Author

I was thinking a similar thing about whether it could be handled in async/await. I haven’t thought too hard about it yet.

I can’t speak for other uses of it, but I can now speak for the WebViewControl case: you set the Completed handler, and it will then be called later from the same thread in a DispatchMessageW (i.e. you need to get an event loop running).

For my particular case, I believe I need the Send bound not to be present. (I’ve worked around this so far with an unsafe wrapper, and on reflection may continue to need to do something like that anyway.) I picture the code normally going something like this:

let mut control = None;
let operation = process
    .create_web_view_control_async(host_window_handle, rect)
    .expect("CreateWebViewControlAsync call failed");
operation.set_completed(&AsyncOperationCompletedHandler::new(|_sender, _args| {
    control = operation.get_results().unwrap();
    if let Some(ref control) = control {
        control.navigate(&Uri::create_uri(&FastHString::from("http://www.example.com")).unwrap()).unwrap();
    }
}));

@Boddlnagg
Copy link
Collaborator

We would really need to know if it's guaranteed that async operations always execute on the thread that created the callback. If it's not guaranteed, the Send bound is necessary, but we could add some unsafe way to create handler with a !Send callback.

By the way, I'm experimenting with async/await in a branch: https://github.com/Boddlnagg/winrt-rust/tree/futures-preview

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