From 734cfd1d48b731f16fca01403656c59a072703d9 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Tue, 30 Jun 2026 15:22:17 +0200 Subject: [PATCH] libutil/rpc: add more filler macros for rpc conversions sometimes we need to disambiguate based on the kind of the thing we are filling due to how the c++ type works. in templates some constraints on type resolution are lifted. sometimes we can make the compiler help us. Co-authored-by: piegames Change-Id: Id9549764813a862b8d64959157fed258709eb6ac --- lix/libutil/rpc.hh | 57 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/lix/libutil/rpc.hh b/lix/libutil/rpc.hh index 2d3efb91f..0c8f7fc69 100644 --- a/lix/libutil/rpc.hh +++ b/lix/libutil/rpc.hh @@ -169,10 +169,14 @@ inline void doFill(auto && builder, Inner (Builder::*field)(), From && f, auto & // lists and other primitives. lists must be distinguished by having builders. template + requires requires { + requires std::same_as; + typename Inner::Builds; + } || std::convertible_to inline void doFill(auto && builder, Inner (Builder::*field)(Init), From && f, auto &&... args) { if constexpr (requires { - std::same_as; + requires std::same_as; typename Inner::Builds; }) { @@ -183,10 +187,57 @@ inline void doFill(auto && builder, Inner (Builder::*field)(Init), From && f, au (builder.*field)(std::forward(f)); } } + +template +inline constexpr bool IsRpcListV = false; +template +inline constexpr bool IsRpcListV> = true; + +template +concept RpcList = IsRpcListV; } #define LIX_RPC_FILL(fobj, ffield, fsource, ...) \ - [&] { ::nix::rpc::detail::doFill(fobj, &decltype(fobj)::ffield, (fsource), ##__VA_ARGS__); }() + (::nix::rpc::detail::doFill(fobj, &decltype(fobj)::ffield, (fsource), ##__VA_ARGS__)) + +#define LIX_RPC_FILL_LIST(fobj, ffield, fsource, ...) \ + (::nix::rpc::detail::doFill( \ + fobj, \ + ([](Inner (Builder::*field)(Init)) { \ + return field; \ + })(&decltype(fobj)::ffield), \ + (fsource), \ + ##__VA_ARGS__ \ + )) + +#define LIX_RPC_FILL_STRUCT(fobj, ffield, fsource, ...) \ + (::nix::rpc::detail::doFill( \ + fobj, \ + ([](Inner (Builder::*field)()) { \ + return field; \ + })(&decltype(fobj)::ffield), \ + (fsource), \ + ##__VA_ARGS__ \ + )) + +// set a value regardless of its kind. *only* use this in templates or it'll fail to compile. +#define LIX_RPC_FILL_GENERIC_DEPENDENT(fobj, ffield, fsource, ...) \ + ({ \ + if constexpr (requires { \ + requires ::nix::rpc::detail::RpcList< \ + typename decltype(fobj.get##ffield())::Builds>; \ + }) \ + { \ + LIX_RPC_FILL_LIST(fobj, init##ffield, (fsource), ##__VA_ARGS__); \ + } else if constexpr (requires { \ + { LIX_RPC_FILL(fobj, set##ffield, (fsource), ##__VA_ARGS__) }; \ + }) \ + { \ + LIX_RPC_FILL(fobj, set##ffield, (fsource), ##__VA_ARGS__); \ + } else { \ + LIX_RPC_FILL_STRUCT(fobj, init##ffield, (fsource), ##__VA_ARGS__); \ + } \ + }) namespace detail { std::exception_ptr unwrapErrorRaw(kj::Exception & e, std::source_location loc); @@ -250,6 +301,8 @@ inline void rethrow_as_rpc_error() #ifdef LIX_UR_COMPILER_UWU #define RPC_FILL LIX_RPC_FILL +#define RPC_FILL_LIST LIX_RPC_FILL_LIST +#define RPC_FILL_STRUCT LIX_RPC_FILL_STRUCT #define TRY_AWAIT_RPC_NOEXCEPT LIX_TRY_AWAIT_RPC_NOEXCEPT #define TRY_AWAIT_RPC_V1 LIX_TRY_AWAIT_RPC_V1 #define TRY_AWAIT_RPC LIX_TRY_AWAIT_RPC_V1