You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
10 KiB
C
322 lines
10 KiB
C
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
|
|
#include "value.h"
|
|
#include "reflect/reflect.h"
|
|
|
|
enum {
|
|
reflect_json = 2,
|
|
};
|
|
#define REFLECT_JSON \
|
|
{ \
|
|
.offset = offsetof( OBJ_TYPE, json ), \
|
|
.type = reflect_json, \
|
|
}
|
|
|
|
struct json_pull_parser;
|
|
struct json_writer;
|
|
struct json_value;
|
|
struct json_reflection;
|
|
|
|
struct json_object_field;
|
|
struct json_field_type
|
|
{
|
|
bool (*reader )( struct json_pull_parser* jpp, void* field_data, struct json_reflection* json_type_data, int offset );
|
|
|
|
bool (*writer )( struct json_writer* jw, const char* field_name, void* field_data, struct json_reflection* json_type_data, int offset );
|
|
|
|
bool (*deserialize)( struct json_value value, void* field_data, struct json_reflection* json_type_data, int offset );
|
|
|
|
const char* type_string;
|
|
size_t size;
|
|
struct json_object_field* layout;
|
|
void* (*alloc)();
|
|
void (*free)( void* ptr );
|
|
};
|
|
|
|
#if __has_include("collections/enum_list_item.h")
|
|
#include "collections/enum_list_item.h"
|
|
#define json_enum enum_list_item
|
|
# else
|
|
struct json_enum
|
|
{
|
|
const char* name;
|
|
int value;
|
|
};
|
|
#endif
|
|
|
|
// Meta-fields
|
|
extern struct json_field_type json_field_inline_sublayout;
|
|
extern struct json_field_type json_field_extra;
|
|
|
|
// Integer
|
|
extern struct json_field_type json_field_integer;
|
|
|
|
// layout/bool.c
|
|
extern struct json_field_type json_field_bool;
|
|
extern struct json_field_type json_field_bool_or_null;
|
|
extern struct json_field_type json_field_fixed_bool;
|
|
extern struct json_field_type json_field_bool_callback;
|
|
struct rich_bool {
|
|
unsigned visible : 1;
|
|
unsigned value : 1;
|
|
};
|
|
extern struct json_field_type json_field_rich_bool;
|
|
|
|
// layout/string.c
|
|
extern struct json_field_type json_field_string;
|
|
extern struct json_field_type json_field_callback_string;
|
|
extern struct json_field_type json_field_fixed_string;
|
|
|
|
// layout/date
|
|
extern struct json_field_type json_field_date_time;
|
|
extern struct json_field_type json_field_empty_array;
|
|
|
|
// layout/object.c
|
|
extern struct json_field_type json_field_object_composite;
|
|
extern struct json_field_type json_field_fixed_null;
|
|
|
|
// layout/array.c
|
|
extern struct json_field_type json_field_array_of;
|
|
extern struct json_field_type json_field_single_or_array_of;
|
|
extern struct json_field_type json_field_array_of_objects;
|
|
|
|
// layout/enum.c
|
|
extern struct json_field_type json_field_enum;
|
|
|
|
// layout/tagged_union.c
|
|
extern struct json_field_type json_field_tagged_union;
|
|
|
|
bool json_field_object_type_reader ( struct json_pull_parser* jpp, void* field_data, struct json_reflection* json_field_data, int offset );
|
|
bool json_field_object_composite_reader( struct json_pull_parser* jpp, void* field_data, struct json_reflection* json_field_data, int offset );
|
|
|
|
bool json_field_object_type_writer ( struct json_writer* jw, const char* field_name, void* field_data, struct json_reflection* json_field_data, int offset );
|
|
bool json_field_object_composite_writer( struct json_writer* jw, const char* field_name, void* field_data, struct json_reflection* json_field_data, int offset );
|
|
|
|
struct json_tagged_union_typelist
|
|
{
|
|
int tag_value;
|
|
unsigned int offset;
|
|
struct json_field_type* type;
|
|
};
|
|
#define JSON_TAGGED_UNION_TYPELIST_END { .tag_value = 0 }
|
|
|
|
struct json_reflection // NOTE: this must be identical to the anonymous structure in json_object_field
|
|
{
|
|
const char* key;
|
|
struct json_field_type* type;
|
|
unsigned required : 1;
|
|
unsigned allow_drop_empty : 1;
|
|
unsigned always_write : 1;
|
|
union {
|
|
struct json_field_type* array_item_type;
|
|
struct json_enum* enum_list;
|
|
struct json_object_field* composite_layout;
|
|
struct json_object_field* sublayout;
|
|
struct json_tagged_union_typelist* tagged_item_types;
|
|
const char* fixed_string;
|
|
bool fixed_bool;
|
|
bool (*string_callback)( void* field_data, bool is_read, char** val );
|
|
bool (*bool_callback)( void* field_data, bool is_read, bool* val );
|
|
};
|
|
};
|
|
|
|
struct json_object_field
|
|
{
|
|
int offset; // TODO: break this out
|
|
|
|
struct {
|
|
const char* key;
|
|
struct json_field_type* type;
|
|
unsigned required : 1;
|
|
unsigned allow_drop_empty : 1;
|
|
unsigned always_write : 1;
|
|
union {
|
|
struct json_field_type* array_item_type;
|
|
struct json_enum* enum_list;
|
|
struct json_object_field* composite_layout;
|
|
struct json_object_field* sublayout;
|
|
struct json_tagged_union_typelist* tagged_item_types;
|
|
const char* fixed_string;
|
|
bool fixed_bool;
|
|
bool (*string_callback)( void* field_data, bool is_read, char** val );
|
|
bool (*bool_callback)( void* field_data, bool is_read, bool* val );
|
|
};
|
|
};
|
|
};
|
|
|
|
struct json_layout
|
|
{
|
|
int count;
|
|
int stride;
|
|
int* first_offset;
|
|
struct json_reflection* first_reflection;
|
|
};
|
|
|
|
enum {
|
|
jrol_flag_dont_ignore_unhandled = 1 << 0,
|
|
};
|
|
|
|
void json_layout_convert_legacy( struct json_object_field* legacy, struct json_layout* layout );
|
|
|
|
typedef bool (*json_layout_downcast_cb)( struct json_value obj, void** data, struct json_layout** new_layout );
|
|
|
|
bool json_read_reflection_with_downcast( struct json_pull_parser* jpp, struct reflection_list* reflect, void** data, json_layout_downcast_cb downcast );
|
|
|
|
bool json_read_object_layout_with_downcast( struct json_pull_parser* jpp, struct json_object_field* layout, void** data, json_layout_downcast_cb downcast );
|
|
bool json_read_object_layout_from_FILE_ex( FILE* f, struct json_object_field* layout, void** data, int flags, json_layout_downcast_cb downcast );
|
|
|
|
bool json_read_object_layout( struct json_pull_parser* jpp, struct json_object_field* layout, void* data );
|
|
bool json_read_object_layout_from_FILE( FILE* f, struct json_object_field* layout, void* data );
|
|
bool json_read_object_layout_from_file( const char* filename, struct json_object_field* layout, void* data );
|
|
bool json_read_object_layout_from_file_ex( const char* filename, struct json_object_field* layout, void* data, int flags );
|
|
bool json_read_object_layout_from_value( struct json_value value, struct json_object_field* layout, void* data );
|
|
|
|
void json_write_pretty_object_layout( struct json_writer* jw, struct json_object_field* layout, void* data );
|
|
void json_write_pretty_layout( struct json_writer* jw, struct json_layout* layout, void* data );
|
|
void json_write_array( struct json_writer* jw, struct json_field_type* array_item_type, void* data );
|
|
|
|
void json_write_object_layout( FILE* f, struct json_object_field* layout, void* data );
|
|
void json_write_object_layout_to_FILE( FILE* f, const char* indentation, struct json_object_field* layout, void* data );
|
|
void json_write_object_layout_to_file( const char* filename, const char* indentation, struct json_object_field* layout, void* data );
|
|
void json_write_object_layout_to_value( struct json_value* value, struct json_object_field* layout, void* data );
|
|
|
|
#define JSON_LAYOUT_FROM_LEGACY( type ) \
|
|
struct json_layout type ## _json_layout = { \
|
|
.stride = sizeof( type ## _layout[0] ),\
|
|
.count = sizeof( type ##_layout ) / sizeof( type ##_layout[0] ) - 1, \
|
|
.first_offset = &type ## _layout[0].offset ,\
|
|
.first_reflection = (struct json_reflection*)& type ## _layout[0].key, \
|
|
}
|
|
|
|
#define JSON_FIELD_END { .key = NULL }
|
|
#define JSON_FIELD_EMPTY_ARRAY( name, is_req ) { \
|
|
.key = #name, \
|
|
.required = is_req, \
|
|
.type = &json_field_empty_array, \
|
|
}
|
|
#define JSON_FIELD_ARRAY_OF_INTS( name, is_req ) {\
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_array_of, \
|
|
.array_item_type = &json_field_integer, \
|
|
}
|
|
#define JSON_FIELD_ARRAY_OF_STRINGS( name, is_req ) {\
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_array_of, \
|
|
.array_item_type = &json_field_string, \
|
|
}
|
|
#define JSON_FIELD_ARRAY_OF_TYPE( name, is_req, item_type ) {\
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_array_of, \
|
|
.array_item_type = &item_type, \
|
|
}
|
|
#define JSON_FIELD_ENUM( name, enums, is_req ) {\
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_enum, \
|
|
.enum_list = enums, \
|
|
}
|
|
|
|
#define JSON_FIELD_INTEGER( name, is_req ) { \
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_integer \
|
|
}
|
|
#define JSON_FIELD_STRING( name, is_req ) { \
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_string \
|
|
}
|
|
#define JSON_FIELD_FIXED_STRING( name, val, is_req ) { \
|
|
.key = #name, \
|
|
.required = is_req, \
|
|
.type = &json_field_fixed_string, \
|
|
.fixed_string = val, \
|
|
}
|
|
#define JSON_FIELD_FIXED_BOOL( name, val ) { \
|
|
.key = #name, \
|
|
.required = false, \
|
|
.type = &json_field_fixed_bool, \
|
|
.fixed_bool = val \
|
|
}
|
|
#define JSON_FIELD_BOOL( name, is_req ) { \
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_bool, \
|
|
}
|
|
#define JSON_FIELD_DATETIME( name, is_req ) { \
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.required = is_req, \
|
|
.type = &json_field_date_time, \
|
|
}
|
|
#define JSON_FIELD_FIXED_NULL( name ) { \
|
|
.key = #name, \
|
|
.required = false, \
|
|
.type = &json_field_fixed_null, \
|
|
}
|
|
#define JSON_FIELD_INLINE_SUBLAYOUT( name, layout ) \
|
|
{ \
|
|
.key = #name, \
|
|
.offset = offsetof( OBJ_TYPE, name ), \
|
|
.type = &json_field_inline_sublayout,\
|
|
.required = false, \
|
|
.sublayout = layout, \
|
|
}
|
|
|
|
|
|
#define JSON_FIELD_TYPE_COMPOSITE( name )\
|
|
struct json_field_type name ## _composite_type = { \
|
|
.reader = json_field_object_composite_reader,\
|
|
.writer = json_field_object_composite_writer,\
|
|
.size = sizeof( struct name ),\
|
|
.layout = name##_layout,\
|
|
.alloc = NULL, \
|
|
.free = NULL, \
|
|
};
|
|
|
|
#define JSON_FIELD_TYPE_OBJECT_LAYOUT( name ) \
|
|
struct json_field_type name ## _type = { \
|
|
.reader = json_field_object_type_reader, \
|
|
.writer = json_field_object_type_writer, \
|
|
.size = sizeof( struct name* ), \
|
|
.layout = name ## _layout, \
|
|
.alloc = name ## _alloc_shim , \
|
|
.free = name ## _free_shim, \
|
|
}
|
|
#define JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( name ) \
|
|
void* name ## _alloc_shim() {\
|
|
struct name* a;\
|
|
a = malloc(sizeof(*a));\
|
|
memset(a,0,sizeof(*a));\
|
|
return a; \
|
|
} \
|
|
void name ## _free_shim( void* ptr )\
|
|
{\
|
|
name ## _free(ptr);\
|
|
}\
|
|
struct json_field_type name ## _type = { \
|
|
.reader = json_field_object_type_reader, \
|
|
.writer = json_field_object_type_writer, \
|
|
.size = sizeof( struct name* ), \
|
|
.layout = name ## _layout, \
|
|
.alloc = name ## _alloc_shim, \
|
|
.free = name ## _free_shim, \
|
|
.type_string = #name, \
|
|
}
|
|
|
|
|