summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync_file_system/drive_backend/callback_helper.h
blob: 8d524d477642aef79caa646d395d231bb8e4e782 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/thread_task_runner_handle.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 T>
typename base::enable_if<
    base::internal::IsMoveOnlyType<T>::value,
    base::internal::PassedWrapper<T> >::type
RebindForward(T& t) {
  return base::Passed(&t);
}

template <typename T>
typename base::enable_if<
    !base::internal::IsMoveOnlyType<T>::value,
    T&>::type
RebindForward(T& t) {
  return t;
}

template <typename T>
class CallbackHolder {
 public:
  CallbackHolder(const scoped_refptr<base::SequencedTaskRunner>& task_runner,
                 const tracked_objects::Location& from_here,
                 const base::Callback<T>& callback)
      : task_runner_(task_runner),
        from_here_(from_here),
        callback_(new base::Callback<T>(callback)) {
    DCHECK(task_runner_.get());
  }

  ~CallbackHolder() {
    base::Callback<T>* callback = callback_.release();
    if (!task_runner_->DeleteSoon(from_here_, callback))
      delete callback;
  }

  base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); }
  const tracked_objects::Location& from_here() const { return from_here_; }
  const base::Callback<T>& callback() const { return *callback_; }

 private:
  scoped_refptr<base::SequencedTaskRunner> task_runner_;
  const tracked_objects::Location from_here_;
  scoped_ptr<base::Callback<T> > callback_;

  DISALLOW_COPY_AND_ASSIGN(CallbackHolder);
};

template <typename>
struct RelayToTaskRunnerHelper;

template <typename... Args>
struct RelayToTaskRunnerHelper<void(Args...)> {
  static void Run(CallbackHolder<void(Args...)>* holder, Args... args) {
    holder->task_runner()->PostTask(
        holder->from_here(),
        base::Bind(holder->callback(),
                   RebindForward(args)...));
  }
};

}  // namespace internal

template <typename T>
base::Callback<T> RelayCallbackToTaskRunner(
    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
    const tracked_objects::Location& from_here,
    const base::Callback<T>& callback) {
  DCHECK(task_runner->RunsTasksOnCurrentThread());

  if (callback.is_null())
    return base::Callback<T>();

  return base::Bind(&internal::RelayToTaskRunnerHelper<T>::Run,
                    base::Owned(new internal::CallbackHolder<T>(
                        task_runner, from_here, callback)));
}

template <typename T>
base::Callback<T> RelayCallbackToCurrentThread(
    const tracked_objects::Location& from_here,
    const base::Callback<T>& callback) {
  return RelayCallbackToTaskRunner(
      base::ThreadTaskRunnerHandle::Get(),
      from_here, callback);
}

}  // namespace drive_backend
}  // namespace sync_file_system

#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_CALLBACK_HELPER_H_