Dqn/dqn_json.cpp

430 lines
14 KiB
C++
Raw Normal View History

2024-04-18 22:59:11 +10:00
#pragma once
#include "dqn.h"
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON //////////////////////////////////////////////////////////////////////////////////
void *DN_JSON_ArenaAllocFunc(void *user_data, size_t count)
2024-04-18 22:59:11 +10:00
{
void *result = NULL;
if (!user_data)
return result;
2025-02-14 00:27:42 +11:00
DN_Arena *arena = DN_CAST(DN_Arena*)user_data;
result = DN_Arena_Alloc(arena, count, alignof(json_value_s), DN_ZeroMem_No);
2024-04-18 22:59:11 +10:00
return result;
}
2025-02-14 00:27:42 +11:00
char const *DN_JSON_TypeEnumCString(json_type_e type, size_t *size)
2024-04-18 22:59:11 +10:00
{
switch (type) {
case json_type_string: { if (size) { *size = sizeof("string") - 1; } return "string"; }
case json_type_number: { if (size) { *size = sizeof("number") - 1; } return "number"; }
case json_type_object: { if (size) { *size = sizeof("object") - 1; } return "object"; }
case json_type_array: { if (size) { *size = sizeof("array") - 1; } return "array"; }
case json_type_true: { if (size) { *size = sizeof("true (boolean)") - 1; } return "true (boolean)"; }
case json_type_false: { if (size) { *size = sizeof("false (boolean)") - 1; } return "false (boolean)"; }
default: /*FALLTHRU*/
case json_type_null: { if (size) { *size = sizeof("(null)") - 1; } return "(null)"; }
}
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_String8Cmp(json_string_s const *lhs, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
bool result = false;
2025-02-14 00:27:42 +11:00
if (lhs && DN_Str8_HasData(key)) {
DN_Str8 lhs_string = DN_Str8_Init(lhs->string, lhs->string_size);
result = DN_Str8_Eq(lhs_string, key);
2024-04-18 22:59:11 +10:00
}
return result;
}
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON_It ///////////////////////////////////////////////////////////////////////////////
DN_JSONIt DN_JSON_LoadFileToIt(DN_Arena *arena, DN_Str8 json)
2024-04-18 22:59:11 +10:00
{
json_parse_result_s parse_result = {};
json_value_ex_s *ex_value =
2025-02-14 00:27:42 +11:00
DN_CAST(json_value_ex_s *) json_parse_ex(json.data,
2024-04-18 22:59:11 +10:00
json.size,
json_parse_flags_allow_location_information,
2025-02-14 00:27:42 +11:00
DN_JSON_ArenaAllocFunc,
2024-04-18 22:59:11 +10:00
arena,
&parse_result);
2025-02-14 00:27:42 +11:00
DN_JSONIt result = {};
DN_JSON_ItPushValue(&result, &ex_value->value);
2024-04-18 22:59:11 +10:00
return result;
}
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON_ItPush/Pop ///////////////////////////////////////////////////////////////////////
bool DN_JSON_ItPushObjElement(DN_JSONIt *it, json_object_element_s *element)
2024-04-18 22:59:11 +10:00
{
if (!it || !element)
return false;
2025-02-14 00:27:42 +11:00
DN_ASSERT(it->stack_count < DN_ARRAY_ICOUNT(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeObjElement, element};
2024-04-18 22:59:11 +10:00
return true;
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_ItPushObj(DN_JSONIt *it, json_object_s *obj)
2024-04-18 22:59:11 +10:00
{
if (!it || !obj)
return false;
2025-02-14 00:27:42 +11:00
DN_ASSERT(it->stack_count < DN_ARRAY_ICOUNT(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeObj, obj};
2024-04-18 22:59:11 +10:00
return true;
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_ItPushArrayElement(DN_JSONIt *it, json_array_element_s *element)
2024-04-18 22:59:11 +10:00
{
if (!it || !element)
return false;
2025-02-14 00:27:42 +11:00
DN_ASSERT(it->stack_count < DN_ARRAY_ICOUNT(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeArrayElement, element};
2024-04-18 22:59:11 +10:00
return true;
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_ItPushArray(DN_JSONIt *it, json_value_s *value)
2024-04-18 22:59:11 +10:00
{
if (!it || !value || json_value_as_array(value) == nullptr)
return false;
2025-02-14 00:27:42 +11:00
DN_ASSERT(it->stack_count < DN_ARRAY_ICOUNT(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeArray, value};
2024-04-18 22:59:11 +10:00
return true;
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_ItPushValue(DN_JSONIt *it, json_value_s *value)
2024-04-18 22:59:11 +10:00
{
bool result = false;
if (!it || !value)
return result;
if (value->type == json_type_object) {
2025-02-14 00:27:42 +11:00
result = DN_JSON_ItPushObj(it, json_value_as_object(value));
2024-04-18 22:59:11 +10:00
} else if (value->type == json_type_array) {
2025-02-14 00:27:42 +11:00
result = DN_JSON_ItPushArray(it, value);
2024-04-18 22:59:11 +10:00
}
return result;
}
2025-02-14 00:27:42 +11:00
void DN_JSON_ItPop(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
if (!it)
return;
2025-02-14 00:27:42 +11:00
DN_ASSERT(it->stack_count > 0);
2024-04-18 22:59:11 +10:00
if (it->stack_count > 0)
it->stack_count--;
}
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON_It JSON tree navigation //////////////////////////////////////////////////////////
json_value_s *DN_JSON_ItPushCurrValue(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
json_value_s *result = nullptr;
2025-02-14 00:27:42 +11:00
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
2024-04-18 22:59:11 +10:00
if (!curr)
return result;
2025-02-14 00:27:42 +11:00
if (curr->type == DN_JSON_ItEntryTypeObjElement) {
json_object_element_s *element = DN_CAST(json_object_element_s *) curr->value;
2024-04-18 22:59:11 +10:00
result = element->value;
2025-02-14 00:27:42 +11:00
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
json_array_element_s *element = DN_CAST(json_array_element_s *) curr->value;
2024-04-18 22:59:11 +10:00
result = element->value;
} else {
2025-02-14 00:27:42 +11:00
result = DN_CAST(json_value_s *) curr->value;
2024-04-18 22:59:11 +10:00
}
if (result->type == json_type_array) {
json_array_s *array = json_value_as_array(result);
2025-02-14 00:27:42 +11:00
DN_ASSERT(array);
DN_JSON_ItPushArray(it, result);
2024-04-18 22:59:11 +10:00
} else if (result->type == json_type_object) {
json_object_s *obj = json_value_as_object(result);
2025-02-14 00:27:42 +11:00
DN_ASSERT(obj);
DN_JSON_ItPushObj(it, obj);
2024-04-18 22:59:11 +10:00
}
return result;
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_ItNext(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
2024-04-18 22:59:11 +10:00
if (!curr)
return false;
json_object_element_s *obj_element = nullptr;
json_array_element_s *array_element = nullptr;
2025-02-14 00:27:42 +11:00
if (curr->type == DN_JSON_ItEntryTypeObj) {
auto *obj = DN_CAST(json_object_s *) curr->value;
2024-04-18 22:59:11 +10:00
obj_element = obj->start;
2025-02-14 00:27:42 +11:00
} else if (curr->type == DN_JSON_ItEntryTypeObjElement) {
auto *element = DN_CAST(json_object_element_s *) curr->value;
2024-04-18 22:59:11 +10:00
obj_element = element->next;
2025-02-14 00:27:42 +11:00
DN_JSON_ItPop(it);
} else if (curr->type == DN_JSON_ItEntryTypeArray) {
auto *value = DN_CAST(json_value_s *) curr->value;
2024-04-18 22:59:11 +10:00
auto *array = json_value_as_array(value);
array_element = array->start;
2025-02-14 00:27:42 +11:00
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
auto *element = DN_CAST(json_array_element_s *) curr->value;
2024-04-18 22:59:11 +10:00
array_element = element->next;
2025-02-14 00:27:42 +11:00
DN_JSON_ItPop(it);
2024-04-18 22:59:11 +10:00
} else {
2025-02-14 00:27:42 +11:00
DN_JSON_ItPop(it);
2024-04-18 22:59:11 +10:00
}
if (obj_element)
2025-02-14 00:27:42 +11:00
DN_JSON_ItPushObjElement(it, obj_element);
2024-04-18 22:59:11 +10:00
else if (array_element)
2025-02-14 00:27:42 +11:00
DN_JSON_ItPushArrayElement(it, array_element);
2024-04-18 22:59:11 +10:00
bool result = obj_element || array_element;
return result;
}
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON_ItCurr ///////////////////////////////////////////////////////////////////////////
DN_JSONItEntry *DN_JSON_ItCurr(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
DN_JSONItEntry *result = nullptr;
2024-04-18 22:59:11 +10:00
if (!it || it->stack_count <= 0)
return result;
result = &it->stack[it->stack_count - 1];
return result;
}
2025-02-14 00:27:42 +11:00
json_value_s *DN_JSON_ItCurrValue(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
json_value_s *result = nullptr;
2025-02-14 00:27:42 +11:00
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
2024-04-18 22:59:11 +10:00
if (!curr)
return result;
2025-02-14 00:27:42 +11:00
if (curr->type == DN_JSON_ItEntryTypeObjElement) {
auto *element = DN_CAST(json_object_element_s *)curr->value;
2024-04-18 22:59:11 +10:00
result = element->value;
2025-02-14 00:27:42 +11:00
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
auto *element = DN_CAST(json_array_element_s *)curr->value;
2024-04-18 22:59:11 +10:00
result = element->value;
2025-02-14 00:27:42 +11:00
} else if (curr->type == DN_JSON_ItEntryTypeString ||
curr->type == DN_JSON_ItEntryTypeNumber ||
curr->type == DN_JSON_ItEntryTypeObj ||
curr->type == DN_JSON_ItEntryTypeArray)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
result = DN_CAST(json_value_s *)curr->value;
2024-04-18 22:59:11 +10:00
}
return result;
}
2025-02-14 00:27:42 +11:00
json_object_element_s *DN_JSON_ItCurrObjElement(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
auto *result = (curr && curr->type == DN_JSON_ItEntryTypeObjElement)
? DN_CAST(json_object_element_s *) curr->value
2024-04-18 22:59:11 +10:00
: nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON_ItValueIs ////////////////////////////////////////////////////////////////////////
json_value_s *DN_JSON_ItValueIs(DN_JSONIt *it, json_type_e type)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_value_s *curr = DN_JSON_ItCurrValue(it);
2024-04-18 22:59:11 +10:00
json_value_s *result = (curr && type == curr->type) ? curr : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
json_object_s *DN_JSON_ItValueIsObj(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_value_s *curr = DN_JSON_ItCurrValue(it);
2024-04-18 22:59:11 +10:00
json_object_s *result = curr ? json_value_as_object(curr) : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
json_array_s *DN_JSON_ItValueIsArray(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_value_s *curr = DN_JSON_ItCurrValue(it);
2024-04-18 22:59:11 +10:00
json_array_s *result = curr ? json_value_as_array(curr) : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
json_string_s *DN_JSON_ItValueIsString(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_value_s *curr = DN_JSON_ItCurrValue(it);
2024-04-18 22:59:11 +10:00
json_string_s *result = curr ? json_value_as_string(curr) : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
json_number_s *DN_JSON_ItValueIsNumber(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_value_s *curr = DN_JSON_ItCurrValue(it);
2024-04-18 22:59:11 +10:00
json_number_s *result = curr ? json_value_as_number(curr) : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
json_value_s *DN_JSON_ItValueIsBool(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_value_s *curr = DN_JSON_ItCurrValue(it);
2024-04-18 22:59:11 +10:00
json_value_s *result = (curr && (curr->type == json_type_true || curr->type == json_type_false)) ? curr : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
json_value_s *DN_JSON_ItValueIsNull(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_value_s *curr = DN_JSON_ItCurrValue(it);
2024-04-18 22:59:11 +10:00
json_value_s *result = (curr && (curr->type == json_type_null)) ? curr : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
size_t DN_JSON_ItValueArraySize(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
size_t result = 0;
2025-02-14 00:27:42 +11:00
if (json_array_s *curr = DN_JSON_ItValueIsArray(it))
2024-04-18 22:59:11 +10:00
result = curr->length;
return result;
}
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON_ItKeyValueIs /////////////////////////////////////////////////////////////////////
DN_Str8 DN_JSON_ItKey(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
DN_Str8 result = {};
2024-04-18 22:59:11 +10:00
if (curr) {
2025-02-14 00:27:42 +11:00
result.data = DN_CAST(char *)curr->name->string;
2024-04-18 22:59:11 +10:00
result.size = curr->name->string_size;
}
return result;
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_ItKeyIs(DN_JSONIt *it, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
bool result = DN_JSON_String8Cmp(curr->name, key);
2024-04-18 22:59:11 +10:00
return result;
}
2025-02-14 00:27:42 +11:00
json_object_s *DN_JSON_ItKeyValueIsObj(DN_JSONIt *it, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
json_object_s *result = nullptr;
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
if (curr && DN_JSON_String8Cmp(curr->name, key))
2024-04-18 22:59:11 +10:00
result = json_value_as_object(curr->value);
return result;
}
2025-02-14 00:27:42 +11:00
json_array_s *DN_JSON_ItKeyValueIsArray(DN_JSONIt *it, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
json_array_s *result = nullptr;
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
if (curr && DN_JSON_String8Cmp(curr->name, key))
2024-04-18 22:59:11 +10:00
result = json_value_as_array(curr->value);
return result;
}
2025-02-14 00:27:42 +11:00
json_string_s *DN_JSON_ItKeyValueIsString(DN_JSONIt *it, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
2024-04-18 22:59:11 +10:00
json_string_s *result = nullptr;
2025-02-14 00:27:42 +11:00
if (curr && DN_JSON_String8Cmp(curr->name, key))
2024-04-18 22:59:11 +10:00
result = json_value_as_string(curr->value);
return result;
}
2025-02-14 00:27:42 +11:00
json_number_s *DN_JSON_ItKeyValueIsNumber(DN_JSONIt *it, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
2024-04-18 22:59:11 +10:00
json_number_s *result = nullptr;
2025-02-14 00:27:42 +11:00
if (curr && DN_JSON_String8Cmp(curr->name, key))
2024-04-18 22:59:11 +10:00
result = json_value_as_number(curr->value);
return result;
}
2025-02-14 00:27:42 +11:00
json_value_s *DN_JSON_ItKeyValueIsBool(DN_JSONIt *it, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
2024-04-18 22:59:11 +10:00
json_value_s *result = nullptr;
2025-02-14 00:27:42 +11:00
if (curr && DN_JSON_String8Cmp(curr->name, key))
2024-04-18 22:59:11 +10:00
result = curr->value->type == json_type_true || curr->value->type == json_type_false ? curr->value : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
json_value_s *DN_JSON_ItKeyValueIsNull(DN_JSONIt *it, DN_Str8 key)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
2024-04-18 22:59:11 +10:00
json_value_s *result = nullptr;
2025-02-14 00:27:42 +11:00
if (curr && DN_JSON_String8Cmp(curr->name, key))
2024-04-18 22:59:11 +10:00
result = curr->value->type == json_type_null ? curr->value : nullptr;
return result;
}
2025-02-14 00:27:42 +11:00
// NOTE: DN_JSON_ItValueTo ////////////////////////////////////////////////////////////////////////
DN_Str8 DN_JSON_ItValueToString(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
2025-02-14 00:27:42 +11:00
DN_Str8 result = {};
if (json_string_s *curr = DN_JSON_ItValueIsString(it))
result = DN_Str8_Init(curr->string, curr->string_size);
2024-04-18 22:59:11 +10:00
return result;
}
2025-02-14 00:27:42 +11:00
int64_t DN_JSON_ItValueToI64(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
int64_t result = {};
2025-02-14 00:27:42 +11:00
if (json_number_s *curr = DN_JSON_ItValueIsNumber(it))
result = DN_Str8_ToI64(DN_Str8_Init(curr->number, curr->number_size), 0 /*separator*/).value;
2024-04-18 22:59:11 +10:00
return result;
}
2025-02-14 00:27:42 +11:00
uint64_t DN_JSON_ItValueToU64(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
uint64_t result = {};
2025-02-14 00:27:42 +11:00
if (json_number_s *curr = DN_JSON_ItValueIsNumber(it))
result = DN_Str8_ToU64(DN_Str8_Init(curr->number, curr->number_size), 0 /*separator*/).value;
2024-04-18 22:59:11 +10:00
return result;
}
2025-02-14 00:27:42 +11:00
bool DN_JSON_ItValueToBool(DN_JSONIt *it)
2024-04-18 22:59:11 +10:00
{
bool result = {};
2025-02-14 00:27:42 +11:00
if (json_value_s *curr = DN_JSON_ItValueIsBool(it))
2024-04-18 22:59:11 +10:00
result = curr->type == json_type_true;
return result;
}
2025-02-14 00:27:42 +11:00
void DN_JSON_ItErrorUnknownKeyValue_(DN_JSONIt *it, DN_CallSite call_site)
2024-04-18 22:59:11 +10:00
{
if (!it)
return;
2025-02-14 00:27:42 +11:00
json_object_element_s const *curr = DN_JSON_ItCurrObjElement(it);
2024-04-18 22:59:11 +10:00
if (!curr)
return;
size_t value_type_size = 0;
2025-02-14 00:27:42 +11:00
char const *value_type = DN_JSON_TypeEnumCString(DN_CAST(json_type_e)curr->value->type, &value_type_size);
2024-04-18 22:59:11 +10:00
json_string_s const *key = curr->name;
if (it->flags & json_parse_flags_allow_location_information) {
2025-02-14 00:27:42 +11:00
json_string_ex_s const *info = DN_CAST(json_string_ex_s const *)key;
DN_Log_TypeFCallSite(DN_LogType_Warning,
2024-04-18 22:59:11 +10:00
call_site,
"Unknown key-value pair in object [loc=%zu:%zu, key=%.*s, value=%.*s]",
info->line_no,
info->row_no,
2025-02-14 00:27:42 +11:00
DN_CAST(int)key->string_size,
2024-04-18 22:59:11 +10:00
key->string,
2025-02-14 00:27:42 +11:00
DN_CAST(int)value_type_size,
2024-04-18 22:59:11 +10:00
value_type);
} else {
2025-02-14 00:27:42 +11:00
DN_Log_TypeFCallSite(DN_LogType_Warning,
2024-04-18 22:59:11 +10:00
call_site,
"Unknown key-value pair in object [key=%.*s, value=%.*s]",
2025-02-14 00:27:42 +11:00
DN_CAST(int)key->string_size,
2024-04-18 22:59:11 +10:00
key->string,
2025-02-14 00:27:42 +11:00
DN_CAST(int)value_type_size,
2024-04-18 22:59:11 +10:00
value_type);
}
}