How best to do async functions and XPCOM?

2019-12-06 Thread Geoff Lankow

Hi all

I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd 
like to use Promises but a lot of the time I'll be far from a JS context 
so that doesn't really seem like an option. The best alternative I've 
come up with is to create some sort of listener object and pass it to 
the async function:


interface nsIFooOperationListener : nsISupports {
  void onOperationComplete(
in nsresult status,
[optional] in string errorMessage
  );
};

...

void fooFunction(..., in nsIFooOperationListener listener);

This works fine but I wonder if there's a better way, or if there's some 
established prior art I can use/borrow rather than find out the pitfalls 
myself.


TIA,
GL
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-06 Thread Gerald Squelart
On Friday, December 6, 2019 at 9:20:21 AM UTC+11, Geoff Lankow wrote:
> Hi all
> 
> I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd 
> like to use Promises but a lot of the time I'll be far from a JS context 
> so that doesn't really seem like an option. The best alternative I've 
> come up with is to create some sort of listener object and pass it to 
> the async function:
> 
> interface nsIFooOperationListener : nsISupports {
>void onOperationComplete(
>  in nsresult status,
>  [optional] in string errorMessage
>);
> };
> 
> ...
> 
> void fooFunction(..., in nsIFooOperationListener listener);
> 
> This works fine but I wonder if there's a better way, or if there's some 
> established prior art I can use/borrow rather than find out the pitfalls 
> myself.
> 
> TIA,
> GL

We have mozilla::MozPromise [0], similar to mozilla::dom::Promise but it 
doesn't rely on JS at all.

It can be a bit tricky to use, the simplest way (to start) is probably to do 
something like InvokeAsync(work thread, code to run that resolves or rejects 
the promise)->Then(target thread, on-success follow-up, on-failure follow-up) 
(e.g., [1]).

Good luck!
g.

[0] 
https://searchfox.org/mozilla-central/rev/ea63a0888d406fae720cf24f4727d87569a8cab5/xpcom/threads/MozPromise.h#98
[1] 
https://searchfox.org/mozilla-central/rev/ea63a0888d406fae720cf24f4727d87569a8cab5/dom/media/ChannelMediaDecoder.cpp#392
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-06 Thread Boris Zbarsky

On 12/5/19 5:20 PM, Geoff Lankow wrote:
I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd 
like to use Promises but a lot of the time I'll be far from a JS context 


Is that because both the implementation of the API and the consumer of 
the API will be C++?


For what it's worth, you are never far from a JSContext; AutoJSAPI will 
give you one.  The hard part may be finding an appropriate global to use...


In general, if the consumer or implementor of the API is JS, I would use 
JS promises.  If this is all in C++ land, MozPromise works fine, afaict.


-Boris
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-06 Thread saschanaz7
On Friday, December 6, 2019 at 7:20:21 AM UTC+9, Geoff Lankow wrote:
> Hi all
> 
> I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd 
> like to use Promises but a lot of the time I'll be far from a JS context 
> so that doesn't really seem like an option. The best alternative I've 
> come up with is to create some sort of listener object and pass it to 
> the async function:
> 
> interface nsIFooOperationListener : nsISupports {
>void onOperationComplete(
>  in nsresult status,
>  [optional] in string errorMessage
>);
> };
> 
> ...
> 
> void fooFunction(..., in nsIFooOperationListener listener);
> 
> This works fine but I wonder if there's a better way, or if there's some 
> established prior art I can use/borrow rather than find out the pitfalls 
> myself.
> 
> TIA,
> GL

I recently got a chance to play with MozPromise [0] in a pure C++ function to 
access Windows API. It served my purpose well except that I had to use a bit 
hacky way to pass `MozPromiseHolder` into a lambda expression.

[0]: https://phabricator.services.mozilla.com/D42484
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-09 Thread Joshua Cranmer 🐧

On 12/5/2019 6:33 PM, Gerald Squelart wrote:

On Friday, December 6, 2019 at 9:20:21 AM UTC+11, Geoff Lankow wrote:

Hi all

I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd
like to use Promises but a lot of the time I'll be far from a JS context
so that doesn't really seem like an option. The best alternative I've
come up with is to create some sort of listener object and pass it to
the async function:

interface nsIFooOperationListener : nsISupports {
void onOperationComplete(
  in nsresult status,
  [optional] in string errorMessage
);
};

...

void fooFunction(..., in nsIFooOperationListener listener);

This works fine but I wonder if there's a better way, or if there's some
established prior art I can use/borrow rather than find out the pitfalls
myself.

TIA,
GL

We have mozilla::MozPromise [0], similar to mozilla::dom::Promise but it 
doesn't rely on JS at all.

It can be a bit tricky to use, the simplest way (to start) is probably to do 
something like InvokeAsync(work thread, code to run that resolves or rejects the 
promise)->Then(target thread, on-success follow-up, on-failure follow-up) 
(e.g., [1]).


The problem with MozPromise is that it doesn't integrate well if you use 
XPIDL interfaces, so you have this annoying issue that if you want to 
use XPIDL integration, you have to use mozilla::dom::Promise, which is 
annoying to use from C++. A third wrinkle, especially now that async 
functions has landed in Rust, is if you want to try to use 
std::future::Future in Rust, which isn't going to convert terribly well 
to either form.


It may be worth spending some time building some wrappers to integrate 
between all of our various async function frameworks...


--
Joshua Cranmer
Thunderbird and DXR developer
Source code archæologist

___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-12 Thread Kris Maglione

On Fri, Dec 06, 2019 at 11:20:12AM +1300, Geoff Lankow wrote:

Hi all

I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd 
like to use Promises but a lot of the time I'll be far from a JS 
context so that doesn't really seem like an option. The best 
alternative I've come up with is to create some sort of listener 
object and pass it to the async function:


interface nsIFooOperationListener : nsISupports {
 void onOperationComplete(
   in nsresult status,
   [optional] in string errorMessage
 );
};

...

void fooFunction(..., in nsIFooOperationListener listener);

This works fine but I wonder if there's a better way, or if there's 
some established prior art I can use/borrow rather than find out the 
pitfalls myself.


In general, if you're thinking about using an XPIDL interface for something, 
you're probably going down the wrong track. If you're only going to be 
dealing with C++, then you should generally use a pure C++ interface 
(probably just MozPromise in this case). If you're going to need to interact 
with JS at any point, you should probably just use dom::Promise. You can 
always use AutoJSAPI to get a JSContext, and create the Promise in the 
shared JSM global.

___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-12 Thread Kris Maglione

On Sun, Dec 08, 2019 at 11:40:52PM -0500, Joshua Cranmer 🐧 wrote:
The problem with MozPromise is that it doesn't integrate well if you 
use XPIDL interfaces, so you have this annoying issue that if you want 
to use XPIDL integration, you have to use mozilla::dom::Promise, which 
is annoying to use from C++.


In what way is dom::Promise annoying to use from C++? The entire purpose of 
dom::Promise is to make JS promises easy to use from C++.

___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-12 Thread Andreas Tolfsen
Also sprach Joshua Cranmer:

> The problem with MozPromise is that it doesn't integrate well if you use 
> XPIDL interfaces, so you have this annoying issue that if you want to use 
> XPIDL integration, you have to use mozilla::dom::Promise, which is annoying 
> to use from C++. A third wrinkle, especially now that async functions has 
> landed in Rust, is if you want to try to use std::future::Future in Rust, 
> which isn't going to convert terribly well to either form.

In this context it should also be mentioned that the Rust XPCOM bindings do not 
support DOM promises quite yet:

https://bugzilla.mozilla.org/show_bug.cgi?id=1512319

___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-12 Thread Geoff Lankow
Thanks to all who replied, including Kris whose reply seems to have not 
made it back to the list. As per usual when I ask for help I've been 
immediately distracted by something more urgent and not got back to the 
problem at hand. :-/


As some pointed out this would be a lot easier if I was exclusively in 
JS-land or in C++-land, but I'm not. Nor am I starting something new 
from scratch, which also be easier.


I'm modernising some existing components while trying to avoid wholesale 
rewriting of major parts of the program. There are multiple pieces in 
both languages and they all interact. Also some of this code is *really* 
old in Mozilla terms, which is, um, helpful…


GL
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2019-12-16 Thread Boris Zbarsky

On 12/10/19 3:31 PM, Kris Maglione wrote:

In what way is dom::Promise annoying to use from C++?


The one thing I know about that's pretty annoying is if you receive the 
promise from someone else and want to add reactions to it. 
PromiseNativeHandler kinda works, but then you get JS::Values and have 
to extract the things you care about from them manually, which is a bit 
of a pain.


-Boris
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: How best to do async functions and XPCOM?

2020-01-08 Thread Kris Maglione

On Thu, Dec 12, 2019 at 09:30:06AM -0500, Boris Zbarsky wrote:

On 12/10/19 3:31 PM, Kris Maglione wrote:

In what way is dom::Promise annoying to use from C++?


The one thing I know about that's pretty annoying is if you receive 
the promise from someone else and want to add reactions to it. 
PromiseNativeHandler kinda works, but then you get JS::Values and have 
to extract the things you care about from them manually, which is a 
bit of a pain.


Note that you can also use `ThenWithCycleCollectedArgs` and 
`ThenWithoutCycleCollection` to add reactions from native code, which is 
a lot easier than `PromiseNativeHandler`. You do still need to manually 
deal with JS::Values, though.

___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform