treat integers and doubles both as JSON numbers

Fri, 01 Nov 2024 17:35:42 +0100

author
Mike Becker <universe@uap-core.de>
date
Fri, 01 Nov 2024 17:35:42 +0100
changeset 966
1aa7ec3e46e7
parent 965
dfdfedbe2c86
child 967
a58f602ed2fe

treat integers and doubles both as JSON numbers

relates to #431

src/cx/json.h file | annotate | diff | comparison | revisions
tests/test_json.c file | annotate | diff | comparison | revisions
--- a/src/cx/json.h	Fri Nov 01 17:24:51 2024 +0100
+++ b/src/cx/json.h	Fri Nov 01 17:35:42 2024 +0100
@@ -64,7 +64,7 @@
     CX_JSON_OBJECT,
     CX_JSON_ARRAY,
     CX_JSON_STRING,
-    CX_JSON_INTEGER, // TODO: the spec does not know integer types
+    CX_JSON_INTEGER,
     CX_JSON_NUMBER,
     CX_JSON_LITERAL
 };
@@ -207,8 +207,7 @@
 
 __attribute__((__nonnull__))
 static inline bool cxJsonIsNumber(CxJsonValue *value) {
-    // TODO: this is not good, because an integer is also a number
-    return value->type == CX_JSON_NUMBER;
+    return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER;
 }
 
 __attribute__((__nonnull__))
@@ -241,20 +240,37 @@
     return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL;
 }
 
+__attribute__((__nonnull__, __returns_nonnull__))
+static inline char *cxJsonAsString(CxJsonValue *value) {
+    return value->value.string.ptr;
+}
+
 __attribute__((__nonnull__))
-static inline cxmutstr cxJsonAsString(CxJsonValue *value) {
-    // TODO: do we need a separate method to return this directly as cxstring?
+static inline cxstring cxJsonAsCxString(CxJsonValue *value) {
+    return cx_strcast(value->value.string);
+}
+
+__attribute__((__nonnull__))
+static inline cxmutstr cxJsonAsCxMutStr(CxJsonValue *value) {
     return value->value.string;
 }
 
 __attribute__((__nonnull__))
 static inline double cxJsonAsDouble(CxJsonValue *value) {
-    return value->value.number;
+    if (value->type == CX_JSON_INTEGER) {
+        return (double) value->value.integer;
+    } else {
+        return value->value.number;
+    }
 }
 
 __attribute__((__nonnull__))
 static inline int64_t cxJsonAsInteger(CxJsonValue *value) {
-    return value->value.integer;
+    if (value->type == CX_JSON_INTEGER) {
+        return value->value.integer;
+    } else {
+        return (int64_t) value->value.number;
+    }
 }
 
 __attribute__((__nonnull__))
--- a/tests/test_json.c	Fri Nov 01 17:24:51 2024 +0100
+++ b/tests/test_json.c	Fri Nov 01 17:35:42 2024 +0100
@@ -72,7 +72,7 @@
         CxJsonValue *message = cxJsonObjGet(obj, "message");
         CX_TEST_ASSERT(cxJsonIsString(message));
         CX_TEST_ASSERT(0 == cx_strcmp(
-                cx_strcast(cxJsonAsString(message)),
+                cxJsonAsCxString(message),
                 cx_str("success"))
         );
 
@@ -80,14 +80,20 @@
         CX_TEST_ASSERT(cxJsonIsObject(position));
         CxJsonValue *longitude = cxJsonObjGet(position, "longitude");
         CX_TEST_ASSERT(cxJsonIsNumber(longitude));
+        CX_TEST_ASSERT(!cxJsonIsInteger(longitude));
         CX_TEST_ASSERT(cxJsonAsDouble(longitude) == -94.7099);
+        CX_TEST_ASSERT(cxJsonAsInteger(longitude) == -94);
         CxJsonValue *latitude = cxJsonObjGet(position, "latitude");
         CX_TEST_ASSERT(cxJsonIsNumber(latitude));
+        CX_TEST_ASSERT(!cxJsonIsInteger(latitude));
         CX_TEST_ASSERT(cxJsonAsDouble(latitude) == 51.5539);
+        CX_TEST_ASSERT(cxJsonAsInteger(latitude) == 51);
 
         CxJsonValue *timestamp = cxJsonObjGet(obj, "timestamp");
         CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
+        CX_TEST_ASSERT(cxJsonIsNumber(timestamp));
         CX_TEST_ASSERT(cxJsonAsInteger(timestamp) == 1729348561);
+        CX_TEST_ASSERT(cxJsonAsDouble(timestamp) == 1729348561.0);
 
         CxJsonValue *alive = cxJsonObjGet(obj, "alive");
         CX_TEST_ASSERT(cxJsonIsBool(alive));
@@ -140,7 +146,7 @@
         CxJsonValue *message = cxJsonObjGet(obj, "message");
         CX_TEST_ASSERT(cxJsonIsString(message));
         CX_TEST_ASSERT(0 == cx_strcmp(
-                cx_strcast(cxJsonAsString(message)),
+                cxJsonAsCxString(message),
                 cx_str("success"))
         );
         CxJsonValue *timestamp = cxJsonObjGet(obj, "__timestamp");

mercurial