libutil/rpc-types: Add map type
Co-authored-by: piegames <git@piegames.de> Change-Id: I4215efb0e9839925d34ad45d47879148dbdfc4c2
This commit is contained in:
co-authored by
piegames
parent
7307475218
commit
0e180a479f
@@ -152,6 +152,91 @@ inline auto from(const O & r, Args &&... args)
|
||||
return r.isSome() ? std::optional<To>{std::in_place, from(r.getSome(), args...)} : std::nullopt;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template<typename>
|
||||
struct MapArgsT;
|
||||
template<typename Key, typename Value>
|
||||
struct MapArgsT<Map<Key, Value>>
|
||||
{
|
||||
using key = Key;
|
||||
using value = Value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using MapKey = typename MapArgsT<T>::key;
|
||||
template<typename T>
|
||||
using MapValue = typename MapArgsT<T>::value;
|
||||
|
||||
template<typename T>
|
||||
concept MapT = requires { MapArgsT<T>{}; };
|
||||
template<typename T>
|
||||
concept MapReaderT = MapT<typename T::Reads>;
|
||||
|
||||
template<typename T>
|
||||
concept CxxMapT = requires(T map) {
|
||||
typename T::key_type;
|
||||
typename T::mapped_type;
|
||||
// disallow multimaps
|
||||
{
|
||||
map.emplace(std::declval<typename T::key_type>(), std::declval<typename T::mapped_type>())
|
||||
} -> std::same_as<std::pair<typename T::iterator, bool>>;
|
||||
};
|
||||
}
|
||||
|
||||
template<detail::MapT RpcMap, detail::CxxMapT CxxMap>
|
||||
struct Convert<RpcMap, CxxMap>
|
||||
{
|
||||
using NixKey = typename CxxMap::key_type;
|
||||
using NixValue = typename CxxMap::mapped_type;
|
||||
|
||||
template<typename... Args>
|
||||
requires requires(RpcMap::Entry::Reader r, Args... args) {
|
||||
to<NixKey>(r.getKey(), args...);
|
||||
to<NixValue>(r.getValue(), args...);
|
||||
}
|
||||
static CxxMap convert(const RpcMap::Reader & m, Args &&... args)
|
||||
{
|
||||
CxxMap result;
|
||||
for (auto && e : m.getEntries()) {
|
||||
result.emplace(to<NixKey>(e.getKey(), args...), to<NixValue>(e.getValue(), args...));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<detail::MapT RpcMap, detail::CxxMapT CxxMap>
|
||||
struct Fill<RpcMap, CxxMap>
|
||||
{
|
||||
template<typename... Args>
|
||||
static void fill(RpcMap::Builder builder, const CxxMap & from, Args &&... args)
|
||||
{
|
||||
auto entries = builder.initEntries(from.size());
|
||||
size_t i = 0;
|
||||
for (auto & [k, v] : from) {
|
||||
LIX_RPC_FILL_GENERIC_DEPENDENT(entries[i], Key, k, args...);
|
||||
LIX_RPC_FILL_GENERIC_DEPENDENT(entries[i], Value, v, args...);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<detail::MapReaderT Map, typename... Args>
|
||||
requires requires(Map::Reads::Entry::Reader r, Args... args) {
|
||||
from(r.getKey(), args...);
|
||||
from(r.getValue(), args...);
|
||||
}
|
||||
auto from(const Map & m, Args &&... args)
|
||||
{
|
||||
std::map<
|
||||
decltype(from(m.getEntries().begin()->getKey(), args...)),
|
||||
decltype(from(m.getEntries().begin()->getValue(), args...))>
|
||||
result;
|
||||
for (auto && e : m.getEntries()) {
|
||||
result.emplace(from(e.getKey(), args...), from(e.getValue(), args...));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace error::v1 {
|
||||
std::string encodeLossy(const ::nix::ErrorInfo & e);
|
||||
std::optional<::nix::ErrorInfo> tryDecode(std::string_view source);
|
||||
|
||||
@@ -61,6 +61,16 @@ struct OptionInt64 {
|
||||
}
|
||||
}
|
||||
|
||||
struct Map(Key, Value) {
|
||||
# if this list contains multiple entries with the same key the *first* entry of each
|
||||
# such subsequence must be used. all other entries MUST still be read and validated.
|
||||
entries @0 :List(Entry);
|
||||
struct Entry {
|
||||
key @0 :Key;
|
||||
value @1 :Value;
|
||||
}
|
||||
}
|
||||
|
||||
struct Settings {
|
||||
struct Setting {
|
||||
name @0 :Data;
|
||||
|
||||
@@ -53,6 +53,60 @@ TEST(RpcConverters, DISABLED_optionConvertersCompile)
|
||||
);
|
||||
}
|
||||
|
||||
TEST(RpcConverters, DISABLED_mapConvertersCompile)
|
||||
{
|
||||
using namespace rpc;
|
||||
|
||||
// primitive args
|
||||
RPC_FILL_STRUCT(
|
||||
(Option<Map<OptionInt64, OptionInt64>>::Builder{nullptr}),
|
||||
initSome,
|
||||
(std::map<std::optional<int64_t>, std::optional<int64_t>>{})
|
||||
);
|
||||
static_assert(std::same_as<
|
||||
decltype(from(Map<OptionInt64, OptionInt64>::Reader{})),
|
||||
std::map<std::optional<int64_t>, std::optional<int64_t>>>);
|
||||
|
||||
// string args
|
||||
RPC_FILL_STRUCT(
|
||||
(Option<Map<capnp::Data, capnp::Data>>::Builder{nullptr}),
|
||||
initSome,
|
||||
(std::map<std::string, std::string>{})
|
||||
);
|
||||
static_assert(std::same_as<
|
||||
decltype(to<std::map<std::string, std::string>>(Map<capnp::Data, capnp::Data>::Reader{})),
|
||||
std::map<std::string, std::string>>);
|
||||
static_assert(std::same_as<
|
||||
decltype(to<std::map<std::string_view, std::string_view>>(
|
||||
Map<capnp::Data, capnp::Data>::Reader{}
|
||||
)),
|
||||
std::map<std::string_view, std::string_view>>);
|
||||
|
||||
// struct args
|
||||
RPC_FILL_STRUCT(
|
||||
(Option<Map<Option<OptionInt64>, Option<OptionInt64>>>::Builder{nullptr}),
|
||||
initSome,
|
||||
(std::map<std::optional<std::optional<int64_t>>, std::optional<std::optional<int64_t>>>{})
|
||||
);
|
||||
static_assert(std::same_as<
|
||||
decltype(from(Map<Option<OptionInt64>, Option<rpc::Error>>::Reader{})),
|
||||
std::map<std::optional<std::optional<int64_t>>, std::optional<ErrorInfo>>>);
|
||||
|
||||
// nested args
|
||||
RPC_FILL_STRUCT(
|
||||
(Option<Map<Map<OptionInt64, OptionInt64>, Map<OptionInt64, OptionInt64>>>::Builder{nullptr}),
|
||||
initSome,
|
||||
(std::map<
|
||||
std::map<std::optional<int64_t>, std::optional<int64_t>>,
|
||||
std::map<std::optional<int64_t>, std::optional<int64_t>>>{})
|
||||
);
|
||||
static_assert(std::same_as<
|
||||
decltype(from(Map<Map<OptionInt64, OptionInt64>, Map<OptionInt64, OptionInt64>>::Reader{})),
|
||||
std::map<
|
||||
std::map<std::optional<int64_t>, std::optional<int64_t>>,
|
||||
std::map<std::optional<int64_t>, std::optional<int64_t>>>>);
|
||||
}
|
||||
|
||||
TEST(RpcErrorV1, shortMessage)
|
||||
{
|
||||
Error e{ErrorInfo{lvlWarn, HintFmt("test message %s", "data")}};
|
||||
|
||||
Reference in New Issue
Block a user