Bug 1772053 - Enable dynamic code disable mitigations only on Windows 10 1703+ r...
[gecko.git] / dom / media / gtest / WaitFor.h
blob00e979b408c6f410ed53634791cad2cf298bd12e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef WAITFOR_H_
6 #define WAITFOR_H_
8 #include "MediaEventSource.h"
9 #include "MediaUtils.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/MozPromise.h"
12 #include "mozilla/ResultVariant.h"
13 #include "mozilla/SpinEventLoopUntil.h"
15 namespace mozilla {
17 /**
18 * Waits for an occurrence of aEvent on the current thread (by blocking it,
19 * except tasks added to the event loop may run) and returns the event's
20 * templated value, if it's non-void.
22 * The caller must be wary of eventloop issues, in
23 * particular cases where we rely on a stable state runnable, but there is never
24 * a task to trigger stable state. In such cases it is the responsibility of the
25 * caller to create the needed tasks, as JS would. A noteworthy API that relies
26 * on stable state is MediaTrackGraph::GetInstance.
28 template <typename T>
29 T WaitFor(MediaEventSource<T>& aEvent) {
30 Maybe<T> value;
31 MediaEventListener listener = aEvent.Connect(
32 AbstractThread::GetCurrent(), [&](T aValue) { value = Some(aValue); });
33 SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
34 "WaitFor(MediaEventSource<T>& aEvent)"_ns,
35 [&] { return value.isSome(); });
36 listener.Disconnect();
37 return value.value();
40 /**
41 * Specialization of WaitFor<T> for void.
43 void WaitFor(MediaEventSource<void>& aEvent);
45 /**
46 * Variant of WaitFor that blocks the caller until a MozPromise has either been
47 * resolved or rejected.
49 template <typename R, typename E, bool Exc>
50 Result<R, E> WaitFor(const RefPtr<MozPromise<R, E, Exc>>& aPromise) {
51 Maybe<R> success;
52 Maybe<E> error;
53 aPromise->Then(
54 GetCurrentSerialEventTarget(), __func__,
55 [&](R aResult) { success = Some(aResult); },
56 [&](E aError) { error = Some(aError); });
57 SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
58 "WaitFor(const RefPtr<MozPromise<R, E, Exc>>& aPromise)"_ns,
59 [&] { return success.isSome() || error.isSome(); });
60 if (success.isSome()) {
61 return success.extract();
63 return Err(error.extract());
66 /**
67 * A variation of WaitFor that takes a callback to be called each time aEvent is
68 * raised. Blocks the caller until the callback function returns true.
70 template <typename... Args, typename CallbackFunction>
71 void WaitUntil(MediaEventSource<Args...>& aEvent, CallbackFunction&& aF) {
72 bool done = false;
73 MediaEventListener listener =
74 aEvent.Connect(AbstractThread::GetCurrent(), [&](Args... aValue) {
75 if (!done) {
76 done = aF(std::forward<Args>(aValue)...);
78 });
79 SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
80 "WaitUntil(MediaEventSource<Args...>& aEvent, CallbackFunction&& aF)"_ns,
81 [&] { return done; });
82 listener.Disconnect();
85 template <typename... Args>
86 using TakeNPromise = MozPromise<std::vector<std::tuple<Args...>>, bool, true>;
88 template <ListenerPolicy Lp, typename... Args>
89 auto TakeN(MediaEventSourceImpl<Lp, Args...>& aEvent, size_t aN)
90 -> RefPtr<TakeNPromise<Args...>> {
91 using Storage = std::vector<std::tuple<Args...>>;
92 using Promise = TakeNPromise<Args...>;
93 using Values = media::Refcountable<Storage>;
94 using Listener = media::Refcountable<MediaEventListener>;
95 RefPtr<Values> values = MakeRefPtr<Values>();
96 values->reserve(aN);
97 RefPtr<Listener> listener = MakeRefPtr<Listener>();
98 auto promise = InvokeAsync(
99 AbstractThread::GetCurrent(), __func__, [values, aN]() mutable {
100 SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
101 "TakeN(MediaEventSourceImpl<Lp, Args...>& aEvent, size_t aN)"_ns,
102 [&] { return values->size() == aN; });
103 return Promise::CreateAndResolve(std::move(*values), __func__);
105 *listener = aEvent.Connect(AbstractThread::GetCurrent(),
106 [values, listener, aN](Args... aValue) {
107 values->push_back({aValue...});
108 if (values->size() == aN) {
109 listener->Disconnect();
112 return promise;
116 * Helper that, given that canonicals have just been updated on the current
117 * thread, will block its execution until mirrors and their watchers have
118 * executed on aTarget.
120 inline void WaitForMirrors(const RefPtr<nsISerialEventTarget>& aTarget) {
121 Unused << WaitFor(InvokeAsync(aTarget, __func__, [] {
122 return GenericPromise::CreateAndResolve(true, "WaitForMirrors resolver");
123 }));
127 * Short form of WaitForMirrors that assumes mirrors are on the current thread
128 * (like canonicals).
130 inline void WaitForMirrors() { WaitForMirrors(GetCurrentSerialEventTarget()); }
132 } // namespace mozilla
134 #endif // WAITFOR_H_