blob: aa6ed7381baea6f94834370eb72d447ea8c1e602 [file] [log] [blame]
#include "state_merge.h"
#include <tuple>
#include "safepower_agent.pb.h"
#include "state_fields.h"
#include "google/protobuf/map.h"
namespace safepower_agent {
using ::safepower_agent_proto::NodeState;
using ::safepower_agent_proto::SystemState;
template <typename Field>
concept IsMessage = requires { &Field::get_mutable_from; };
template <typename Proto>
static void Update(Proto& dest, const Proto& update);
template <typename Proto, typename Field>
inline void UpdateField(const Field& field, Proto& dest, const Proto& src) {
if (!field.is_in(src)) return;
if constexpr (IsMessage<Field>) {
Update(*field.get_mutable_from(dest), field.get_from(src));
} else {
field.set_in(dest, field.get_from(src));
}
}
template <typename Proto, typename Key, typename Value>
inline void UpdateField(const MapFieldDef<Key, Value>& field, Proto& dest,
const Proto& src) {
for (const auto& [key, value] : field.get_from(src)) {
Update((*field.get_mutable_from(dest))[key], value);
}
}
template <typename Proto>
static void Update(Proto& dest, const Proto& update) {
std::apply(
[&](auto&&... fields) { (UpdateField(fields, dest, update), ...); },
ProtoFields<Proto>::kFields);
}
// Recursively update a map field.
template <typename Key, typename Value>
static void Update(google::protobuf::Map<Key, Value>& dest,
const google::protobuf::Map<Key, Value>& update) {
for (const auto& [key, value] : update) {
auto found = dest.find(key);
if (found == dest.end()) {
dest.insert({key, value});
} else {
Update(found->second, value);
}
}
}
template <>
void ApplyStateUpdate(SystemState& current_state, const SystemState& update) {
Update(current_state, update);
}
} // namespace safepower_agent