Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/c-coroutine`
Browse files Browse the repository at this point in the history
Summary of commits:
- add json support handling, parson wrapper functions,
 * `json_for()`, `json_encode()`, `is_json()`, `json_read()`, `json_serialize()`, and `json_write()`
 * setup parson memory allocation routine
- add `fs_write_file` coroutine for libuv `uv_fs_write`
- add basic json example
- Merge PR#203 from `kgabis/parson`
  • Loading branch information
TheTechsTech committed Dec 22, 2023
1 parent 7948666 commit 99f0060
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 30 deletions.
2 changes: 1 addition & 1 deletion docs/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8...3.14)

add_subdirectory(echo-server)

set(TARGET_LIST child co_cpp_future_wait co_cpp_future test_delay chan_3 primes co_uv_fs co_uv_stream co_uv_listen co_uv_connect co_uv_spawn co_uv_url co_http_request co_http_response co_parse_http go_channel go_sleep go_select go_wait_group go_panic go_readfile go_multi_args)
set(TARGET_LIST child co_json co_cpp_future_wait co_cpp_future test_delay chan_3 primes co_uv_fs co_uv_stream co_uv_listen co_uv_connect co_uv_spawn co_uv_url co_http_request co_http_response co_parse_http go_channel go_sleep go_select go_wait_group go_panic go_readfile go_multi_args)
foreach (TARGET ${TARGET_LIST})
add_executable(${TARGET} ${TARGET}.c)
target_link_libraries(${TARGET} ze)
Expand Down
14 changes: 14 additions & 0 deletions docs/examples/co_json.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "ze.h"

int co_main(int argc, char **argv) {
json_t *encoded = json_encode("si.s.v",
kv("name", "John Smith"),
kv("age", 25),
kv("address.city", "Cupertino"),
kv("contact.emails", json_parse(json_for("ss", "email@example.com", "email2@example.com"))));

if (is_json(encoded))
puts(json_serialize(encoded, true));

return 0;
}
5 changes: 5 additions & 0 deletions include/compat/parson.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ JSON_Value *json_value_init_array(void);
JSON_Value *json_value_init_string(const char *string); /* copies passed string */
JSON_Value *json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */
JSON_Value *json_value_init_number(double number);
JSON_Value *json_value_init_number_as_string(const char *number);
JSON_Value *json_value_init_number_as_string_with_len(const char *number_as_string, size_t number_as_string_length);
JSON_Value *json_value_init_boolean(int boolean);
JSON_Value *json_value_init_null(void);
JSON_Value *json_value_deep_copy(const JSON_Value *value);
Expand All @@ -255,6 +257,9 @@ JSON_Array *json_value_get_array(const JSON_Value *value);
const char *json_value_get_string(const JSON_Value *value);
size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_value_get_number(const JSON_Value *value);
const char *json_value_get_number_as_string(const JSON_Value *value);
size_t json_value_get_number_as_string_len(const JSON_Value *value);

int json_value_get_boolean(const JSON_Value *value);
JSON_Value *json_value_get_parent(const JSON_Value *value);

Expand Down
10 changes: 10 additions & 0 deletions include/coroutine.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#endif

#include <time.h>
#include "compat/parson.h"

#if defined(_MSC_VER)
#define ZE_MPROTECT 1
Expand Down Expand Up @@ -386,6 +387,7 @@ typedef struct routine_s routine_t;
typedef struct oa_hash_s hash_t;
typedef struct ex_ptr_s ex_ptr_t;
typedef struct ex_context_s ex_context_t;
typedef struct json_value_t json_t;
typedef hash_t ht_string_t;
typedef hash_t wait_group_t;
typedef hash_t wait_result_t;
Expand Down Expand Up @@ -845,6 +847,14 @@ C_API u_string base64_decode(u_string_t src);

C_API int co_array_init(co_array_t *);

C_API bool is_json(json_t *schema);
C_API string json_serialize(json_t *json, bool is_pretty);
C_API json_t *json_parse(string_t text);
C_API json_t *json_read(string_t filename);
C_API int json_write(string_t filename, string_t text);
C_API json_t *json_encode(string_t desc, ...);
C_API string json_for(string_t desc, ...);

/* Creates an unbuffered channel, similar to golang channels. */
C_API channel_t *channel(void);

Expand Down
2 changes: 1 addition & 1 deletion include/uv_routine.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include <ctype.h>
#include "uv_tls.h"
#include "compat/parson.h"
#include <stdbool.h>

/* Public API qualifier. */
Expand Down Expand Up @@ -186,6 +185,7 @@ C_API void uv_close_free(void *handle);
C_API void coroutine_event_cleanup(void *handle);

C_API char *fs_readfile(const char *path);
C_API int fs_write_file(const char *path, const char *text);
C_API uv_file fs_open(const char *path, int flags, int mode);
C_API int fs_close(uv_file fd);
C_API uv_stat_t *fs_fstat(uv_file fd);
Expand Down
238 changes: 238 additions & 0 deletions src/json.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#include "../include/ze.h"

ZE_FORCE_INLINE bool is_json(json_t *schema) {
return (is_empty(schema) || json_value_get_type(schema) == JSONError) ? false : true;
}

string json_serialize(json_t *json, bool is_pretty) {
string json_string = NULL;
if (!is_empty(json)) {
if (is_pretty)
json_string = json_serialize_to_string_pretty((const json_t *)json);
else
json_string = json_serialize_to_string((const json_t *)json);

defer(json_free_serialized_string, json_string);
}

return json_string;
}

ZE_FORCE_INLINE int json_write(string_t filename, string_t text) {
return fs_write_file(filename, text);
}

ZE_FORCE_INLINE json_t *json_parse(string_t text) {
return json_parse_string(text);
}

json_t *json_read(string_t filename) {
string file_contents = fs_readfile(filename);
if (is_empty(file_contents))
return NULL;

return json_parse(file_contents);
}

json_t *json_encode(string_t desc, ...) {
int count = (int)strlen(desc);
json_t *json_root = json_value_init_object();
defer(json_value_free, json_root);
JSON_Object *json_object = json_value_get_object(json_root);

va_list argp;
string key, value_char;
int value_bool;
JSON_Status status = JSONSuccess;
void_t value_any = NULL;
JSON_Array *value_array = NULL;
double value_float = 0;
int64_t value_int = 0;
size_t value_max = 0;
bool is_dot = false, is_array = false, is_double = false, is_int = false, is_max = false;

va_start(argp, desc);
for (int i = 0; i < count; i++) {
switch (*desc++) {
case '.':
is_dot = true;
break;
case 'e':
if (is_array) {
is_array = false;
value_array = NULL;
is_dot = false;
}
break;
case 'a':
if (!is_array) {
key = va_arg(argp, string);
status = json_object_set_value(json_object, key, json_value_init_array());
value_array = json_object_get_array(json_object, key);
is_array = true;
is_dot = false;
}
break;
case 'n':
if (!is_array)
key = va_arg(argp, string);

if (is_array)
status = json_array_append_null(value_array);
else if (is_dot)
status = json_object_dotset_null(json_object, key);
else
status = json_object_set_null(json_object, key);
is_dot = false;
break;
case 'd':
is_int = true;
case 'f':
if (!is_int)
is_double = true;
case 'i':
if (!is_double && !is_int)
is_max = true;

if (!is_array)
key = va_arg(argp, string);

if (is_double)
value_float = va_arg(argp, double);
else if (is_int)
value_int = va_arg(argp, int64_t);
else
value_max = va_arg(argp, size_t);

if (is_array)
status = json_array_append_number(value_array, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));
else if (is_dot)
status = json_object_dotset_number(json_object, key, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));
else
status = json_object_set_number(json_object, key, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));

is_dot = false;
is_double = false;
is_int = false;
is_max = false;
break;
case 'b':
if (!is_array)
key = va_arg(argp, string);

value_bool = va_arg(argp, int);
if (is_array)
status = json_array_append_boolean(value_array, value_bool);
else if (is_dot)
status = json_object_dotset_boolean(json_object, key, value_bool);
else
status = json_object_set_boolean(json_object, key, value_bool);
is_dot = false;
break;
case 's':
if (!is_array)
key = va_arg(argp, string);

value_char = va_arg(argp, string);
if (is_array)
status = json_array_append_string(value_array, value_char);
else if (is_dot)
status = json_object_dotset_string(json_object, key, value_char);
else
status = json_object_set_string(json_object, key, value_char);
is_dot = false;
break;
case 'v':
if (!is_array)
key = va_arg(argp, string);

value_any = va_arg(argp, void_t);
if (is_array)
status = json_array_append_value(value_array, value_any);
else if (is_dot)
status = json_object_dotset_value(json_object, key, value_any);
else
status = json_object_set_value(json_object, key, value_any);
is_dot = false;
break;
default:
break;
}
}
va_end(argp);

return json_root;
}

string json_for(string_t desc, ...) {
int count = (int)strlen(desc);
json_t *json_root = json_value_init_object();
defer(json_value_free, json_root);
JSON_Object *json_object = json_value_get_object(json_root);
JSON_Status status = json_object_set_value(json_object, "array", json_value_init_array());
JSON_Array *value_array = json_object_get_array(json_object, "array");

va_list argp;
string value_char;
int value_bool;
void_t value_any = NULL;
double value_float = 0;
int64_t value_int = 0;
size_t value_max = 0;
bool is_double = false, is_int = false, is_max = false;

va_start(argp, desc);
for (int i = 0; i < count; i++) {
switch (*desc++) {
case 'n':
status = json_array_append_null(value_array);
break;
case 'd':
is_int = true;
case 'f':
if (!is_int)
is_double = true;
case 'i':
if (!is_double && !is_int)
is_max = true;

if (is_double)
value_float = va_arg(argp, double);
else if (is_int)
value_int = va_arg(argp, int64_t);
else
value_max = va_arg(argp, size_t);

status = json_array_append_number(value_array, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));
is_double = false;
is_int = false;
is_max = false;
break;
case 'b':
value_bool = va_arg(argp, int);
status = json_array_append_boolean(value_array, value_bool);
break;
case 's':
value_char = va_arg(argp, string);
status = json_array_append_string(value_array, value_char);
break;
case 'v':
value_any = va_arg(argp, void_t);
status = json_array_append_value(value_array, value_any);
break;
default:
break;
}
}
va_end(argp);

return json_serialize(json_array_get_wrapping_value(value_array), false);
}
Loading

0 comments on commit 99f0060

Please sign in to comment.