"Daniel P. Berrange" <berra...@redhat.com> writes: > The qdict_flatten() method will take a dict whose elements are > further nested dicts/lists and flatten them by concatenating > keys. > > The qdict_crumple() method aims to do the reverse, taking a flat > qdict, and turning it into a set of nested dicts/lists. It will > apply nesting based on the key name, with a '.' indicating a > new level in the hierarchy. If the keys in the nested structure > are all numeric, it will create a list, otherwise it will create > a dict. > > If the keys are a mixture of numeric and non-numeric, or the > numeric keys are not in strictly ascending order, an error will > be reported. > > As an example, a flat dict containing > > { > 'foo.0.bar': 'one', > 'foo.0.wizz': '1', > 'foo.1.bar': 'two', > 'foo.1.wizz': '2' > } > > will get turned into a dict with one element 'foo' whose > value is a list. The list elements will each in turn be > dicts. > > { > 'foo': [ > { 'bar': 'one', 'wizz': '1' }, > { 'bar': 'two', 'wizz': '2' } > ], > } > > If the key is intended to contain a literal '.', then it must > be escaped as '..'. ie a flat dict > > { > 'foo..bar': 'wizz', > 'bar.foo..bar': 'eek', > 'bar.hello': 'world' > } > > Will end up as > > { > 'foo.bar': 'wizz', > 'bar': { > 'foo.bar': 'eek', > 'hello': 'world' > } > } > > The intent of this function is that it allows a set of QemuOpts > to be turned into a nested data structure that mirrors the nesting > used when the same object is defined over QMP. > > Reviewed-by: Eric Blake <ebl...@redhat.com> > Reviewed-by: Kevin Wolf <kw...@redhat.com> > Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> > Signed-off-by: Daniel P. Berrange <berra...@redhat.com> > --- > include/qapi/qmp/qdict.h | 1 + > qobject/qdict.c | 289 > +++++++++++++++++++++++++++++++++++++++++++++++ > tests/check-qdict.c | 261 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 551 insertions(+) > > diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h > index 71b8eb0..e0d24e1 100644 > --- a/include/qapi/qmp/qdict.h > +++ b/include/qapi/qmp/qdict.h > @@ -73,6 +73,7 @@ void qdict_flatten(QDict *qdict); > void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start); > void qdict_array_split(QDict *src, QList **dst); > int qdict_array_entries(QDict *src, const char *subqdict); > +QObject *qdict_crumple(const QDict *src, bool recursive, Error **errp); > > void qdict_join(QDict *dest, QDict *src, bool overwrite); > > diff --git a/qobject/qdict.c b/qobject/qdict.c > index 60f158c..c38e90e 100644 > --- a/qobject/qdict.c > +++ b/qobject/qdict.c [...] > +/** > + * qdict_crumple: > + * @src: the original flat dictionary (only scalar values) to crumple > + * @recursive: true to recursively crumple nested dictionaries
Is recursive=false used outside tests in this series? > + * > + * Takes a flat dictionary whose keys use '.' separator to indicate > + * nesting, and values are scalars, and crumples it into a nested > + * structure. If the @recursive parameter is false, then only the > + * first level of structure implied by the keys will be crumpled. If > + * @recursive is true, then the input will be recursively crumpled to > + * expand all levels of structure in the keys. > + * > + * To include a literal '.' in a key name, it must be escaped as '..' > + * > + * For example, an input of: > + * > + * { 'foo.0.bar': 'one', 'foo.0.wizz': '1', > + * 'foo.1.bar': 'two', 'foo.1.wizz': '2' } > + * > + * will result in an output of: > + * > + * { > + * 'foo': [ > + * { 'bar': 'one', 'wizz': '1' }, > + * { 'bar': 'two', 'wizz': '2' } > + * ], > + * } > + * > + * The following scenarios in the input dict will result in an > + * error being returned: > + * > + * - Any values in @src are non-scalar types > + * - If keys in @src imply that a particular level is both a > + * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar". > + * - If keys in @src imply that a particular level is a list, > + * but the indices are non-contiguous. e.g. "foo.0.bar" and > + * "foo.2.bar" without any "foo.1.bar" present. > + * - If keys in @src represent list indexes, but are not in > + * the "%zu" format. e.g. "foo.+0.bar" > + * > + * Returns: either a QDict or QList for the nested data structure, or NULL > + * on error > + */ > +QObject *qdict_crumple(const QDict *src, bool recursive, Error **errp) [...]