Add *Callback::Then() to chain 2 callbacks together
a.Then(b) will return a new callback that when Run() will
1) run |a|
2) run |b|, passing it the return value from a
3) return the result from |b|
OnceCallbacks must be destroyed when joining them together with Then(),
so the method is rvalue-qualified. This means it is used in the
same way as Run(), for example, this function posts two callbacks to
run together as a single task:
void PostTwoTasks(base::OnceClosure c1, base::OnceClosure c2) {
PostTask(std::move(c1).Then(std::move(c2)));
}
RepeatingCallback can be joined destructively via the rvalue-qualified
overload, or non-destructively otherwise. The latter is allowed for a
RepeatingCallback because it is meant to have multiple callers and
therefore having both the original callbacks and the joined callback
pointing to the same underlying functor is not problematic.
[email protected], [email protected]
Bug: 1140582
Change-Id: Ie147f01d1c8adeb5ed34e4933f211e7d247e3c6b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2485642
Commit-Queue: danakj <[email protected]>
Reviewed-by: Gabriel Charette <[email protected]>
Reviewed-by: Chris Hamilton <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Cr-Commit-Position: refs/heads/master@{#820319}
diff --git a/docs/callback.md b/docs/callback.md
index f8c6361..7425239 100644
--- a/docs/callback.md
+++ b/docs/callback.md
@@ -84,6 +84,85 @@
method had been called. Afterward, its `is_null()` method will return true and
its `operator bool()` will return false.
+### Chaining callbacks
+
+When you have 2 callbacks that you wish to run in sequence, they can be joined
+together into a single callback through the use of `Then()`.
+
+Calling `Then()` on a `base::OnceCallback` joins a second callback that will be
+run together with, but after, the first callback. The return value from the
+first callback is passed along to the second, and the return value from the
+second callback is returned at the end. More concretely, calling `a.Then(b)`
+produces a new `base::OnceCallback` that will run `b(a());`, returning the
+result from `b`.
+
+This example uses `Then()` to join 2 `base::OnceCallback`s together:
+```cpp
+int Floor(float f) { return std::floor(f); }
+std::string IntToString(int i) { return base::NumberToString(i); }
+
+base::OnceCallback<int(float)> first = base::BindOnce(&Floor);
+base::OnceCallback<std::string(int)> second = base::BindOnce(&IntToString);
+
+// This will run |first|, run and pass the result to |second|, then return
+// the result from |second|.
+std::string r = std::move(first).Then(std::move(second)).Run(3.5f);
+// |r| will be "3". |first| and |second| are now both null, as they were
+// consumed to perform the join operation.
+```
+
+Similarly, `Then()` also works with `base::RepeatingCallback`; however, the
+joined callback must also be a `base::RepeatingCallback` to ensure the resulting
+callback can be invoked multiple times.
+
+This example uses `Then()` to join 2 `base::RepeatingCallback`s together:
+```cpp
+int Floor(float f) { return std::floor(f); }
+std::string IntToString(int i) { return base::NumberToString(i); }
+
+base::RepeatingCallback<int(float)> first = base::BindRepeating(&Floor);
+base::RepeatingCallback<std::string(int)> second = base::BindRepeating(&IntToString);
+
+// This creates a RepeatingCallback that will run |first|, run and pass the
+// result to |second|, then return the result from |second|.
+base::RepeatingCallback<std::string(float)> joined =
+ std::move(first).Then(std::move(second));
+// |first| and |second| are now both null, as they were consumed to perform
+// the join operation.
+
+// This runs the functor that was originally bound to |first|, then |second|.
+std::string r = joined.Run(3.5);
+// |r| will be "3".
+
+// It's valid to call it multiple times since all callbacks involved are
+// base::RepeatingCallbacks.
+r = joined.Run(2.5);
+// |r| is set to "2".
+```
+
+In the above example, casting the `base::RepeatingCallback` to an r-value with
+`std::move()` causes `Then()` to destroy the original callback, in the same way
+that occurs for joining `base::OnceCallback`s. However since a
+`base::RepeatingCallback` can be run multiple times, it can be joined
+non-destructively as well.
+```cpp
+int Floor(float f) { return std::floor(f); }
+std::string IntToString(int i) { return base::NumberToString(i); }
+
+base::RepeatingCallback<int(float)> first = base::BindRepeating(&Floor);
+base::RepeatingCallback<std::string(int)> second = base::BindRepeating(&IntToString);
+
+// This creates a RepeatingCallback that will run |first|, run and pass the
+// result to |second|, then return the result from |second|.
+std::string r = first.Then(second).Run(3.5f);
+// |r| will be 3, and |first| and |second| are still valid to use.
+
+// Runs Floor().
+int i = first.Run(5.5);
+// Runs IntToString().
+std::string s = second.Run(9);
+```
+
## Quick reference for basic stuff
### Binding A Bare Function