diff --git a/WORKSPACE b/WORKSPACE index 0ad7c4f81d4..e43598b5850 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -35,10 +35,10 @@ rules_foreign_cc_dependencies() http_archive( name = "capnp-cpp", - sha256 = "0cb62c35736ab4202a3e2f245ef4ac34549b209cb79e070711e42293fc4daf1c", - strip_prefix = "capnproto-capnproto-253c18f/c++", + sha256 = "7ccdf8eeed127d439bc8a94d5742f87d3e5e305f13c3bbb2797005eb6705bf98", + strip_prefix = "capnproto-capnproto-d0e3946/c++", type = "tgz", - urls = ["https://github.com/capnproto/capnproto/tarball/253c18fc6d8e21bb1114c720ab778fc397115c41"], + urls = ["https://github.com/capnproto/capnproto/tarball/d0e3946787b635c7196ded373ae867642e0cf5c7"], ) http_archive( diff --git a/src/workerd/io/worker.c++ b/src/workerd/io/worker.c++ index 794946f322c..3373174fe1e 100644 --- a/src/workerd/io/worker.c++ +++ b/src/workerd/io/worker.c++ @@ -2802,7 +2802,8 @@ bool Worker::Actor::hasAlarmHandler() { kj::Promise Worker::Actor::makeAlarmTaskForPreview(kj::Date scheduledTime) { auto& context = IoContext::current(); - auto retry = coCapture([this, originalTime = scheduledTime](auto runAlarmFunc) -> kj::Promise { + auto retry = kj::coCapture([this, originalTime = scheduledTime](auto runAlarmFunc) + -> kj::Promise { kj::Date scheduledTime = originalTime; for(auto i : kj::zeroTo(WorkerInterface::ALARM_RETRY_MAX_TRIES)) { diff --git a/src/workerd/util/co-capture-test.c++ b/src/workerd/util/co-capture-test.c++ deleted file mode 100644 index 761fbedc462..00000000000 --- a/src/workerd/util/co-capture-test.c++ +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2017-2022 Cloudflare, Inc. -// Licensed under the Apache 2.0 license found in the LICENSE file or at: -// https://opensource.org/licenses/Apache-2.0 - -#include "co-capture.h" - -#include -#include - -#include -#include - -namespace workerd { -namespace { - -std::random_device randomDevice; -std::mt19937 randomIterator(randomDevice()); - -KJ_TEST("Verify coCapture() functors can only be run once") { - auto io = kj::setupAsyncIo(); - - auto functor = coCapture([](kj::Timer& timer) -> kj::Promise { - co_await timer.afterDelay(1 * kj::MILLISECONDS); - }); - - auto promise = functor(io.lowLevelProvider->getTimer()); - KJ_EXPECT_THROW(FAILED, functor(io.lowLevelProvider->getTimer())); - - promise.wait(io.waitScope); -} - -auto makeDelayedIntegerFunctor(size_t i) { - return [i](kj::Timer& timer) -> kj::Promise { - co_await timer.afterDelay(1 * kj::MILLISECONDS); - co_return i; - }; -} - -KJ_TEST("Verify coCapture() with local scoped functors") { - auto io = kj::setupAsyncIo(); - - constexpr size_t COUNT = 100; - kj::Vector> promises; - for (size_t i = 0; i < COUNT; ++i) { - auto functor = coCapture(makeDelayedIntegerFunctor(i)); - promises.add(functor(io.lowLevelProvider->getTimer())); - } - - for (size_t i = COUNT; i > 0 ; --i) { - auto j = i-1; - auto result = promises[j].wait(io.waitScope); - KJ_REQUIRE(result == j); - } -} - -auto makeCheckThenDelayedIntegerFunctor(kj::Timer& timer, size_t i) { - return [&timer, i](size_t val) -> kj::Promise { - KJ_REQUIRE(val == i); - co_await timer.afterDelay(1 * kj::MILLISECONDS); - co_return i; - }; -} - -KJ_TEST("Verify coCapture() with continuation functors") { - // This test usually works locally without `coCapture()()`. It does however, fail in - // ASAN. - auto io = kj::setupAsyncIo(); - - constexpr size_t COUNT = 100; - kj::Vector> promises; - for (size_t i = 0; i < COUNT; ++i) { - auto promise = io.lowLevelProvider->getTimer().afterDelay(1 * kj::MILLISECONDS).then([i]() { - return i; - }); - promise = promise.then(coCapture( - makeCheckThenDelayedIntegerFunctor(io.lowLevelProvider->getTimer(), i))); - promises.add(kj::mv(promise)); - } - - for (size_t i = COUNT; i > 0 ; --i) { - auto j = i-1; - auto result = promises[j].wait(io.waitScope); - KJ_REQUIRE(result == j); - } -} - -} -} diff --git a/src/workerd/util/co-capture.h b/src/workerd/util/co-capture.h deleted file mode 100644 index dd9b51fbb85..00000000000 --- a/src/workerd/util/co-capture.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2017-2022 Cloudflare, Inc. -// Licensed under the Apache 2.0 license found in the LICENSE file or at: -// https://opensource.org/licenses/Apache-2.0 - -#pragma once - -#include -#include - -namespace workerd { - -namespace _ { -template -struct CaptureForCoroutine { - kj::Maybe maybeFunctor; - - explicit CaptureForCoroutine(Functor&& f) : maybeFunctor(kj::mv(f)) {} - - template - using ReturnType = std::invoke_result_t; - - template - static auto coInvoke(Functor functor, Args&&... args) -> ReturnType { - // Since the functor is now in the local scope and no longer a member variable, it will be - // persisted in the coroutine state. - - // Note that `co_await localFunctor(...)` can still return `void`. It just happens that - // `co_return voidReturn();` is explicitly allowed. - co_return co_await functor(kj::fwd(args)...); - } - - template - auto operator()(Args&&... args) { - auto localFunctor = kj::mv(KJ_REQUIRE_NONNULL( - maybeFunctor, "Attempted to invoke CaptureForCoroutine functor multiple times")); - maybeFunctor = nullptr; - return coInvoke(kj::mv(localFunctor), kj::fwd(args)...); - } -}; -} // namespace _ - -template -auto coCapture(Functor&& f) { - // Wrap a functor with a lambda that stores it on the heap, invokes it, and then attaches the - // functor to the result promise. - // - // This function is meant to help address this pain point with functors that return a coroutine: - // https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cp51-do-not-use-capturing-lambdas-that-are-coroutines - // - // The two most common patterns where this may be useful look like so: - // ``` - // void addTask(Value myValue) { - // auto myFun = [myValue]() -> kj::Promise { - // ... - // co_return; - // }; - // tasks.add(myFun()); - // } - // ``` - // and - // ``` - // kj::Promise afterPromise(kj::Promise promise, Value myValue) { - // auto myFun = [myValue]() -> kj::Promise { - // ... - // co_return; - // }; - // return promise.then(kj::mv(myFun)); - // } - // ``` - // - // Note that there are potentially more optimal alternatives to both of these patterns: - // ``` - // void addTask(Value myValue) { - // auto myFun = [](auto myValue) -> kj::Promise { - // ... - // co_return; - // }; - // tasks.add(myFun(myValue)); - // } - // ``` - // and - // ``` - // kj::Promise afterPromise(kj::Promise promise, Value myValue) { - // auto myFun = [&]() -> kj::Promise { - // ... - // co_return; - // }; - // co_await promise; - // co_await myFun(); - // co_return; - // } - // ``` - // - // For situations where you are trying to capture a specific local variable, kj::mvCapture() can - // also be useful: - // ``` - // kj::Promise reactToPromise(kj::Promise promise) { - // BigA a; - // TinyB b; - // - // doSomething(a, b); - // return promise.then(kj::mvCapture(b, [](TinyB b, MyType type) -> kj::Promise { - // ... - // co_return; - // }); - // } - // ``` - - return _::CaptureForCoroutine(kj::mv(f)); -} - -} // namespace workerd