1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef REMOTING_BASE_TASK_UTIL_H_
6 #define REMOTING_BASE_TASK_UTIL_H_
7 
8 #include "base/bind.h"
9 #include "base/threading/sequence_bound.h"
10 #include "base/threading/sequenced_task_runner_handle.h"
11 
12 namespace remoting {
13 
14 // Wraps and returns a callback such that it will call the original callback on
15 // the thread where this method is called.
16 template <typename... Args>
WrapCallbackToCurrentSequence(const base::Location & from_here,base::OnceCallback<void (Args...)> callback)17 base::OnceCallback<void(Args...)> WrapCallbackToCurrentSequence(
18     const base::Location& from_here,
19     base::OnceCallback<void(Args...)> callback) {
20   return base::BindOnce(
21       [](scoped_refptr<base::SequencedTaskRunner> task_runner,
22          const base::Location& from_here,
23          base::OnceCallback<void(Args...)> callback, Args... args) {
24         base::OnceClosure closure =
25             base::BindOnce(std::move(callback), std::forward<Args>(args)...);
26         if (task_runner->RunsTasksInCurrentSequence()) {
27           std::move(closure).Run();
28           return;
29         }
30         task_runner->PostTask(from_here, std::move(closure));
31       },
32       base::SequencedTaskRunnerHandle::Get(), from_here, std::move(callback));
33 }
34 
35 // Similar to base::SequenceBound::Post, but executes the callback (which should
36 // be the last method argument) on the sequence where the task is posted from.
37 // Say if you want to call this method and make |callback| run on the current
38 // sequence:
39 //
40 //   client_.Post(FROM_HERE, &DirectoryClient::DeleteHost, host_id, callback);
41 //
42 // You can just do:
43 //
44 //   PostWithCallback(FROM_HERE, &client_, &DirectoryClient::DeleteHost,
45 //                    callback, host_id);
46 //
47 // Note that |callback| is moved before other arguments, as type deduction does
48 // not work the other way around.
49 //
50 // Also you should probably bind a WeakPtr in your callback rather than using
51 // base::Unretained, since the underlying sequence bound object will generally
52 // be deleted after the owning object.
53 template <typename SequenceBoundType,
54           typename... MethodArgs,
55           typename... Args,
56           typename... CallbackArgs>
PostWithCallback(const base::Location & from_here,base::SequenceBound<SequenceBoundType> * client,void (SequenceBoundType::* method)(MethodArgs...),base::OnceCallback<void (CallbackArgs...)> callback,Args &&...args)57 void PostWithCallback(const base::Location& from_here,
58                       base::SequenceBound<SequenceBoundType>* client,
59                       void (SequenceBoundType::*method)(MethodArgs...),
60                       base::OnceCallback<void(CallbackArgs...)> callback,
61                       Args&&... args) {
62   client->Post(from_here, method, std::forward<Args>(args)...,
63                WrapCallbackToCurrentSequence(from_here, std::move(callback)));
64 }
65 
66 }  // namespace remoting
67 
68 #endif  // REMOTING_BASE_TASK_UTIL_H_
69