All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/8] json: add support for array iteration
@ 2022-01-05 18:46 James Prestwood
  0 siblings, 0 replies; only message in thread
From: James Prestwood @ 2022-01-05 18:46 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 5444 bytes --]

Arrays can now be parsed using the JSON_ARRAY type (stored in
a struct json_iter) then iterated using json_iter_next. When
iterating the type can be checked with json_iter_get_type. For
each iteration the value can be obtained using any of the type
getters (int/uint/boolean/null).

For now only primitive type arrays are supported.

Several internal APIs were renamed/altered to make them more
general purpose for both arrays and objects.
---
 src/json.c | 64 ++++++++++++++++++++++++++++++++++++++++++------------
 src/json.h |  5 +++++
 2 files changed, 55 insertions(+), 14 deletions(-)

diff --git a/src/json.c b/src/json.c
index a83ba464..879d43be 100644
--- a/src/json.c
+++ b/src/json.c
@@ -56,7 +56,8 @@ struct json_contents {
 	jsmn_parser *p;
 };
 
-static jsmntok_t *next_key_in_parent(struct json_iter *iter, jsmntok_t *current)
+static jsmntok_t *next_token_in_parent(struct json_iter *iter,
+					jsmntok_t *current)
 {
 	int parent = current->parent;
 
@@ -69,20 +70,14 @@ static jsmntok_t *next_key_in_parent(struct json_iter *iter, jsmntok_t *current)
 	return NULL;
 }
 
-/*
- * 'object' is expected to be a value, so object - 1 is its key. Find
- * the next key who's parent matches the parent of object - 1. The
- * token preceeding this next key will mark the end of 'object'.
- */
-static int find_object_tokens(struct json_iter *iter, jsmntok_t *object)
+static int find_parent_tokens(struct json_iter *iter, jsmntok_t *token)
 {
-	jsmntok_t *next = next_key_in_parent(iter, object - 1);
+	jsmntok_t *next = next_token_in_parent(iter, token);
 
-	/* End of token list */
 	if (!next)
 		next = ITER_END(iter);
 
-	return next - object - 1;
+	return next - token;
 }
 
 static void iter_recurse(struct json_iter *iter, jsmntok_t *token,
@@ -92,18 +87,29 @@ static void iter_recurse(struct json_iter *iter, jsmntok_t *token,
 
 	child->contents = c;
 	child->start = token - c->tokens;
+	child->current = child->start;
 
 	/*
 	* For objects iterating all tokens with the object as the parent
 	* parent should give the total number of tokens for this object.
 	*
+	* For arrays we want to count the tokens inside the array itself. We
+	* cannot simply count until we reach a different parent than the array
+	* due to the possibility of nested objects. Instead we find the next
+	* token with the same parent as the array (the next key in the object).
+	* This offset will include both the arrays key, and the array itself,
+	* hence subtracting 2.
+	*
 	* For strings/primitives the value is always going to one token which
 	* will not be iteratable. Because of this the count is set to zero to
 	* disallow any iteration on this child iterator.
 	*/
 	if (token->type == JSMN_OBJECT)
-		child->count = find_object_tokens(iter, token);
-	else
+		child->count = find_parent_tokens(iter, token);
+	else if (token->type == JSMN_ARRAY) {
+		child->count = find_parent_tokens(iter, token - 1) - 2;
+		child->array = true;
+	} else
 		child->count = 0;
 }
 
@@ -176,6 +182,7 @@ static void assign_arg(void *data, void *user_data)
 		break;
 	case JSON_OBJECT:
 	case JSON_PRIMITIVE:
+	case JSON_ARRAY:
 		iter_val = arg->value;
 
 		if (!arg->v)
@@ -223,6 +230,7 @@ bool json_iter_parse(struct json_iter *iter, enum json_type type, ...)
 		case JSON_STRING:
 		case JSON_OBJECT:
 		case JSON_PRIMITIVE:
+		case JSON_ARRAY:
 			break;
 		default:
 			goto error;
@@ -252,7 +260,7 @@ bool json_iter_parse(struct json_iter *iter, enum json_type type, ...)
 				break;
 			}
 
-			next = next_key_in_parent(iter, next);
+			next = next_token_in_parent(iter, next);
 			if (!next)
 				break;
 		}
@@ -287,7 +295,7 @@ static bool iter_get_primitive_data(struct json_iter *iter, void **ptr,
 					size_t *len)
 {
 	struct json_contents *c = iter->contents;
-	jsmntok_t *t = c->tokens + iter->start;
+	jsmntok_t *t = c->tokens + iter->current;
 
 	if (t->type != JSMN_PRIMITIVE)
 		return false;
@@ -392,3 +400,31 @@ bool json_iter_get_null(struct json_iter *iter)
 
 	return false;
 }
+
+enum json_type json_iter_get_type(struct json_iter *iter)
+{
+	struct json_contents *c = iter->contents;
+	jsmntok_t *t = c->tokens + iter->current;
+
+	return (enum json_type) t->type;
+}
+
+bool json_iter_next(struct json_iter *iter)
+{
+	struct json_contents *c = iter->contents;
+
+	/* For now only allow json_iter_next() on arrays */
+	if (!iter->array)
+		return false;
+
+	if (c->tokens + iter->current + 1 > ITER_END(iter))
+		return false;
+
+	iter->current++;
+
+	/* TODO: Add support for nested array iteration */
+	if ((c->tokens + iter->current)->type == JSMN_ARRAY)
+		return false;
+
+	return true;
+}
diff --git a/src/json.h b/src/json.h
index 9f00a9d5..75ac9853 100644
--- a/src/json.h
+++ b/src/json.h
@@ -42,6 +42,8 @@ struct json_iter {
 	struct json_contents *contents;
 	int start;
 	int count;
+	int current;
+	bool array : 1;
 };
 
 #define JSON_MANDATORY(key, type, out) \
@@ -92,3 +94,6 @@ bool json_iter_get_int(struct json_iter *iter, int *i);
 bool json_iter_get_uint(struct json_iter *iter, unsigned int *i);
 bool json_iter_get_boolean(struct json_iter *iter, bool *b);
 bool json_iter_get_null(struct json_iter *iter);
+
+enum json_type json_iter_get_type(struct json_iter *iter);
+bool json_iter_next(struct json_iter *iter);
-- 
2.31.1

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2022-01-05 18:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-05 18:46 [PATCH 3/8] json: add support for array iteration James Prestwood

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.