From df45583c7a7621e7995a17b2902fa25944b5d716 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Mon, 14 Jul 2025 17:17:12 +0200 Subject: [PATCH] libutil: add AsyncContext::timeoutAfter this is just a Result-aware version of kj's Timer::timeoutAfter. Change-Id: I17ff77d40201996b9dafc32bbff0298db8a4fcc9 --- lix/libutil/async.hh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) 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