diff --git a/lix/libutil/async.hh b/lix/libutil/async.hh index 453e65df1..5dfd6e33c 100644 --- a/lix/libutil/async.hh +++ b/lix/libutil/async.hh @@ -7,8 +7,10 @@ #include #include #include +#include #include #include +#include namespace nix { @@ -33,6 +35,34 @@ struct AsyncContext } KJ_DISALLOW_COPY_AND_MOVE(AsyncContext); + + /** + * Wrap a promise in a timeout. `Result` promises are turned into + * `Result` promises, where `true` means that the wrapped promise + * ran to completion and `false` means it timed out. Other promises are + * wrapped to return `Result>` and return `nullopt` if + * the have time out or wrap their inner type as an optional otherwise. + */ + template + auto timeoutAfter(kj::Duration timeout, kj::Promise> && p) + { + using RetT = std::conditional_t, bool, std::optional>; + return p + .then([](Result r) -> Result { + if (r.has_value()) { + if constexpr (std::is_void_v) { + return true; + } else { + return std::move(r.value()); + } + } else { + return r.error(); + } + }) + .exclusiveJoin(provider.getTimer().afterDelay(timeout).then([]() -> Result { + return RetT{}; + })); + } }; struct AsyncIoRoot