The migration subsystem currently has code to merge two objects of the
same type. It does so by checking which fields are present in a source
object and overwriting the corresponding fields on the destination
object. This leads to a lot of open-coded lines such as:

    if (src->has_foobar) {
        dst->foobar = src->foobar;
    }

This pattern could be replaced by a copy using visitors. Implement a
macro that extracts elements from a source object using an output
visitor and merges it with a destination object using an input
visitor.

Signed-off-by: Fabiano Rosas <[email protected]>
---
 include/qapi/type-helpers.h | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/include/qapi/type-helpers.h b/include/qapi/type-helpers.h
index fc8352cdec..011716c6ad 100644
--- a/include/qapi/type-helpers.h
+++ b/include/qapi/type-helpers.h
@@ -10,6 +10,8 @@
  */
 
 #include "qapi/qapi-types-common.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
 
 HumanReadableText *human_readable_text_from_str(GString *str);
 
@@ -20,3 +22,30 @@ HumanReadableText *human_readable_text_from_str(GString 
*str);
  * cleanup.
  */
 char **strv_from_str_list(const strList *list);
+
+/*
+ * Merge @src over @dst by copying deep clones of the present members
+ * from @src to @dst. Non-present on @src are left untouched on @dst.
+ */
+#define QAPI_MERGE(type, dst_, src_)                                    \
+    ({                                                                  \
+        QObject *out_ = NULL;                                           \
+        Visitor *v_;                                                    \
+        /* read in from src */                                          \
+        v_ = qobject_output_visitor_new(&out_);                         \
+        visit_type_ ## type(v_, NULL, &src_, &error_abort);             \
+        visit_complete(v_, &out_);                                      \
+        visit_free(v_);                                                 \
+        /*                                                              \
+         * Write to dst but leave existing fields intact (except for    \
+         * has_* which will be updated according to their presence in   \
+         * src).                                                        \
+         */                                                             \
+        v_ = qobject_input_visitor_new(out_);                           \
+        visit_start_struct(v_, NULL, NULL, 0, &error_abort);            \
+        visit_type_ ## type ## _members(v_, dst_, &error_abort);        \
+        visit_check_struct(v_, &error_abort);                           \
+        visit_end_struct(v_, NULL);                                     \
+        visit_free(v_);                                                 \
+        qobject_unref(out_);                                            \
+    })
-- 
2.51.0


Reply via email to