|
Csilk 0.2.1
A lightweight, high-performance C HTTP web framework
|
Reflection and JSON binding implementation. More...
#include "csilk/reflection/reflect.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <uv.h>
Macros | |
| #define | MAX_REG_STRUCTS 256 |
Functions | |
| void | csilk_reflect_init (void) |
| Initialize the reflection system (called once at startup). | |
| static void | registry_lock (void) |
| Internal: acquire the global reflection registry mutex. | |
| static void | registry_unlock (void) |
| Internal: unlock the global reflection registry mutex. | |
| void | csilk_reflect_register (const char *name, const csilk_field_desc_t *fields, size_t count) |
| Register a struct type with the reflection engine. | |
| const csilk_reflect_entry_t * | csilk_reflect_find (const char *name) |
| Look up a registered type descriptor by name. | |
| void | csilk_reflect_foreach (csilk_reflect_foreach_cb cb, void *user_data) |
| Iterate over all registered reflection types and invoke a callback for each. | |
| static cJSON * | serialize_scalar (const void *addr, const csilk_field_desc_t *desc) |
| Internal: serialize a single struct field value to a cJSON node. | |
| static void | struct_to_cjson_internal (cJSON *obj, const void *struct_ptr, const csilk_field_desc_t *descs, size_t field_count) |
| Internal: walk all fields of a struct and build a cJSON object. | |
| static void | deserialize_scalar (const cJSON *item, void *addr, const csilk_field_desc_t *desc) |
| Internal: deserialize a cJSON value into a single struct field. | |
| static void | cjson_to_struct_internal (const cJSON *obj, void *struct_ptr, const csilk_field_desc_t *descs, size_t field_count) |
| Internal: walk a cJSON object and populate a struct's fields. | |
| static int | get_basic_type (const char *type_name, csilk_field_desc_t *out_desc) |
| char * | csilk_json_marshal (const char *type_name, const void *ptr) |
| Serialize a registered struct or basic type to a compact JSON string. | |
| int | csilk_json_unmarshal (const char *type_name, const char *json_str, void *ptr) |
| Deserialize a JSON string into a registered struct or basic type instance. | |
Variables | |
| static csilk_reflect_entry_t | g_registry [MAX_REG_STRUCTS] |
| static size_t | g_registry_count = 0 |
| static uv_mutex_t | g_registry_mutex |
| static int | g_registry_mutex_init = 0 |
Reflection and JSON binding implementation.
Architecture: The reflection system provides runtime type introspection via a global registry of struct descriptors. Each registered type stores an array of csilk_field_desc_t entries with field name, type, offset, size, and metadata (is_pointer, array_length, nested_type_name). The registry is a fixed-size array (256 entries) protected by a mutex for thread safety.
JSON marshalling (struct → JSON, csilk_json_marshal): Walk each field descriptor, compute the field's address by adding the compile-time offset to the struct base pointer, and serialize the value to a cJSON node. Nested structs trigger recursive serialization via a registry lookup of the nested type. Arrays serialize each element by stride (field->size) into a cJSON array.
JSON unmarshalling (JSON → struct, csilk_json_unmarshal): Parse the JSON string with cJSON_Parse, then for each field descriptor, look up the matching JSON key and deserialize the cJSON value into the field's memory address. String fields support both fixed-size buffers (strncpy) and heap-allocated pointers (malloc + copy). Nested structs are recursively deserialized with optional auto-allocation for pointer fields.
Both marshal and unmarshal have a fast path for basic scalar types (int, float, bool, string) — if type_name matches a known primitive, serialization bypasses the registry entirely.
Thread safety: All public functions lock the registry mutex for read/write access. csilk_reflect_foreach() uses two-phase iteration (collect names under lock, invoke callbacks outside lock) to avoid deadlock when callbacks re-enter the reflection API (e.g., add_schema() in swagger.c).
| #define MAX_REG_STRUCTS 256 |
|
static |
Internal: walk a cJSON object and populate a struct's fields.
For each field descriptor, looks up the matching JSON key in the cJSON object (case-sensitive using cJSON_GetObjectItemCaseSensitive). Array fields limit iteration to min(json_array_size, array_length). Non-matching keys are silently ignored.
| obj | Source cJSON object. |
| struct_ptr | Pointer to the target struct. |
| descs | Array of field descriptors. |
| field_count | Number of field descriptors. |
| char * csilk_json_marshal | ( | const char * | type_name, |
| const void * | ptr | ||
| ) |
Serialize a registered struct or basic type to a compact JSON string.
Serialise a reflected struct to a JSON string.
| int csilk_json_unmarshal | ( | const char * | type_name, |
| const char * | json_str, | ||
| void * | ptr | ||
| ) |
Deserialize a JSON string into a registered struct or basic type instance.
Deserialise a JSON string into a reflected struct.
| const csilk_reflect_entry_t * csilk_reflect_find | ( | const char * | name | ) |
Look up a registered type descriptor by name.
Look up a registered type by name.
Searches the global registry for a type matching name.
| name | Type name to find (case-sensitive). |
| void csilk_reflect_foreach | ( | csilk_reflect_foreach_cb | cb, |
| void * | user_data | ||
| ) |
Iterate over all registered reflection types and invoke a callback for each.
Iterate over all registered reflection types.
Collects type names into a temporary array while holding the registry lock, then releases the lock and invokes the callback for each name. This two-phase approach avoids deadlocks when the callback itself calls back into reflection APIs (e.g., csilk_reflect_find()).
| cb | Callback invoked once per registered type. |
| user_data | Opaque pointer passed through to the callback. |
| void csilk_reflect_init | ( | void | ) |
Initialize the reflection system (called once at startup).
Initialise the reflection subsystem.
Creates the global registry mutex. Idempotent — safe to call multiple times. Automatically called by csilk_server_new() and other entry points.
| void csilk_reflect_register | ( | const char * | name, |
| const csilk_field_desc_t * | fields, | ||
| size_t | count | ||
| ) |
Register a struct type with the reflection engine.
Manually register a struct type for reflection.
Adds a type name and its field descriptors to the global registry. Once registered, the type can be serialized/deserialized to/from JSON via csilk_json_marshal() / csilk_json_unmarshal(). The CSILK_REGISTER_REFLECT() macro generates the field array and calls this function automatically.
| name | Type name string (e.g., "my_request_t"). Must remain valid for the lifetime of the registration. |
| fields | Array of csilk_field_desc_t describing each struct field. |
| count | Number of fields in the array. |
|
static |
Internal: deserialize a cJSON value into a single struct field.
Maps cJSON types back to C primitives based on the field descriptor. For CSILK_TYPE_STRING, handles both fixed-size buffers (strncpy) and pointer fields (malloc + copy). For CSILK_TYPE_STRUCT, recursively calls cjson_to_struct_internal(). Null JSON values or missing items cause the field to be skipped (left at its current value).
| item | Source cJSON node (may be NULL or Null). |
| addr | Memory address of the target field. |
| desc | Field descriptor with type, size, and pointer flag. |
|
static |
|
static |
Internal: acquire the global reflection registry mutex.
Initializes the mutex on first call if not yet initialized. Blocks until the lock is acquired.
|
static |
Internal: unlock the global reflection registry mutex.
Must be called after registry_lock() to release the lock around the registered types table.
|
static |
Internal: serialize a single struct field value to a cJSON node.
Maps C primitive types and nested structs to cJSON values based on the field descriptor. Supports int8/16/32/64, uint8/16/32/64, float, double, bool, string (fixed-size buffer or pointer), and nested struct types. For nested structs, recursively calls struct_to_cjson_internal().
| addr | Memory address of the field within the source struct. |
| desc | Field descriptor specifying type, offset, and metadata. |
|
static |
Internal: walk all fields of a struct and build a cJSON object.
Iterates over the field descriptors, computes each field's address by adding the offset to the struct pointer, and serializes each field to a cJSON node added to the object. Array fields are serialized as cJSON arrays (one element per array slot). Non-array fields use the field's json_key as the object key.
| obj | Target cJSON object to populate. |
| struct_ptr | Pointer to the source struct (must not be NULL). |
| descs | Array of field descriptors. |
| field_count | Number of field descriptors. |
|
static |
|
static |
|
static |
|
static |