summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/callback_internal.h5
-rw-r--r--base/task_runner_util.h3
-rw-r--r--base/task_runner_util_unittest.cc37
3 files changed, 43 insertions, 2 deletions
diff --git a/base/callback_internal.h b/base/callback_internal.h
index 244504b..92ea80a 100644
--- a/base/callback_internal.h
+++ b/base/callback_internal.h
@@ -166,6 +166,11 @@ struct CallbackParamTraits<ScopedVector<T> > {
// In C++11, std::forward would replace all uses of this function. However, it
// is impossible to implement a general std::forward with C++11 due to a lack
// of rvalue references.
+//
+// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
+// simulate std::forward() and forward the result of one Callback as a
+// parameter to another callback. This is to support Callbacks that return
+// the movable-but-not-copyable types whitelisted above.
template <typename T>
T& CallbackForward(T& t) { return t; }
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
index 9d20ef2..67e223e 100644
--- a/base/task_runner_util.h
+++ b/base/task_runner_util.h
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
#include "base/logging.h"
#include "base/task_runner.h"
@@ -37,7 +38,7 @@ void ReplyAdapter(const Callback<void(ReturnType)>& callback,
ReturnType* result) {
DCHECK(result);
if(!callback.is_null())
- callback.Run(*result);
+ callback.Run(CallbackForward(*result));
}
// Helper class for TaskRunner::PostTaskAndReplyWithResult.
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
index 4c58826..daed770 100644
--- a/base/task_runner_util_unittest.cc
+++ b/base/task_runner_util_unittest.cc
@@ -20,9 +20,28 @@ void StoreValue(int* destination, int value) {
*destination = value;
}
+int g_foo_destruct_count = 0;
+
+struct Foo {
+ ~Foo() {
+ ++g_foo_destruct_count;
+ }
+};
+
+scoped_ptr<Foo> CreateFoo() {
+ return scoped_ptr<Foo>(new Foo);
+}
+
+void ExpectFoo(scoped_ptr<Foo> foo) {
+ EXPECT_TRUE(foo.get());
+ scoped_ptr<Foo> local_foo(foo.Pass());
+ EXPECT_TRUE(local_foo.get());
+ EXPECT_FALSE(foo.get());
+}
+
} // namespace
-TEST(TaskRunnerHelpersTest, PostAndReplyWithStatus) {
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) {
MessageLoop message_loop;
int result = 0;
@@ -37,4 +56,20 @@ TEST(TaskRunnerHelpersTest, PostAndReplyWithStatus) {
EXPECT_EQ(42, result);
}
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassed) {
+ g_foo_destruct_count = 0;
+
+ MessageLoop message_loop;
+
+ PostTaskAndReplyWithResult(
+ message_loop.message_loop_proxy(),
+ FROM_HERE,
+ Bind(&CreateFoo),
+ Bind(&ExpectFoo));
+
+ message_loop.RunAllPending();
+
+ EXPECT_EQ(1, g_foo_destruct_count);
+}
+
} // namespace base