| #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 |