xref: /aosp_15_r20/external/cronet/base/threading/sequence_bound.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_THREADING_SEQUENCE_BOUND_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_THREADING_SEQUENCE_BOUND_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <concepts>
9*6777b538SAndroid Build Coastguard Worker #include <new>
10*6777b538SAndroid Build Coastguard Worker #include <tuple>
11*6777b538SAndroid Build Coastguard Worker #include <type_traits>
12*6777b538SAndroid Build Coastguard Worker #include <utility>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/memory/scoped_refptr.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/run_loop.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/threading/sequence_bound_internal.h"
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace base {
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker // Performing blocking work on a different task runner is a common pattern for
26*6777b538SAndroid Build Coastguard Worker // improving responsiveness of foreground task runners. `SequenceBound<T>`
27*6777b538SAndroid Build Coastguard Worker // provides an abstraction for an owner object living on the owner sequence, to
28*6777b538SAndroid Build Coastguard Worker // construct, call methods on, and destroy an object of type T that lives on a
29*6777b538SAndroid Build Coastguard Worker // different sequence (the bound sequence).
30*6777b538SAndroid Build Coastguard Worker //
31*6777b538SAndroid Build Coastguard Worker // This makes it natural for code running on different sequences to be
32*6777b538SAndroid Build Coastguard Worker // partitioned along class boundaries, e.g.:
33*6777b538SAndroid Build Coastguard Worker //
34*6777b538SAndroid Build Coastguard Worker // class Tab {
35*6777b538SAndroid Build Coastguard Worker //  private:
36*6777b538SAndroid Build Coastguard Worker //   void OnScroll() {
37*6777b538SAndroid Build Coastguard Worker //     // ...
38*6777b538SAndroid Build Coastguard Worker //     io_helper_.AsyncCall(&IOHelper::SaveScrollPosition);
39*6777b538SAndroid Build Coastguard Worker //   }
40*6777b538SAndroid Build Coastguard Worker //   base::SequenceBound<IOHelper> io_helper_{GetBackgroundTaskRunner()};
41*6777b538SAndroid Build Coastguard Worker // };
42*6777b538SAndroid Build Coastguard Worker //
43*6777b538SAndroid Build Coastguard Worker // Note: `SequenceBound<T>` intentionally does not expose a raw pointer to the
44*6777b538SAndroid Build Coastguard Worker // managed `T` to ensure its internal sequence-safety invariants are not
45*6777b538SAndroid Build Coastguard Worker // violated. As a result, `AsyncCall()` cannot simply use `base::OnceCallback`
46*6777b538SAndroid Build Coastguard Worker //
47*6777b538SAndroid Build Coastguard Worker // SequenceBound also supports replies:
48*6777b538SAndroid Build Coastguard Worker //
49*6777b538SAndroid Build Coastguard Worker //   class Database {
50*6777b538SAndroid Build Coastguard Worker //    public:
51*6777b538SAndroid Build Coastguard Worker //     int Query(int value) {
52*6777b538SAndroid Build Coastguard Worker //       return value * value;
53*6777b538SAndroid Build Coastguard Worker //     }
54*6777b538SAndroid Build Coastguard Worker //   };
55*6777b538SAndroid Build Coastguard Worker //
56*6777b538SAndroid Build Coastguard Worker //   // SequenceBound itself is owned on
57*6777b538SAndroid Build Coastguard Worker //   // `SequencedTaskRunner::GetCurrentDefault()`. The managed Database
58*6777b538SAndroid Build Coastguard Worker //   // instance managed by it is constructed and owned on `GetDBTaskRunner()`.
59*6777b538SAndroid Build Coastguard Worker //   base::SequenceBound<Database> db(GetDBTaskRunner());
60*6777b538SAndroid Build Coastguard Worker //
61*6777b538SAndroid Build Coastguard Worker //   // `Database::Query()` runs on `GetDBTaskRunner()`, but
62*6777b538SAndroid Build Coastguard Worker //   // `reply_callback` will run on the owner task runner.
63*6777b538SAndroid Build Coastguard Worker //   auto reply_callback = [] (int result) {
64*6777b538SAndroid Build Coastguard Worker //     LOG(ERROR) << result;  // Prints 25.
65*6777b538SAndroid Build Coastguard Worker //   };
66*6777b538SAndroid Build Coastguard Worker //   db.AsyncCall(&Database::Query).WithArgs(5)
67*6777b538SAndroid Build Coastguard Worker //     .Then(base::BindOnce(reply_callback));
68*6777b538SAndroid Build Coastguard Worker //
69*6777b538SAndroid Build Coastguard Worker //   // When `db` goes out of scope, the Database instance will also be
70*6777b538SAndroid Build Coastguard Worker //   // destroyed via a task posted to `GetDBTaskRunner()`.
71*6777b538SAndroid Build Coastguard Worker //
72*6777b538SAndroid Build Coastguard Worker // Sequence safety:
73*6777b538SAndroid Build Coastguard Worker //
74*6777b538SAndroid Build Coastguard Worker // Const-qualified methods may be used concurrently from multiple sequences,
75*6777b538SAndroid Build Coastguard Worker // e.g. `AsyncCall()` or `is_null()`. Calls that are forwarded to the
76*6777b538SAndroid Build Coastguard Worker // managed `T` will be posted to the bound sequence and executed serially
77*6777b538SAndroid Build Coastguard Worker // there.
78*6777b538SAndroid Build Coastguard Worker //
79*6777b538SAndroid Build Coastguard Worker // Mutable methods (e.g. `Reset()`, destruction, or move assignment) require
80*6777b538SAndroid Build Coastguard Worker // external synchronization if used concurrently with any other methods,
81*6777b538SAndroid Build Coastguard Worker // including const-qualified methods.
82*6777b538SAndroid Build Coastguard Worker //
83*6777b538SAndroid Build Coastguard Worker // Advanced usage:
84*6777b538SAndroid Build Coastguard Worker //
85*6777b538SAndroid Build Coastguard Worker // Using `SequenceBound<std::unique_ptr<T>>` allows transferring ownership of an
86*6777b538SAndroid Build Coastguard Worker // already-constructed `T` to `SequenceBound`. This can be helpful for more
87*6777b538SAndroid Build Coastguard Worker // complex situations, where `T` needs to be constructed on a specific sequence
88*6777b538SAndroid Build Coastguard Worker // that is different from where `T` will ultimately live.
89*6777b538SAndroid Build Coastguard Worker //
90*6777b538SAndroid Build Coastguard Worker // Construction (via the constructor or emplace) takes a `std::unique_ptr<T>`
91*6777b538SAndroid Build Coastguard Worker // instead of forwarding the arguments to `T`'s constructor:
92*6777b538SAndroid Build Coastguard Worker //
93*6777b538SAndroid Build Coastguard Worker //   std::unique_ptr<Database> db_impl = MakeDatabaseOnMainThread();
94*6777b538SAndroid Build Coastguard Worker //   base::SequenceBound<std::unique_ptr<Database>> db(GetDbTaskRunner(),
95*6777b538SAndroid Build Coastguard Worker //                                                     std::move(db_impl));
96*6777b538SAndroid Build Coastguard Worker //
97*6777b538SAndroid Build Coastguard Worker // All other usage (e.g. `AsyncCall()`, `Reset()`) functions identically to a
98*6777b538SAndroid Build Coastguard Worker // regular `SequenceBound<T>`:
99*6777b538SAndroid Build Coastguard Worker //
100*6777b538SAndroid Build Coastguard Worker //   // No need to dereference the `std::unique_ptr` explicitly:
101*6777b538SAndroid Build Coastguard Worker //   db.AsyncCall(&Database::Query).WithArgs(5).Then(base::BindOnce(...));
102*6777b538SAndroid Build Coastguard Worker template <typename T,
103*6777b538SAndroid Build Coastguard Worker           typename CrossThreadTraits =
104*6777b538SAndroid Build Coastguard Worker               sequence_bound_internal::CrossThreadTraits>
105*6777b538SAndroid Build Coastguard Worker class SequenceBound {
106*6777b538SAndroid Build Coastguard Worker  private:
107*6777b538SAndroid Build Coastguard Worker   using Storage = sequence_bound_internal::Storage<T, CrossThreadTraits>;
108*6777b538SAndroid Build Coastguard Worker   using UnwrappedT = typename Storage::element_type;
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker  public:
111*6777b538SAndroid Build Coastguard Worker   template <typename Signature>
112*6777b538SAndroid Build Coastguard Worker   using CrossThreadTask =
113*6777b538SAndroid Build Coastguard Worker       typename CrossThreadTraits::template CrossThreadTask<Signature>;
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker   // Note: on construction, SequenceBound binds to the current sequence. Any
116*6777b538SAndroid Build Coastguard Worker   // subsequent SequenceBound calls (including destruction) must run on that
117*6777b538SAndroid Build Coastguard Worker   // same sequence.
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker   // Constructs a null SequenceBound with no managed `T`.
120*6777b538SAndroid Build Coastguard Worker   SequenceBound() = default;
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker   // Constructs a SequenceBound that manages a new instance of `T` on
123*6777b538SAndroid Build Coastguard Worker   // `task_runner`. `T` will be constructed on `task_runner`.
124*6777b538SAndroid Build Coastguard Worker   //
125*6777b538SAndroid Build Coastguard Worker   // Once this constructor returns, it is safe to immediately use `AsyncCall()`,
126*6777b538SAndroid Build Coastguard Worker   // et cetera; these calls will be sequenced after the construction of the
127*6777b538SAndroid Build Coastguard Worker   // managed `T`.
128*6777b538SAndroid Build Coastguard Worker   template <typename... Args>
SequenceBound(scoped_refptr<SequencedTaskRunner> task_runner,Args &&...args)129*6777b538SAndroid Build Coastguard Worker   explicit SequenceBound(scoped_refptr<SequencedTaskRunner> task_runner,
130*6777b538SAndroid Build Coastguard Worker                          Args&&... args)
131*6777b538SAndroid Build Coastguard Worker       : impl_task_runner_(std::move(task_runner)) {
132*6777b538SAndroid Build Coastguard Worker     storage_.Construct(*impl_task_runner_, std::forward<Args>(args)...);
133*6777b538SAndroid Build Coastguard Worker   }
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker   // If non-null, the managed `T` will be destroyed on `impl_task_runner_`.`
~SequenceBound()136*6777b538SAndroid Build Coastguard Worker   ~SequenceBound() { Reset(); }
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker   // Disallow copy or assignment. SequenceBound has single ownership of the
139*6777b538SAndroid Build Coastguard Worker   // managed `T`.
140*6777b538SAndroid Build Coastguard Worker   SequenceBound(const SequenceBound&) = delete;
141*6777b538SAndroid Build Coastguard Worker   SequenceBound& operator=(const SequenceBound&) = delete;
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker   // Move construction and assignment.
SequenceBound(SequenceBound && other)144*6777b538SAndroid Build Coastguard Worker   SequenceBound(SequenceBound&& other) { MoveRecordFrom(other); }
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker   SequenceBound& operator=(SequenceBound&& other) {
147*6777b538SAndroid Build Coastguard Worker     Reset();
148*6777b538SAndroid Build Coastguard Worker     MoveRecordFrom(other);
149*6777b538SAndroid Build Coastguard Worker     return *this;
150*6777b538SAndroid Build Coastguard Worker   }
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   // Move conversion helpers: allows upcasting from SequenceBound<Derived> to
153*6777b538SAndroid Build Coastguard Worker   // SequenceBound<Base>.
154*6777b538SAndroid Build Coastguard Worker   template <typename U>
155*6777b538SAndroid Build Coastguard Worker   // NOLINTNEXTLINE(google-explicit-constructor): Intentionally implicit.
SequenceBound(SequenceBound<U,CrossThreadTraits> && other)156*6777b538SAndroid Build Coastguard Worker   SequenceBound(SequenceBound<U, CrossThreadTraits>&& other) {
157*6777b538SAndroid Build Coastguard Worker     // TODO(https://crbug.com/1382549): static_assert that U* is convertible to
158*6777b538SAndroid Build Coastguard Worker     // T*.
159*6777b538SAndroid Build Coastguard Worker     MoveRecordFrom(other);
160*6777b538SAndroid Build Coastguard Worker   }
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   template <typename U>
163*6777b538SAndroid Build Coastguard Worker   SequenceBound& operator=(SequenceBound<U, CrossThreadTraits>&& other) {
164*6777b538SAndroid Build Coastguard Worker     // TODO(https://crbug.com/1382549): static_assert that U* is convertible to
165*6777b538SAndroid Build Coastguard Worker     // T*.
166*6777b538SAndroid Build Coastguard Worker     Reset();
167*6777b538SAndroid Build Coastguard Worker     MoveRecordFrom(other);
168*6777b538SAndroid Build Coastguard Worker     return *this;
169*6777b538SAndroid Build Coastguard Worker   }
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker   // Constructs a new managed instance of `T` on `task_runner`. If `this` is
172*6777b538SAndroid Build Coastguard Worker   // already managing another instance of `T`, that pre-existing instance will
173*6777b538SAndroid Build Coastguard Worker   // first be destroyed by calling `Reset()`.
174*6777b538SAndroid Build Coastguard Worker   //
175*6777b538SAndroid Build Coastguard Worker   // Once `emplace()` returns, it is safe to immediately use `AsyncCall()`,
176*6777b538SAndroid Build Coastguard Worker   // et cetera; these calls will be sequenced after the construction of the
177*6777b538SAndroid Build Coastguard Worker   // managed `T`.
178*6777b538SAndroid Build Coastguard Worker   template <typename... Args>
emplace(scoped_refptr<SequencedTaskRunner> task_runner,Args &&...args)179*6777b538SAndroid Build Coastguard Worker   SequenceBound& emplace(scoped_refptr<SequencedTaskRunner> task_runner,
180*6777b538SAndroid Build Coastguard Worker                          Args&&... args) {
181*6777b538SAndroid Build Coastguard Worker     Reset();
182*6777b538SAndroid Build Coastguard Worker     impl_task_runner_ = std::move(task_runner);
183*6777b538SAndroid Build Coastguard Worker     storage_.Construct(*impl_task_runner_, std::forward<Args>(args)...);
184*6777b538SAndroid Build Coastguard Worker     return *this;
185*6777b538SAndroid Build Coastguard Worker   }
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker   // Invokes `method` of the managed `T` on `impl_task_runner_`. May only be
188*6777b538SAndroid Build Coastguard Worker   // used when `is_null()` is false.
189*6777b538SAndroid Build Coastguard Worker   //
190*6777b538SAndroid Build Coastguard Worker   // Basic usage:
191*6777b538SAndroid Build Coastguard Worker   //
192*6777b538SAndroid Build Coastguard Worker   //   helper.AsyncCall(&IOHelper::DoWork);
193*6777b538SAndroid Build Coastguard Worker   //
194*6777b538SAndroid Build Coastguard Worker   // If `method` accepts arguments, use `WithArgs()` to bind them:
195*6777b538SAndroid Build Coastguard Worker   //
196*6777b538SAndroid Build Coastguard Worker   //   helper.AsyncCall(&IOHelper::DoWorkWithArgs)
197*6777b538SAndroid Build Coastguard Worker   //       .WithArgs(args);
198*6777b538SAndroid Build Coastguard Worker   //
199*6777b538SAndroid Build Coastguard Worker   // Use `Then()` to run a callback on the owner sequence after `method`
200*6777b538SAndroid Build Coastguard Worker   // completes:
201*6777b538SAndroid Build Coastguard Worker   //
202*6777b538SAndroid Build Coastguard Worker   //   helper.AsyncCall(&IOHelper::GetValue)
203*6777b538SAndroid Build Coastguard Worker   //       .Then(std::move(process_result_callback));
204*6777b538SAndroid Build Coastguard Worker   //
205*6777b538SAndroid Build Coastguard Worker   // If a method returns a non-void type, use of `Then()` is required, and the
206*6777b538SAndroid Build Coastguard Worker   // method's return value will be passed to the `Then()` callback. To ignore
207*6777b538SAndroid Build Coastguard Worker   // the method's return value instead, wrap `method` in `base::IgnoreResult()`:
208*6777b538SAndroid Build Coastguard Worker   //
209*6777b538SAndroid Build Coastguard Worker   //   // Calling `GetPrefs` to force-initialize prefs.
210*6777b538SAndroid Build Coastguard Worker   //   helper.AsyncCall(base::IgnoreResult(&IOHelper::GetPrefs));
211*6777b538SAndroid Build Coastguard Worker   //
212*6777b538SAndroid Build Coastguard Worker   // `WithArgs()` and `Then()` may also be combined:
213*6777b538SAndroid Build Coastguard Worker   //
214*6777b538SAndroid Build Coastguard Worker   //   // Ordering is important: `Then()` must come last.
215*6777b538SAndroid Build Coastguard Worker   //   helper.AsyncCall(&IOHelper::GetValueWithArgs)
216*6777b538SAndroid Build Coastguard Worker   //       .WithArgs(args)
217*6777b538SAndroid Build Coastguard Worker   //       .Then(std::move(process_result_callback));
218*6777b538SAndroid Build Coastguard Worker   //
219*6777b538SAndroid Build Coastguard Worker   // Note: internally, `AsyncCall()` is implemented using a series of helper
220*6777b538SAndroid Build Coastguard Worker   // classes that build the callback chain and post it on destruction. Capturing
221*6777b538SAndroid Build Coastguard Worker   // the return value and passing it elsewhere or triggering lifetime extension
222*6777b538SAndroid Build Coastguard Worker   // (e.g. by binding the return value to a reference) are both unsupported.
223*6777b538SAndroid Build Coastguard Worker   template <typename R, typename C, typename... Args>
requires(std::derived_from<UnwrappedT,C>)224*6777b538SAndroid Build Coastguard Worker     requires(std::derived_from<UnwrappedT, C>)
225*6777b538SAndroid Build Coastguard Worker   auto AsyncCall(R (C::*method)(Args...),
226*6777b538SAndroid Build Coastguard Worker                  const Location& location = Location::Current()) const {
227*6777b538SAndroid Build Coastguard Worker     return AsyncCallBuilder<R (C::*)(Args...), R, std::tuple<Args...>>(
228*6777b538SAndroid Build Coastguard Worker         this, &location, method);
229*6777b538SAndroid Build Coastguard Worker   }
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker   template <typename R, typename C, typename... Args>
requires(std::derived_from<UnwrappedT,C>)232*6777b538SAndroid Build Coastguard Worker     requires(std::derived_from<UnwrappedT, C>)
233*6777b538SAndroid Build Coastguard Worker   auto AsyncCall(R (C::*method)(Args...) const,
234*6777b538SAndroid Build Coastguard Worker                  const Location& location = Location::Current()) const {
235*6777b538SAndroid Build Coastguard Worker     return AsyncCallBuilder<R (C::*)(Args...) const, R, std::tuple<Args...>>(
236*6777b538SAndroid Build Coastguard Worker         this, &location, method);
237*6777b538SAndroid Build Coastguard Worker   }
238*6777b538SAndroid Build Coastguard Worker 
239*6777b538SAndroid Build Coastguard Worker   template <typename R, typename C, typename... Args>
requires(std::derived_from<UnwrappedT,C>)240*6777b538SAndroid Build Coastguard Worker     requires(std::derived_from<UnwrappedT, C>)
241*6777b538SAndroid Build Coastguard Worker   auto AsyncCall(internal::IgnoreResultHelper<R (C::*)(Args...) const> method,
242*6777b538SAndroid Build Coastguard Worker                  const Location& location = Location::Current()) const {
243*6777b538SAndroid Build Coastguard Worker     return AsyncCallBuilder<
244*6777b538SAndroid Build Coastguard Worker         internal::IgnoreResultHelper<R (C::*)(Args...) const>, void,
245*6777b538SAndroid Build Coastguard Worker         std::tuple<Args...>>(this, &location, method);
246*6777b538SAndroid Build Coastguard Worker   }
247*6777b538SAndroid Build Coastguard Worker 
248*6777b538SAndroid Build Coastguard Worker   template <typename R, typename C, typename... Args>
requires(std::derived_from<UnwrappedT,C>)249*6777b538SAndroid Build Coastguard Worker     requires(std::derived_from<UnwrappedT, C>)
250*6777b538SAndroid Build Coastguard Worker   auto AsyncCall(internal::IgnoreResultHelper<R (C::*)(Args...)> method,
251*6777b538SAndroid Build Coastguard Worker                  const Location& location = Location::Current()) const {
252*6777b538SAndroid Build Coastguard Worker     return AsyncCallBuilder<internal::IgnoreResultHelper<R (C::*)(Args...)>,
253*6777b538SAndroid Build Coastguard Worker                             void, std::tuple<Args...>>(this, &location, method);
254*6777b538SAndroid Build Coastguard Worker   }
255*6777b538SAndroid Build Coastguard Worker 
256*6777b538SAndroid Build Coastguard Worker   // Posts `task` to `impl_task_runner_`, passing it a reference to the wrapped
257*6777b538SAndroid Build Coastguard Worker   // object. This allows arbitrary logic to be safely executed on the object's
258*6777b538SAndroid Build Coastguard Worker   // task runner. The object is guaranteed to remain alive for the duration of
259*6777b538SAndroid Build Coastguard Worker   // the task.
260*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1182140): Consider checking whether the task runner can run
261*6777b538SAndroid Build Coastguard Worker   // tasks in current sequence, and using "plain" binds and task posting (here
262*6777b538SAndroid Build Coastguard Worker   // and other places that `CrossThreadTraits::PostTask`).
263*6777b538SAndroid Build Coastguard Worker   using ConstPostTaskCallback = CrossThreadTask<void(const UnwrappedT&)>;
264*6777b538SAndroid Build Coastguard Worker   void PostTaskWithThisObject(
265*6777b538SAndroid Build Coastguard Worker       ConstPostTaskCallback callback,
266*6777b538SAndroid Build Coastguard Worker       const Location& location = Location::Current()) const {
267*6777b538SAndroid Build Coastguard Worker     DCHECK(!is_null());
268*6777b538SAndroid Build Coastguard Worker     // Even though the lifetime of the object managed by `storage_` may not
269*6777b538SAndroid Build Coastguard Worker     // have begun yet, the storage has been allocated. Per [basic.life/6] and
270*6777b538SAndroid Build Coastguard Worker     // [basic.life/7], "Indirection through such a pointer is permitted but the
271*6777b538SAndroid Build Coastguard Worker     // resulting lvalue may only be used in limited ways, as described below."
272*6777b538SAndroid Build Coastguard Worker     CrossThreadTraits::PostTask(
273*6777b538SAndroid Build Coastguard Worker         *impl_task_runner_, location,
274*6777b538SAndroid Build Coastguard Worker         CrossThreadTraits::BindOnce(std::move(callback),
275*6777b538SAndroid Build Coastguard Worker                                     storage_.GetRefForBind()));
276*6777b538SAndroid Build Coastguard Worker   }
277*6777b538SAndroid Build Coastguard Worker 
278*6777b538SAndroid Build Coastguard Worker   // Same as above, but for non-const operations. The callback takes a pointer
279*6777b538SAndroid Build Coastguard Worker   // to the wrapped object rather than a const ref.
280*6777b538SAndroid Build Coastguard Worker   using PostTaskCallback = CrossThreadTask<void(UnwrappedT*)>;
281*6777b538SAndroid Build Coastguard Worker   void PostTaskWithThisObject(
282*6777b538SAndroid Build Coastguard Worker       PostTaskCallback callback,
283*6777b538SAndroid Build Coastguard Worker       const Location& location = Location::Current()) const {
284*6777b538SAndroid Build Coastguard Worker     DCHECK(!is_null());
285*6777b538SAndroid Build Coastguard Worker     CrossThreadTraits::PostTask(
286*6777b538SAndroid Build Coastguard Worker         *impl_task_runner_, location,
287*6777b538SAndroid Build Coastguard Worker         CrossThreadTraits::BindOnce(std::move(callback),
288*6777b538SAndroid Build Coastguard Worker                                     storage_.GetPtrForBind()));
289*6777b538SAndroid Build Coastguard Worker   }
290*6777b538SAndroid Build Coastguard Worker 
FlushPostedTasksForTesting()291*6777b538SAndroid Build Coastguard Worker   void FlushPostedTasksForTesting() const {
292*6777b538SAndroid Build Coastguard Worker     DCHECK(!is_null());
293*6777b538SAndroid Build Coastguard Worker     RunLoop run_loop;
294*6777b538SAndroid Build Coastguard Worker     CrossThreadTraits::PostTask(*impl_task_runner_, FROM_HERE,
295*6777b538SAndroid Build Coastguard Worker                                 run_loop.QuitClosure());
296*6777b538SAndroid Build Coastguard Worker     run_loop.Run();
297*6777b538SAndroid Build Coastguard Worker   }
298*6777b538SAndroid Build Coastguard Worker 
299*6777b538SAndroid Build Coastguard Worker   // TODO(liberato): Add PostOrCall(), to support cases where synchronous calls
300*6777b538SAndroid Build Coastguard Worker   // are okay if it's the same task runner.
301*6777b538SAndroid Build Coastguard Worker 
302*6777b538SAndroid Build Coastguard Worker   // Resets `this` to null. If `this` is not currently null, posts destruction
303*6777b538SAndroid Build Coastguard Worker   // of the managed `T` to `impl_task_runner_`.
Reset()304*6777b538SAndroid Build Coastguard Worker   void Reset() {
305*6777b538SAndroid Build Coastguard Worker     if (is_null())
306*6777b538SAndroid Build Coastguard Worker       return;
307*6777b538SAndroid Build Coastguard Worker 
308*6777b538SAndroid Build Coastguard Worker     storage_.Destruct(*impl_task_runner_);
309*6777b538SAndroid Build Coastguard Worker     impl_task_runner_ = nullptr;
310*6777b538SAndroid Build Coastguard Worker   }
311*6777b538SAndroid Build Coastguard Worker 
312*6777b538SAndroid Build Coastguard Worker   // Resets `this` to null. If `this` is not currently null, posts destruction
313*6777b538SAndroid Build Coastguard Worker   // of the managed `T` to `impl_task_runner_`. Blocks until the destructor has
314*6777b538SAndroid Build Coastguard Worker   // run.
SynchronouslyResetForTest()315*6777b538SAndroid Build Coastguard Worker   void SynchronouslyResetForTest() {
316*6777b538SAndroid Build Coastguard Worker     if (is_null())
317*6777b538SAndroid Build Coastguard Worker       return;
318*6777b538SAndroid Build Coastguard Worker 
319*6777b538SAndroid Build Coastguard Worker     scoped_refptr<SequencedTaskRunner> task_runner = impl_task_runner_;
320*6777b538SAndroid Build Coastguard Worker     Reset();
321*6777b538SAndroid Build Coastguard Worker     // `Reset()` posts a task to destroy the managed `T`; synchronously wait for
322*6777b538SAndroid Build Coastguard Worker     // that posted task to complete.
323*6777b538SAndroid Build Coastguard Worker     RunLoop run_loop;
324*6777b538SAndroid Build Coastguard Worker     CrossThreadTraits::PostTask(*task_runner, FROM_HERE,
325*6777b538SAndroid Build Coastguard Worker                                 run_loop.QuitClosure());
326*6777b538SAndroid Build Coastguard Worker     run_loop.Run();
327*6777b538SAndroid Build Coastguard Worker   }
328*6777b538SAndroid Build Coastguard Worker 
329*6777b538SAndroid Build Coastguard Worker   // Return true if `this` is logically null; otherwise, returns false.
330*6777b538SAndroid Build Coastguard Worker   //
331*6777b538SAndroid Build Coastguard Worker   // A SequenceBound is logically null if there is no managed `T`; it is only
332*6777b538SAndroid Build Coastguard Worker   // valid to call `AsyncCall()` on a non-null SequenceBound.
333*6777b538SAndroid Build Coastguard Worker   //
334*6777b538SAndroid Build Coastguard Worker   // Note that the concept of 'logically null' here does not exactly match the
335*6777b538SAndroid Build Coastguard Worker   // lifetime of `T`, which lives on `impl_task_runner_`. In particular, when
336*6777b538SAndroid Build Coastguard Worker   // SequenceBound is first constructed, `is_null()` may return false, even
337*6777b538SAndroid Build Coastguard Worker   // though the lifetime of `T` may not have begun yet on `impl_task_runner_`.
338*6777b538SAndroid Build Coastguard Worker   // Similarly, after `SequenceBound::Reset()`, `is_null()` may return true,
339*6777b538SAndroid Build Coastguard Worker   // even though the lifetime of `T` may not have ended yet on
340*6777b538SAndroid Build Coastguard Worker   // `impl_task_runner_`.
is_null()341*6777b538SAndroid Build Coastguard Worker   bool is_null() const { return storage_.is_null(); }
342*6777b538SAndroid Build Coastguard Worker 
343*6777b538SAndroid Build Coastguard Worker   // True if `this` is not logically null. See `is_null()`.
344*6777b538SAndroid Build Coastguard Worker   explicit operator bool() const { return !is_null(); }
345*6777b538SAndroid Build Coastguard Worker 
346*6777b538SAndroid Build Coastguard Worker  private:
347*6777b538SAndroid Build Coastguard Worker   // For move conversion.
348*6777b538SAndroid Build Coastguard Worker   template <typename U, typename V>
349*6777b538SAndroid Build Coastguard Worker   friend class SequenceBound;
350*6777b538SAndroid Build Coastguard Worker 
351*6777b538SAndroid Build Coastguard Worker   template <template <typename> class CallbackType>
352*6777b538SAndroid Build Coastguard Worker   static constexpr bool IsCrossThreadTask =
353*6777b538SAndroid Build Coastguard Worker       CrossThreadTraits::template IsCrossThreadTask<CallbackType>;
354*6777b538SAndroid Build Coastguard Worker 
355*6777b538SAndroid Build Coastguard Worker   // Support helpers for `AsyncCall()` implementation.
356*6777b538SAndroid Build Coastguard Worker   //
357*6777b538SAndroid Build Coastguard Worker   // Several implementation notes:
358*6777b538SAndroid Build Coastguard Worker   // 1. Tasks are posted via destroying the builder or an explicit call to
359*6777b538SAndroid Build Coastguard Worker   //    `Then()`.
360*6777b538SAndroid Build Coastguard Worker   //
361*6777b538SAndroid Build Coastguard Worker   // 2. A builder may be consumed by:
362*6777b538SAndroid Build Coastguard Worker   //
363*6777b538SAndroid Build Coastguard Worker   //    - calling `Then()`, which immediately posts the task chain
364*6777b538SAndroid Build Coastguard Worker   //    - calling `WithArgs()`, which returns a new builder with the captured
365*6777b538SAndroid Build Coastguard Worker   //      arguments
366*6777b538SAndroid Build Coastguard Worker   //
367*6777b538SAndroid Build Coastguard Worker   //    Builders that are consumed have the internal `sequence_bound_` field
368*6777b538SAndroid Build Coastguard Worker   //    nulled out; the hope is the compiler can see this and use it to
369*6777b538SAndroid Build Coastguard Worker   //    eliminate dead branches (e.g. correctness checks that aren't needed
370*6777b538SAndroid Build Coastguard Worker   //    since the code can be statically proved correct).
371*6777b538SAndroid Build Coastguard Worker   //
372*6777b538SAndroid Build Coastguard Worker   // 3. Builder methods are rvalue-qualified to try to enforce that the builder
373*6777b538SAndroid Build Coastguard Worker   //    is only used as a temporary. Note that this only helps so much; nothing
374*6777b538SAndroid Build Coastguard Worker   //    prevents a determined caller from using `std::move()` to force calls to
375*6777b538SAndroid Build Coastguard Worker   //    a non-temporary instance.
376*6777b538SAndroid Build Coastguard Worker   //
377*6777b538SAndroid Build Coastguard Worker   // TODO(dcheng): It might also be possible to use Gmock-style matcher
378*6777b538SAndroid Build Coastguard Worker   // composition, e.g. something like:
379*6777b538SAndroid Build Coastguard Worker   //
380*6777b538SAndroid Build Coastguard Worker   //   sb.AsyncCall(&Helper::DoWork, WithArgs(args),
381*6777b538SAndroid Build Coastguard Worker   //                Then(std::move(process_result));
382*6777b538SAndroid Build Coastguard Worker   //
383*6777b538SAndroid Build Coastguard Worker   // In theory, this might allow the elimination of magic destructors and
384*6777b538SAndroid Build Coastguard Worker   // better static checking by the compiler.
385*6777b538SAndroid Build Coastguard Worker   template <typename MethodRef>
386*6777b538SAndroid Build Coastguard Worker   class AsyncCallBuilderBase {
387*6777b538SAndroid Build Coastguard Worker    protected:
AsyncCallBuilderBase(const SequenceBound * sequence_bound,const Location * location,MethodRef method)388*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderBase(const SequenceBound* sequence_bound,
389*6777b538SAndroid Build Coastguard Worker                          const Location* location,
390*6777b538SAndroid Build Coastguard Worker                          MethodRef method)
391*6777b538SAndroid Build Coastguard Worker         : sequence_bound_(sequence_bound),
392*6777b538SAndroid Build Coastguard Worker           location_(location),
393*6777b538SAndroid Build Coastguard Worker           method_(method) {
394*6777b538SAndroid Build Coastguard Worker       // Common entry point for `AsyncCall()`, so check preconditions here.
395*6777b538SAndroid Build Coastguard Worker       DCHECK(sequence_bound_);
396*6777b538SAndroid Build Coastguard Worker       DCHECK(!sequence_bound_->storage_.is_null());
397*6777b538SAndroid Build Coastguard Worker     }
398*6777b538SAndroid Build Coastguard Worker 
399*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderBase(AsyncCallBuilderBase&&) = default;
400*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderBase& operator=(AsyncCallBuilderBase&&) = default;
401*6777b538SAndroid Build Coastguard Worker 
402*6777b538SAndroid Build Coastguard Worker     // `sequence_bound_` is consumed and set to `nullptr` when `Then()` is
403*6777b538SAndroid Build Coastguard Worker     // invoked. This is used as a flag for two potential states
404*6777b538SAndroid Build Coastguard Worker     //
405*6777b538SAndroid Build Coastguard Worker     // - if a method returns void, invoking `Then()` is optional. The destructor
406*6777b538SAndroid Build Coastguard Worker     //   will check if `sequence_bound_` is null; if it is, `Then()` was
407*6777b538SAndroid Build Coastguard Worker     //   already invoked and the task chain has already been posted, so the
408*6777b538SAndroid Build Coastguard Worker     //   destructor does not need to do anything. Otherwise, the destructor
409*6777b538SAndroid Build Coastguard Worker     //   needs to post the task to make the async call. In theory, the compiler
410*6777b538SAndroid Build Coastguard Worker     //   should be able to eliminate this branch based on the presence or
411*6777b538SAndroid Build Coastguard Worker     //   absence of a call to `Then()`.
412*6777b538SAndroid Build Coastguard Worker     //
413*6777b538SAndroid Build Coastguard Worker     // - if a method returns a non-void type, `Then()` *must* be invoked. The
414*6777b538SAndroid Build Coastguard Worker     //   destructor will `CHECK()` if `sequence_bound_` is non-null, since that
415*6777b538SAndroid Build Coastguard Worker     //   indicates `Then()` was not invoked. Similarly, note this branch should
416*6777b538SAndroid Build Coastguard Worker     //   be eliminated by the optimizer if the code is free of bugs. :)
417*6777b538SAndroid Build Coastguard Worker     raw_ptr<const SequenceBound<T, CrossThreadTraits>, DanglingUntriaged>
418*6777b538SAndroid Build Coastguard Worker         sequence_bound_;
419*6777b538SAndroid Build Coastguard Worker     // Subtle: this typically points at a Location *temporary*. This is used to
420*6777b538SAndroid Build Coastguard Worker     // try to detect errors resulting from lifetime extension of the async call
421*6777b538SAndroid Build Coastguard Worker     // factory temporaries, since the factory destructors can perform work. If
422*6777b538SAndroid Build Coastguard Worker     // the lifetime of the factory is incorrectly extended, dereferencing
423*6777b538SAndroid Build Coastguard Worker     // `location_` will trigger a stack-use-after-scope when running with ASan.
424*6777b538SAndroid Build Coastguard Worker     const raw_ptr<const Location> location_;
425*6777b538SAndroid Build Coastguard Worker     MethodRef method_;
426*6777b538SAndroid Build Coastguard Worker   };
427*6777b538SAndroid Build Coastguard Worker 
428*6777b538SAndroid Build Coastguard Worker   template <typename MethodRef, typename ReturnType, typename ArgsTuple>
429*6777b538SAndroid Build Coastguard Worker   class AsyncCallBuilderImpl;
430*6777b538SAndroid Build Coastguard Worker 
431*6777b538SAndroid Build Coastguard Worker   // Selected method has no arguments and returns void.
432*6777b538SAndroid Build Coastguard Worker   template <typename MethodRef>
433*6777b538SAndroid Build Coastguard Worker   class AsyncCallBuilderImpl<MethodRef, void, std::tuple<>>
434*6777b538SAndroid Build Coastguard Worker       : public AsyncCallBuilderBase<MethodRef> {
435*6777b538SAndroid Build Coastguard Worker    public:
436*6777b538SAndroid Build Coastguard Worker     // Note: despite being here, this is actually still protected, since it is
437*6777b538SAndroid Build Coastguard Worker     // protected on the base class.
438*6777b538SAndroid Build Coastguard Worker     using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase;
439*6777b538SAndroid Build Coastguard Worker 
~AsyncCallBuilderImpl()440*6777b538SAndroid Build Coastguard Worker     ~AsyncCallBuilderImpl() {
441*6777b538SAndroid Build Coastguard Worker       if (this->sequence_bound_) {
442*6777b538SAndroid Build Coastguard Worker         CrossThreadTraits::PostTask(
443*6777b538SAndroid Build Coastguard Worker             *this->sequence_bound_->impl_task_runner_, *this->location_,
444*6777b538SAndroid Build Coastguard Worker             CrossThreadTraits::BindOnce(
445*6777b538SAndroid Build Coastguard Worker                 this->method_,
446*6777b538SAndroid Build Coastguard Worker                 this->sequence_bound_->storage_.GetPtrForBind()));
447*6777b538SAndroid Build Coastguard Worker       }
448*6777b538SAndroid Build Coastguard Worker     }
449*6777b538SAndroid Build Coastguard Worker 
Then(CrossThreadTask<void ()> then_callback)450*6777b538SAndroid Build Coastguard Worker     void Then(CrossThreadTask<void()> then_callback) && {
451*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_->PostTaskAndThenHelper(
452*6777b538SAndroid Build Coastguard Worker           *this->location_,
453*6777b538SAndroid Build Coastguard Worker           CrossThreadTraits::BindOnce(
454*6777b538SAndroid Build Coastguard Worker               this->method_, this->sequence_bound_->storage_.GetPtrForBind()),
455*6777b538SAndroid Build Coastguard Worker           std::move(then_callback));
456*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_ = nullptr;
457*6777b538SAndroid Build Coastguard Worker     }
458*6777b538SAndroid Build Coastguard Worker 
459*6777b538SAndroid Build Coastguard Worker    private:
460*6777b538SAndroid Build Coastguard Worker     friend SequenceBound;
461*6777b538SAndroid Build Coastguard Worker 
462*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
463*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
464*6777b538SAndroid Build Coastguard Worker   };
465*6777b538SAndroid Build Coastguard Worker 
466*6777b538SAndroid Build Coastguard Worker   // Selected method has no arguments and returns non-void.
467*6777b538SAndroid Build Coastguard Worker   template <typename MethodRef, typename ReturnType>
468*6777b538SAndroid Build Coastguard Worker   class AsyncCallBuilderImpl<MethodRef, ReturnType, std::tuple<>>
469*6777b538SAndroid Build Coastguard Worker       : public AsyncCallBuilderBase<MethodRef> {
470*6777b538SAndroid Build Coastguard Worker    public:
471*6777b538SAndroid Build Coastguard Worker     // Note: despite being here, this is actually still protected, since it is
472*6777b538SAndroid Build Coastguard Worker     // protected on the base class.
473*6777b538SAndroid Build Coastguard Worker     using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase;
474*6777b538SAndroid Build Coastguard Worker 
~AsyncCallBuilderImpl()475*6777b538SAndroid Build Coastguard Worker     ~AsyncCallBuilderImpl() {
476*6777b538SAndroid Build Coastguard Worker       // Must use Then() since the method's return type is not void.
477*6777b538SAndroid Build Coastguard Worker       // Should be optimized out if the code is bug-free.
478*6777b538SAndroid Build Coastguard Worker       CHECK(!this->sequence_bound_)
479*6777b538SAndroid Build Coastguard Worker           << "Then() not invoked for a method that returns a non-void type; "
480*6777b538SAndroid Build Coastguard Worker           << "make sure to invoke Then() or use base::IgnoreResult()";
481*6777b538SAndroid Build Coastguard Worker     }
482*6777b538SAndroid Build Coastguard Worker 
483*6777b538SAndroid Build Coastguard Worker     template <template <typename> class CallbackType, typename ThenArg>
requires(IsCrossThreadTask<CallbackType>)484*6777b538SAndroid Build Coastguard Worker       requires(IsCrossThreadTask<CallbackType>)
485*6777b538SAndroid Build Coastguard Worker     void Then(CallbackType<void(ThenArg)> then_callback) && {
486*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_->PostTaskAndThenHelper(
487*6777b538SAndroid Build Coastguard Worker           *this->location_,
488*6777b538SAndroid Build Coastguard Worker           CrossThreadTraits::BindOnce(
489*6777b538SAndroid Build Coastguard Worker               this->method_, this->sequence_bound_->storage_.GetPtrForBind()),
490*6777b538SAndroid Build Coastguard Worker           std::move(then_callback));
491*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_ = nullptr;
492*6777b538SAndroid Build Coastguard Worker     }
493*6777b538SAndroid Build Coastguard Worker 
494*6777b538SAndroid Build Coastguard Worker    private:
495*6777b538SAndroid Build Coastguard Worker     friend SequenceBound;
496*6777b538SAndroid Build Coastguard Worker 
497*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
498*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
499*6777b538SAndroid Build Coastguard Worker   };
500*6777b538SAndroid Build Coastguard Worker 
501*6777b538SAndroid Build Coastguard Worker   // Selected method has arguments. Return type can be void or non-void.
502*6777b538SAndroid Build Coastguard Worker   template <typename MethodRef, typename ReturnType, typename... Args>
503*6777b538SAndroid Build Coastguard Worker   class AsyncCallBuilderImpl<MethodRef, ReturnType, std::tuple<Args...>>
504*6777b538SAndroid Build Coastguard Worker       : public AsyncCallBuilderBase<MethodRef> {
505*6777b538SAndroid Build Coastguard Worker    public:
506*6777b538SAndroid Build Coastguard Worker     // Note: despite being here, this is actually still protected, since it is
507*6777b538SAndroid Build Coastguard Worker     // protected on the base class.
508*6777b538SAndroid Build Coastguard Worker     using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase;
509*6777b538SAndroid Build Coastguard Worker 
~AsyncCallBuilderImpl()510*6777b538SAndroid Build Coastguard Worker     ~AsyncCallBuilderImpl() {
511*6777b538SAndroid Build Coastguard Worker       // Must use WithArgs() since the method takes arguments.
512*6777b538SAndroid Build Coastguard Worker       // Should be optimized out if the code is bug-free.
513*6777b538SAndroid Build Coastguard Worker       CHECK(!this->sequence_bound_);
514*6777b538SAndroid Build Coastguard Worker     }
515*6777b538SAndroid Build Coastguard Worker 
516*6777b538SAndroid Build Coastguard Worker     template <typename... BoundArgs>
WithArgs(BoundArgs &&...bound_args)517*6777b538SAndroid Build Coastguard Worker     auto WithArgs(BoundArgs&&... bound_args) {
518*6777b538SAndroid Build Coastguard Worker       const SequenceBound* const sequence_bound =
519*6777b538SAndroid Build Coastguard Worker           std::exchange(this->sequence_bound_, nullptr);
520*6777b538SAndroid Build Coastguard Worker       return AsyncCallWithBoundArgsBuilder<ReturnType>(
521*6777b538SAndroid Build Coastguard Worker           sequence_bound, this->location_,
522*6777b538SAndroid Build Coastguard Worker           CrossThreadTraits::BindOnce(this->method_,
523*6777b538SAndroid Build Coastguard Worker                                       sequence_bound->storage_.GetPtrForBind(),
524*6777b538SAndroid Build Coastguard Worker                                       std::forward<BoundArgs>(bound_args)...));
525*6777b538SAndroid Build Coastguard Worker     }
526*6777b538SAndroid Build Coastguard Worker 
527*6777b538SAndroid Build Coastguard Worker    private:
528*6777b538SAndroid Build Coastguard Worker     friend SequenceBound;
529*6777b538SAndroid Build Coastguard Worker 
530*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
531*6777b538SAndroid Build Coastguard Worker     AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
532*6777b538SAndroid Build Coastguard Worker   };
533*6777b538SAndroid Build Coastguard Worker 
534*6777b538SAndroid Build Coastguard Worker   // `MethodRef` is either a member function pointer type or a member function
535*6777b538SAndroid Build Coastguard Worker   //     pointer type wrapped with `internal::IgnoreResultHelper`.
536*6777b538SAndroid Build Coastguard Worker   // `R` is the return type of `MethodRef`. This is always `void` if
537*6777b538SAndroid Build Coastguard Worker   //     `MethodRef` is an `internal::IgnoreResultHelper` wrapper.
538*6777b538SAndroid Build Coastguard Worker   // `ArgsTuple` is a `std::tuple` with template type arguments corresponding to
539*6777b538SAndroid Build Coastguard Worker   //     the types of the method's parameters.
540*6777b538SAndroid Build Coastguard Worker   template <typename MethodRef, typename R, typename ArgsTuple>
541*6777b538SAndroid Build Coastguard Worker   using AsyncCallBuilder = AsyncCallBuilderImpl<MethodRef, R, ArgsTuple>;
542*6777b538SAndroid Build Coastguard Worker 
543*6777b538SAndroid Build Coastguard Worker   // Support factories when arguments are bound using `WithArgs()`. These
544*6777b538SAndroid Build Coastguard Worker   // factories don't need to handle raw method pointers, since everything has
545*6777b538SAndroid Build Coastguard Worker   // already been packaged into a base::OnceCallback.
546*6777b538SAndroid Build Coastguard Worker   template <typename ReturnType>
547*6777b538SAndroid Build Coastguard Worker   class AsyncCallWithBoundArgsBuilderBase {
548*6777b538SAndroid Build Coastguard Worker    protected:
AsyncCallWithBoundArgsBuilderBase(const SequenceBound * sequence_bound,const Location * location,CrossThreadTask<ReturnType ()> callback)549*6777b538SAndroid Build Coastguard Worker     AsyncCallWithBoundArgsBuilderBase(const SequenceBound* sequence_bound,
550*6777b538SAndroid Build Coastguard Worker                                       const Location* location,
551*6777b538SAndroid Build Coastguard Worker                                       CrossThreadTask<ReturnType()> callback)
552*6777b538SAndroid Build Coastguard Worker         : sequence_bound_(sequence_bound),
553*6777b538SAndroid Build Coastguard Worker           location_(location),
554*6777b538SAndroid Build Coastguard Worker           callback_(std::move(callback)) {
555*6777b538SAndroid Build Coastguard Worker       DCHECK(sequence_bound_);
556*6777b538SAndroid Build Coastguard Worker       DCHECK(!sequence_bound_->storage_.is_null());
557*6777b538SAndroid Build Coastguard Worker     }
558*6777b538SAndroid Build Coastguard Worker 
559*6777b538SAndroid Build Coastguard Worker     // Subtle: the internal helpers rely on move elision. Preventing move
560*6777b538SAndroid Build Coastguard Worker     // elision (e.g. using `std::move()` when returning the temporary) will
561*6777b538SAndroid Build Coastguard Worker     // trigger a `CHECK()` since `sequence_bound_` is not reset to nullptr on
562*6777b538SAndroid Build Coastguard Worker     // move.
563*6777b538SAndroid Build Coastguard Worker     AsyncCallWithBoundArgsBuilderBase(
564*6777b538SAndroid Build Coastguard Worker         AsyncCallWithBoundArgsBuilderBase&&) noexcept = default;
565*6777b538SAndroid Build Coastguard Worker     AsyncCallWithBoundArgsBuilderBase& operator=(
566*6777b538SAndroid Build Coastguard Worker         AsyncCallWithBoundArgsBuilderBase&&) noexcept = default;
567*6777b538SAndroid Build Coastguard Worker 
568*6777b538SAndroid Build Coastguard Worker     raw_ptr<const SequenceBound<T, CrossThreadTraits>> sequence_bound_;
569*6777b538SAndroid Build Coastguard Worker     const raw_ptr<const Location> location_;
570*6777b538SAndroid Build Coastguard Worker     CrossThreadTask<ReturnType()> callback_;
571*6777b538SAndroid Build Coastguard Worker   };
572*6777b538SAndroid Build Coastguard Worker 
573*6777b538SAndroid Build Coastguard Worker   // Note: this doesn't handle a void return type, which has an explicit
574*6777b538SAndroid Build Coastguard Worker   // specialization below.
575*6777b538SAndroid Build Coastguard Worker   template <typename ReturnType>
576*6777b538SAndroid Build Coastguard Worker   class AsyncCallWithBoundArgsBuilderDefault
577*6777b538SAndroid Build Coastguard Worker       : public AsyncCallWithBoundArgsBuilderBase<ReturnType> {
578*6777b538SAndroid Build Coastguard Worker    public:
~AsyncCallWithBoundArgsBuilderDefault()579*6777b538SAndroid Build Coastguard Worker     ~AsyncCallWithBoundArgsBuilderDefault() {
580*6777b538SAndroid Build Coastguard Worker       // Must use Then() since the method's return type is not void.
581*6777b538SAndroid Build Coastguard Worker       // Should be optimized out if the code is bug-free.
582*6777b538SAndroid Build Coastguard Worker       CHECK(!this->sequence_bound_);
583*6777b538SAndroid Build Coastguard Worker     }
584*6777b538SAndroid Build Coastguard Worker 
585*6777b538SAndroid Build Coastguard Worker     template <template <typename> class CallbackType, typename ThenArg>
requires(IsCrossThreadTask<CallbackType>)586*6777b538SAndroid Build Coastguard Worker       requires(IsCrossThreadTask<CallbackType>)
587*6777b538SAndroid Build Coastguard Worker     void Then(CallbackType<void(ThenArg)> then_callback) && {
588*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_->PostTaskAndThenHelper(*this->location_,
589*6777b538SAndroid Build Coastguard Worker                                                    std::move(this->callback_),
590*6777b538SAndroid Build Coastguard Worker                                                    std::move(then_callback));
591*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_ = nullptr;
592*6777b538SAndroid Build Coastguard Worker     }
593*6777b538SAndroid Build Coastguard Worker 
594*6777b538SAndroid Build Coastguard Worker    protected:
595*6777b538SAndroid Build Coastguard Worker     using AsyncCallWithBoundArgsBuilderBase<
596*6777b538SAndroid Build Coastguard Worker         ReturnType>::AsyncCallWithBoundArgsBuilderBase;
597*6777b538SAndroid Build Coastguard Worker 
598*6777b538SAndroid Build Coastguard Worker    private:
599*6777b538SAndroid Build Coastguard Worker     friend SequenceBound;
600*6777b538SAndroid Build Coastguard Worker 
601*6777b538SAndroid Build Coastguard Worker     AsyncCallWithBoundArgsBuilderDefault(
602*6777b538SAndroid Build Coastguard Worker         AsyncCallWithBoundArgsBuilderDefault&&) = default;
603*6777b538SAndroid Build Coastguard Worker     AsyncCallWithBoundArgsBuilderDefault& operator=(
604*6777b538SAndroid Build Coastguard Worker         AsyncCallWithBoundArgsBuilderDefault&&) = default;
605*6777b538SAndroid Build Coastguard Worker   };
606*6777b538SAndroid Build Coastguard Worker 
607*6777b538SAndroid Build Coastguard Worker   class AsyncCallWithBoundArgsBuilderVoid
608*6777b538SAndroid Build Coastguard Worker       : public AsyncCallWithBoundArgsBuilderBase<void> {
609*6777b538SAndroid Build Coastguard Worker    public:
610*6777b538SAndroid Build Coastguard Worker     // Note: despite being here, this is actually still protected, since it is
611*6777b538SAndroid Build Coastguard Worker     // protected on the base class.
612*6777b538SAndroid Build Coastguard Worker     using AsyncCallWithBoundArgsBuilderBase<
613*6777b538SAndroid Build Coastguard Worker         void>::AsyncCallWithBoundArgsBuilderBase;
614*6777b538SAndroid Build Coastguard Worker 
~AsyncCallWithBoundArgsBuilderVoid()615*6777b538SAndroid Build Coastguard Worker     ~AsyncCallWithBoundArgsBuilderVoid() {
616*6777b538SAndroid Build Coastguard Worker       if (this->sequence_bound_) {
617*6777b538SAndroid Build Coastguard Worker         CrossThreadTraits::PostTask(*this->sequence_bound_->impl_task_runner_,
618*6777b538SAndroid Build Coastguard Worker                                     *this->location_,
619*6777b538SAndroid Build Coastguard Worker                                     std::move(this->callback_));
620*6777b538SAndroid Build Coastguard Worker       }
621*6777b538SAndroid Build Coastguard Worker     }
622*6777b538SAndroid Build Coastguard Worker 
Then(CrossThreadTask<void ()> then_callback)623*6777b538SAndroid Build Coastguard Worker     void Then(CrossThreadTask<void()> then_callback) && {
624*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_->PostTaskAndThenHelper(*this->location_,
625*6777b538SAndroid Build Coastguard Worker                                                    std::move(this->callback_),
626*6777b538SAndroid Build Coastguard Worker                                                    std::move(then_callback));
627*6777b538SAndroid Build Coastguard Worker       this->sequence_bound_ = nullptr;
628*6777b538SAndroid Build Coastguard Worker     }
629*6777b538SAndroid Build Coastguard Worker 
630*6777b538SAndroid Build Coastguard Worker    private:
631*6777b538SAndroid Build Coastguard Worker     friend SequenceBound;
632*6777b538SAndroid Build Coastguard Worker 
633*6777b538SAndroid Build Coastguard Worker     AsyncCallWithBoundArgsBuilderVoid(AsyncCallWithBoundArgsBuilderVoid&&) =
634*6777b538SAndroid Build Coastguard Worker         default;
635*6777b538SAndroid Build Coastguard Worker     AsyncCallWithBoundArgsBuilderVoid& operator=(
636*6777b538SAndroid Build Coastguard Worker         AsyncCallWithBoundArgsBuilderVoid&&) = default;
637*6777b538SAndroid Build Coastguard Worker   };
638*6777b538SAndroid Build Coastguard Worker 
639*6777b538SAndroid Build Coastguard Worker   template <typename ReturnType>
640*6777b538SAndroid Build Coastguard Worker   using AsyncCallWithBoundArgsBuilder = typename std::conditional<
641*6777b538SAndroid Build Coastguard Worker       std::is_void_v<ReturnType>,
642*6777b538SAndroid Build Coastguard Worker       AsyncCallWithBoundArgsBuilderVoid,
643*6777b538SAndroid Build Coastguard Worker       AsyncCallWithBoundArgsBuilderDefault<ReturnType>>::type;
644*6777b538SAndroid Build Coastguard Worker 
PostTaskAndThenHelper(const Location & location,CrossThreadTask<void ()> callback,CrossThreadTask<void ()> then_callback)645*6777b538SAndroid Build Coastguard Worker   void PostTaskAndThenHelper(const Location& location,
646*6777b538SAndroid Build Coastguard Worker                              CrossThreadTask<void()> callback,
647*6777b538SAndroid Build Coastguard Worker                              CrossThreadTask<void()> then_callback) const {
648*6777b538SAndroid Build Coastguard Worker     CrossThreadTraits::PostTaskAndReply(*impl_task_runner_, location,
649*6777b538SAndroid Build Coastguard Worker                                         std::move(callback),
650*6777b538SAndroid Build Coastguard Worker                                         std::move(then_callback));
651*6777b538SAndroid Build Coastguard Worker   }
652*6777b538SAndroid Build Coastguard Worker 
653*6777b538SAndroid Build Coastguard Worker   template <typename ReturnType,
654*6777b538SAndroid Build Coastguard Worker             template <typename>
655*6777b538SAndroid Build Coastguard Worker             class CallbackType,
656*6777b538SAndroid Build Coastguard Worker             typename ThenArg>
requires(IsCrossThreadTask<CallbackType>)657*6777b538SAndroid Build Coastguard Worker     requires(IsCrossThreadTask<CallbackType>)
658*6777b538SAndroid Build Coastguard Worker   void PostTaskAndThenHelper(const Location& location,
659*6777b538SAndroid Build Coastguard Worker                              CrossThreadTask<ReturnType()> callback,
660*6777b538SAndroid Build Coastguard Worker                              CallbackType<void(ThenArg)> then_callback) const {
661*6777b538SAndroid Build Coastguard Worker     CrossThreadTask<void(ThenArg)>&& once_then_callback =
662*6777b538SAndroid Build Coastguard Worker         std::move(then_callback);
663*6777b538SAndroid Build Coastguard Worker     CrossThreadTraits::PostTaskAndReplyWithResult(
664*6777b538SAndroid Build Coastguard Worker         *impl_task_runner_, location, std::move(callback),
665*6777b538SAndroid Build Coastguard Worker         std::move(once_then_callback));
666*6777b538SAndroid Build Coastguard Worker   }
667*6777b538SAndroid Build Coastguard Worker 
668*6777b538SAndroid Build Coastguard Worker   // Helper to support move construction and move assignment.
669*6777b538SAndroid Build Coastguard Worker   //
670*6777b538SAndroid Build Coastguard Worker   // TODO(https://crbug.com/1382549): Constrain this so converting between
671*6777b538SAndroid Build Coastguard Worker   // std::unique_ptr<T> and T are explicitly forbidden (rather than simply
672*6777b538SAndroid Build Coastguard Worker   // failing to build in spectacular ways).
673*6777b538SAndroid Build Coastguard Worker   template <typename From>
MoveRecordFrom(From && other)674*6777b538SAndroid Build Coastguard Worker   void MoveRecordFrom(From&& other) {
675*6777b538SAndroid Build Coastguard Worker     impl_task_runner_ = std::move(other.impl_task_runner_);
676*6777b538SAndroid Build Coastguard Worker 
677*6777b538SAndroid Build Coastguard Worker     storage_.TakeFrom(std::move(other.storage_));
678*6777b538SAndroid Build Coastguard Worker   }
679*6777b538SAndroid Build Coastguard Worker 
680*6777b538SAndroid Build Coastguard Worker   Storage storage_;
681*6777b538SAndroid Build Coastguard Worker 
682*6777b538SAndroid Build Coastguard Worker   // Task runner which manages `storage_`. An object owned by `storage_` (if
683*6777b538SAndroid Build Coastguard Worker   // any) will be constructed, destroyed, and otherwise used only on this task
684*6777b538SAndroid Build Coastguard Worker   // runner.
685*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SequencedTaskRunner> impl_task_runner_;
686*6777b538SAndroid Build Coastguard Worker };
687*6777b538SAndroid Build Coastguard Worker 
688*6777b538SAndroid Build Coastguard Worker }  // namespace base
689*6777b538SAndroid Build Coastguard Worker 
690*6777b538SAndroid Build Coastguard Worker #endif  // BASE_THREADING_SEQUENCE_BOUND_H_
691