Commit 788a3897 authored by danakj's avatar danakj Committed by Commit Bot

Allow chaining OnceCallback.Then(RepeatingCallback).

Because the input type to OnceCallback::Then() is a templated type as
OnceCallback<U>, a RepeatingCallback does not bind and implicitly
convert to a OnceCallback. This is because templated pattern matching
does not try conversions, so it must match exactly.

Add an overload of OnceCallback::Then() to receive a RepeatingCallback
and cast it explicitly to a OnceCallback, forwarding it on to the
original Then() method.

R=dcheng@chromium.org

Bug: 1140582
Change-Id: Ib571eb361922588a3f200e6aea5c045aad0f72d7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2510411
Commit-Queue: danakj <danakj@chromium.org>
Auto-Submit: danakj <danakj@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#822850}
parent ac1536f9
......@@ -125,6 +125,13 @@ class OnceCallback<R(Args...)> : public internal::CallbackBase {
internal::ThenHelper<OnceCallback, OnceCallback<U>, R, Args...>(),
std::move(*this), std::move(then));
}
template <typename U, typename R2 = internal::ExtractReturnType<U>>
OnceCallback<R2(Args...)> Then(RepeatingCallback<U> then) && {
// RepeatingCallback can convert to OnceCallback, but it does not implicitly
// convert to OnceCallback<U> for the above method, so we have to do that
// explicitly here.
return std::move(*this).Then(static_cast<OnceCallback<U>>(std::move(then)));
}
};
template <typename R, typename... Args>
......
......@@ -204,6 +204,35 @@ TEST_F(CallbackTest, ThenResetsOriginalCallback) {
}
}
// A RepeatingCallback will implicitly convert to a OnceCallback, so a
// once_callback.Then(repeating_callback) should turn into a OnceCallback
// that holds 2 OnceCallbacks which it will run.
TEST_F(CallbackTest, ThenCanConvertRepeatingToOnce) {
{
RepeatingClosure repeating_closure = base::BindRepeating([]() {});
OnceClosure once_closure = base::BindOnce([]() {});
std::move(once_closure).Then(repeating_closure).Run();
RepeatingCallback<int(int)> repeating_callback =
base::BindRepeating([](int i) { return i + 1; });
OnceCallback<int(int)> once_callback =
base::BindOnce([](int i) { return i * 2; });
EXPECT_EQ(3, std::move(once_callback).Then(repeating_callback).Run(1));
}
{
RepeatingClosure repeating_closure = base::BindRepeating([]() {});
OnceClosure once_closure = base::BindOnce([]() {});
std::move(once_closure).Then(std::move(repeating_closure)).Run();
RepeatingCallback<int(int)> repeating_callback =
base::BindRepeating([](int i) { return i + 1; });
OnceCallback<int(int)> once_callback =
base::BindOnce([](int i) { return i * 2; });
EXPECT_EQ(
3, std::move(once_callback).Then(std::move(repeating_callback)).Run(1));
}
}
// A factory class for building an outer and inner callback for calling
// Then() on either a OnceCallback or RepeatingCallback with combinations of
// void return types, non-void, and move-only return types.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment