|  | // Copyright 2014 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_CALLBACK_HELPER_H_ | 
|  | #define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_CALLBACK_HELPER_H_ | 
|  |  | 
|  | #include <functional> | 
|  | #include <memory> | 
|  | #include <type_traits> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/check.h" | 
|  | #include "base/location.h" | 
|  | #include "base/task/sequenced_task_runner.h" | 
|  | #include "base/task/single_thread_task_runner.h" | 
|  |  | 
|  | // TODO(tzik): Merge this file to media/base/bind_to_current_loop.h. | 
|  |  | 
|  | namespace sync_file_system { | 
|  | namespace drive_backend { | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | template <typename Signature, typename... Args> | 
|  | base::OnceClosure MakeClosure(base::RepeatingCallback<Signature>* callback, | 
|  | Args&&... args) { | 
|  | return base::BindOnce(*callback, std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | template <typename Signature, typename... Args> | 
|  | base::OnceClosure MakeClosure(base::OnceCallback<Signature>* callback, | 
|  | Args&&... args) { | 
|  | return base::BindOnce(std::move(*callback), std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | template <typename CallbackType> | 
|  | class CallbackHolder { | 
|  | public: | 
|  | CallbackHolder(const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 
|  | const base::Location& from_here, | 
|  | CallbackType callback) | 
|  | : task_runner_(task_runner), | 
|  | from_here_(from_here), | 
|  | callback_(std::move(callback)) { | 
|  | DCHECK(task_runner_.get()); | 
|  | } | 
|  |  | 
|  | CallbackHolder(const CallbackHolder&) = delete; | 
|  | CallbackHolder& operator=(const CallbackHolder&) = delete; | 
|  |  | 
|  | ~CallbackHolder() { | 
|  | if (callback_) { | 
|  | task_runner_->PostTask(from_here_, | 
|  | base::BindOnce(&CallbackHolder::DeleteCallback, | 
|  | std::move(callback_))); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename... Args> | 
|  | void Run(Args... args) { | 
|  | task_runner_->PostTask( | 
|  | from_here_, MakeClosure(&callback_, std::forward<Args>(args)...)); | 
|  | } | 
|  |  | 
|  | private: | 
|  | static void DeleteCallback(CallbackType callback) {} | 
|  |  | 
|  | scoped_refptr<base::SequencedTaskRunner> task_runner_; | 
|  | const base::Location from_here_; | 
|  | CallbackType callback_; | 
|  | }; | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | template <typename... Args> | 
|  | base::OnceCallback<void(Args...)> RelayCallbackToTaskRunner( | 
|  | const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 
|  | const base::Location& from_here, | 
|  | base::OnceCallback<void(Args...)> callback) { | 
|  | DCHECK(task_runner->RunsTasksInCurrentSequence()); | 
|  |  | 
|  | if (callback.is_null()) | 
|  | return {}; | 
|  |  | 
|  | using CallbackType = base::OnceCallback<void(Args...)>; | 
|  | using HelperType = internal::CallbackHolder<CallbackType>; | 
|  | using RunnerType = void (HelperType::*)(Args...); | 
|  | RunnerType run = &HelperType::Run; | 
|  | return base::BindOnce(run, std::make_unique<HelperType>( | 
|  | task_runner, from_here, std::move(callback))); | 
|  | } | 
|  |  | 
|  | template <typename... Args> | 
|  | base::RepeatingCallback<void(Args...)> RelayCallbackToTaskRunner( | 
|  | const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 
|  | const base::Location& from_here, | 
|  | base::RepeatingCallback<void(Args...)> callback) { | 
|  | DCHECK(task_runner->RunsTasksInCurrentSequence()); | 
|  |  | 
|  | if (callback.is_null()) | 
|  | return {}; | 
|  |  | 
|  | using CallbackType = base::RepeatingCallback<void(Args...)>; | 
|  | using HelperType = internal::CallbackHolder<CallbackType>; | 
|  | using RunnerType = void (HelperType::*)(Args...); | 
|  | RunnerType run = &HelperType::Run; | 
|  | return base::BindRepeating( | 
|  | run, std::make_unique<HelperType>(task_runner, from_here, | 
|  | std::move(callback))); | 
|  | } | 
|  |  | 
|  | template <typename CallbackType> | 
|  | CallbackType RelayCallbackToCurrentThread(const base::Location& from_here, | 
|  | CallbackType callback) { | 
|  | return RelayCallbackToTaskRunner( | 
|  | base::SingleThreadTaskRunner::GetCurrentDefault(), from_here, | 
|  | std::move(callback)); | 
|  | } | 
|  |  | 
|  | }  // namespace drive_backend | 
|  | }  // namespace sync_file_system | 
|  |  | 
|  | #endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_CALLBACK_HELPER_H_ |