| 229 | |
| 230 | template <typename T, typename FT = Future<T>, typename FTSync = typename FT::SyncType> |
| 231 | Future<T> DoTransfer(Future<T> future, bool always_transfer = false) { |
| 232 | auto transferred = Future<T>::Make(); |
| 233 | if (always_transfer) { |
| 234 | CallbackOptions callback_options = CallbackOptions::Defaults(); |
| 235 | callback_options.should_schedule = ShouldSchedule::Always; |
| 236 | callback_options.executor = this; |
| 237 | auto sync_callback = [transferred](const FTSync& result) mutable { |
| 238 | transferred.MarkFinished(result); |
| 239 | }; |
| 240 | future.AddCallback(sync_callback, callback_options); |
| 241 | return transferred; |
| 242 | } |
| 243 | |
| 244 | // We could use AddCallback's ShouldSchedule::IfUnfinished but we can save a bit of |
| 245 | // work by doing the test here. |
| 246 | auto callback = [this, transferred](const FTSync& result) mutable { |
| 247 | auto spawn_status = |
| 248 | Spawn([transferred, result]() mutable { transferred.MarkFinished(result); }); |
| 249 | if (!spawn_status.ok()) { |
| 250 | transferred.MarkFinished(spawn_status); |
| 251 | } |
| 252 | }; |
| 253 | auto callback_factory = [&callback]() { return callback; }; |
| 254 | if (future.TryAddCallback(callback_factory)) { |
| 255 | return transferred; |
| 256 | } |
| 257 | // If the future is already finished and we aren't going to force spawn a thread |
| 258 | // then we don't need to add another layer of callback and can return the original |
| 259 | // future |
| 260 | return future; |
| 261 | } |
| 262 | |
| 263 | // Subclassing API |
| 264 | virtual Status SpawnReal(TaskHints hints, FnOnce<void()> task, StopToken, |
no test coverage detected