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

#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, \
}