Patchwork [5/7] add json encoder for qobjects

login
register
mail settings
Submitter Paolo Bonzini
Date Oct. 17, 2009, 7:55 a.m.
Message ID <1255766136-3028-6-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/36295/
State New
Headers show

Comments

Paolo Bonzini - Oct. 17, 2009, 7:55 a.m.
The JSON encoder is just a virtual method on QObject.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile  |    4 ++--
 qdict.c   |   32 ++++++++++++++++++++++++++++++++
 qint.c    |   16 ++++++++++++++++
 qlist.c   |   28 ++++++++++++++++++++++++++++
 qobject.h |   10 ++++++++++
 qstring.c |   32 ++++++++++++++++++++++++++++++++
 qstring.h |    5 +++++
 7 files changed, 125 insertions(+), 2 deletions(-)
Anthony Liguori - Oct. 17, 2009, 1:03 p.m.
Paolo Bonzini wrote:
> The JSON encoder is just a virtual method on QObject.
>   

I think it makes more sense as an external entity.

Regards,

Anthony Liguori
Paolo Bonzini - Oct. 17, 2009, 1:44 p.m.
On 10/17/2009 03:03 PM, Anthony Liguori wrote:
>
> I think it makes more sense as an external entity.

Maybe... I just thought of it as a toString method that happens to emit 
JSON.

Paolo
Anthony Liguori - Oct. 17, 2009, 4:20 p.m.
Paolo Bonzini wrote:
> On 10/17/2009 03:03 PM, Anthony Liguori wrote:
>>
>> I think it makes more sense as an external entity.
>
> Maybe... I just thought of it as a toString method that happens to 
> emit JSON.

json is one representation of the monitor protocol.  I think we should 
attempt to design things so that there is a clear separate of 
representation from the implementation.

BTW, the next thing I'd like to do this weekend is write a QObject 
decoded based on the json parser.  So that you can do something like:

  int locked, readonly;
  char *file;

  err = qobject_unmarshal(obj, "{'locked': %i, 'file': %s, 'readonly': 
%i}", &locked, &file, &readonly);

I think this would tremendously simplify the monitor command 
implementations.

Regards,

Anthony Liguori

Patch

diff --git a/Makefile b/Makefile
index 7d4d75c..2447d23 100644
--- a/Makefile
+++ b/Makefile
@@ -210,10 +210,10 @@  qemu-io$(EXESUF):  qemu-io.o qemu-tool.o cmd.o $(block-obj-y)
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 
-check-qint: check-qint.o qint.o qemu-malloc.o
+check-qint: check-qint.o qint.o qstring.o qemu-malloc.o
 check-qstring: check-qstring.o qstring.o qemu-malloc.o
 check-qdict: check-qdict.o qdict.o qint.o qstring.o qemu-malloc.o
-check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
+check-qlist: check-qlist.o qlist.o qint.o qstring.o qemu-malloc.o
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
diff --git a/qdict.c b/qdict.c
index a302f4c..efbc53d 100644
--- a/qdict.c
+++ b/qdict.c
@@ -18,10 +18,12 @@ 
 #include "qemu-common.h"
 
 static void qdict_destroy_obj(QObject *obj);
+static void qdict_encode_json(const QObject *obj, QString *str);
 
 static const QType qdict_type = {
     .code = QTYPE_QDICT,
     .destroy = qdict_destroy_obj,
+    .encode_json = qdict_encode_json,
 };
 
 /**
@@ -295,3 +297,33 @@  static void qdict_destroy_obj(QObject *obj)
 
     qemu_free(qdict);
 }
+
+/**
+ * qdict_encode_json(): Encode the dictionary to JSON on a QString.
+ */
+static void qdict_encode_json(const QObject *obj, QString *str)
+{
+    int i, first;
+    const QDict *qdict;
+
+    assert(obj != NULL);
+    qdict = qobject_to_qdict((QObject *) obj);
+
+    qstring_append_ch (str, '{');
+    for (first = 1, i = 0; i < QDICT_HASH_SIZE; i++) {
+        QDictEntry *entry = QLIST_FIRST(&qdict->table[i]);
+        while (entry) {
+            if (!first)
+                qstring_append_ch (str, ',');
+            qstring_append_ch (str, '"');
+            qstring_append_escaped (str, entry->key);
+            qstring_append_ch (str, '"');
+            qstring_append_ch (str, ':');
+            qobject_encode_json (entry->value, str);
+            entry = QLIST_NEXT(entry, next);
+            first = 0;
+        }
+    }
+
+    qstring_append_ch (str, '}');
+}
diff --git a/qint.c b/qint.c
index 447e847..b5ceea3 100644
--- a/qint.c
+++ b/qint.c
@@ -10,14 +10,17 @@ 
  * the COPYING file in the top-level directory.
  */
 #include "qint.h"
+#include "qstring.h"
 #include "qobject.h"
 #include "qemu-common.h"
 
 static void qint_destroy_obj(QObject *obj);
+static void qint_encode_json(const QObject *obj, QString *str);
 
 static const QType qint_type = {
     .code = QTYPE_QINT,
     .destroy = qint_destroy_obj,
+    .encode_json = qint_encode_json,
 };
 
 /**
@@ -64,3 +67,16 @@  static void qint_destroy_obj(QObject *obj)
     assert(obj != NULL);
     qemu_free(qobject_to_qint(obj));
 }
+
+/**
+ * qint_encode_json(): Encode the integer to JSON on a QString.
+ */
+static void qint_encode_json(const QObject *obj, QString *str)
+{
+    char buf[32];
+    QInt *qint;
+
+    qint = qobject_to_qint((QObject *) obj);
+    sprintf (buf, "%" PRId64, qint->value);
+    qstring_append (str, buf);
+}
diff --git a/qlist.c b/qlist.c
index ba2c66c..4c7e1b2 100644
--- a/qlist.c
+++ b/qlist.c
@@ -10,15 +10,18 @@ 
  * the COPYING file in the top-level directory.
  */
 #include "qlist.h"
+#include "qstring.h"
 #include "qobject.h"
 #include "qemu-queue.h"
 #include "qemu-common.h"
 
 static void qlist_destroy_obj(QObject *obj);
+static void qlist_encode_json(const QObject *obj, QString *str);
 
 static const QType qlist_type = {
     .code = QTYPE_QLIST,
     .destroy = qlist_destroy_obj,
+    .encode_json = qlist_encode_json,
 };
  
 /**
@@ -98,3 +101,28 @@  static void qlist_destroy_obj(QObject *obj)
 
     qemu_free(qlist);
 }
+
+/**
+ * qlist_encode_json(): Encode the list to JSON on a QString.
+ */
+static void qlist_encode_json(const QObject *obj, QString *str)
+{
+    const QList *qlist;
+    QListEntry *entry;
+    int first;
+
+    assert(obj != NULL);
+    qlist = qobject_to_qlist((QObject *) obj);
+
+    first = 1;
+    qstring_append_ch (str, '[');
+    QTAILQ_FOREACH(entry, &qlist->head, next) {
+        if (!first)
+            qstring_append_ch (str, ',');
+        qobject_encode_json (entry->value, str);
+        first = 0;
+    }
+
+    qstring_append_ch (str, ']');
+}
+
diff --git a/qobject.h b/qobject.h
index f5c78b2..d941a73 100644
--- a/qobject.h
+++ b/qobject.h
@@ -52,6 +52,7 @@  struct QList;
 typedef struct QType {
     qtype_code code;
     void (*destroy)(struct QObject *);
+    void (*encode_json)(const struct QObject *, struct QString *);
 } QType;
 
 typedef struct QObject {
@@ -112,4 +113,13 @@  static inline qtype_code qobject_type(const QObject *obj)
     return obj->type->code;
 }
 
+/**
+ * qobject_type(): Return the QObject's type
+ */
+static inline void qobject_encode_json(const QObject *obj, struct QString *str)
+{
+    assert(obj->type != NULL);
+    obj->type->encode_json (obj, str);
+}
+
 #endif /* QOBJECT_H */
diff --git a/qstring.c b/qstring.c
index ab77fba..10c1952 100644
--- a/qstring.c
+++ b/qstring.c
@@ -14,10 +14,12 @@ 
 #include "qemu-common.h"
 
 static void qstring_destroy_obj(QObject *obj);
+static void qstring_encode_json(const QObject *obj, QString *str);
 
 static const QType qstring_type = {
     .code = QTYPE_QSTRING,
     .destroy = qstring_destroy_obj,
+    .encode_json = qstring_encode_json,
 };
 
 /**
@@ -63,6 +65,22 @@  QString *qstring_from_str(const char *str)
 }
 
 /**
+ * qstring_json_from_qobject_obj(): Encode a QObject as JSON and return
+ * a QString with the result.
+ *
+ * Return strong reference.
+ */
+QString *qstring_json_from_qobject_obj(const QObject *qobject)
+{
+    QString *qstring;
+
+    qstring = qstring_new();
+    qobject_encode_json(qobject, qstring);
+    return qstring;
+}
+
+
+/**
  * qstring_append(): Append a regular C string to a QString
  */
 void qstring_append(QString *qstring, const char *str)
@@ -172,3 +190,17 @@  static void qstring_destroy_obj(QObject *obj)
     qemu_free(qs->string);
     qemu_free(qs);
 }
+
+/**
+ * qstring_encode_json(): Encode the string to JSON on a QString.
+ */
+static void qstring_encode_json(const QObject *obj, QString *str)
+{
+    QString *qstring;
+
+    assert(obj != NULL);
+    qstring = qobject_to_qstring((QObject *) obj);
+    qstring_append_ch (str, '"');
+    qstring_append_escaped (str, qstring_get_str(qstring));
+    qstring_append_ch (str, '"');
+}
diff --git a/qstring.h b/qstring.h
index 6e16d58..efc1d7a 100644
--- a/qstring.h
+++ b/qstring.h
@@ -11,6 +11,11 @@  typedef struct QString {
 
 QString *qstring_new(void);
 QString *qstring_from_str(const char *str);
+QString *qstring_json_from_qobject_obj(const QObject *obj);
+
+#define qstring_json_from_qobject(obj) \
+        qstring_json_from_qobject_obj(QOBJECT(obj))
+
 const char *qstring_get_str(const QString *qstring);
 void qstring_append(QString *qstring, const char *str);
 void qstring_append_escaped(QString *qstring, const char *str);