Csilk 0.2.1
A lightweight, high-performance C HTTP web framework
Loading...
Searching...
No Matches
reflect.h File Reference
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "cJSON.h"
Include dependency graph for reflect.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  csilk_field_desc_t
 Descriptor for a single field in a reflected struct. More...
 
struct  csilk_reflect_entry_t
 Registration entry for a reflected type. More...
 

Macros

#define CSILK_USER_TYPE_MAP
 User-extensible type-name mapping.
 
#define csilk_type_name(x)
 Map a C expression's type to its reflected string name.
 
#define csilk_marshal(ptr)   csilk_json_marshal(csilk_type_name(*(ptr)), ptr)
 Convenience macro to serialise a reflected struct to a JSON string.
 
#define csilk_unmarshal(json, ptr)   csilk_json_unmarshal(csilk_type_name(*(ptr)), json, ptr)
 Convenience macro to deserialise a JSON string into a reflected struct.
 
#define CSILK_META_EXPAND(struct_type, field, type_enum, size, arr_len, is_ptr, nested_name)    {#field, type_enum, offsetof(struct_type, field), size, arr_len, is_ptr, nested_name},
 Internal helper: expand a single field into a csilk_field_desc_t initialiser.
 
#define CSILK_REGISTER_REFLECT(struct_type, map_macro)
 Automatically register a struct for reflection at program startup.
 

Typedefs

typedef void(* csilk_reflect_foreach_cb) (const char *name, const csilk_reflect_entry_t *entry, void *user_data)
 Callback type for csilk_reflect_foreach.
 

Enumerations

enum  csilk_field_type_t {
  CSILK_TYPE_INT8 , CSILK_TYPE_UINT8 , CSILK_TYPE_INT16 , CSILK_TYPE_UINT16 ,
  CSILK_TYPE_INT32 , CSILK_TYPE_UINT32 , CSILK_TYPE_INT64 , CSILK_TYPE_UINT64 ,
  CSILK_TYPE_FLOAT , CSILK_TYPE_DOUBLE , CSILK_TYPE_BOOL , CSILK_TYPE_STRING ,
  CSILK_TYPE_STRUCT
}
 Supported C data types for struct field reflection. More...
 

Functions

void csilk_reflect_init (void)
 Initialise the reflection subsystem.
 
void csilk_reflect_register (const char *name, const csilk_field_desc_t *fields, size_t count)
 Manually register a struct type for reflection.
 
const csilk_reflect_entry_tcsilk_reflect_find (const char *name)
 Look up a registered type by name.
 
void csilk_reflect_foreach (csilk_reflect_foreach_cb cb, void *user_data)
 Iterate over all registered reflection types.
 
char * csilk_json_marshal (const char *type_name, const void *ptr)
 Serialise a reflected struct to a JSON string.
 
int csilk_json_unmarshal (const char *type_name, const char *json_str, void *ptr)
 Deserialise a JSON string into a reflected struct.
 

Data Structure Documentation

◆ csilk_field_desc_s

struct csilk_field_desc_s

Descriptor for a single field in a reflected struct.

Forward declaration for the field descriptor struct.

Each field in a registered struct produces one of these descriptors, typically via the CSILK_META_EXPAND macro. The array of descriptors is NULL-terminated (sentinel entry with all-zero fields).

During marshalling, the engine walks the field descriptor array, reads offset bytes from the struct base, and converts the value according to type. During unmarshalling, JSON values are type-checked and written to the same offset. Nested structs (CSILK_TYPE_STRUCT) are resolved lazily by name at marshal/unmarshal time, allowing forward references.

Data Fields
size_t array_length

Number of elements for fixed-size C arrays (0 = scalar fields or pointer fields).

bool is_pointer

True if the field is a pointer type (char* or struct pointer). Affects how the field is read/written.

const char * json_key

JSON key name for this field (used during marshal/unmarshal; e.g., "user_name").

const char * nested_type_name

For CSILK_TYPE_STRUCT fields, the registered type name of the nested struct (resolved lazily at marshalling time to support forward declarations). NULL for non-struct fields.

size_t offset

Byte offset of this field from the struct base address (computed via offsetof).

size_t size

Size in bytes of one element (sizeof(field_type)). For arrays this is the element size, not the total.

csilk_field_type_t type

Data type enumerator (see csilk_field_type_t).

◆ csilk_reflect_entry_t

struct csilk_reflect_entry_t

Registration entry for a reflected type.

Stored in an internal hash map. Populated via csilk_reflect_register or automatically via the CSILK_REGISTER_REFLECT macro.

Data Fields
size_t count

Number of valid field descriptors (excluding sentinel).

const csilk_field_desc_t * fields

NULL-terminated array of field descriptors.

const char * name

Unique type name string (e.g., "User", "Config").

Macro Definition Documentation

◆ csilk_marshal

#define csilk_marshal (   ptr)    csilk_json_marshal(csilk_type_name(*(ptr)), ptr)

Convenience macro to serialise a reflected struct to a JSON string.

Automatically deduces the type name via csilk_type_name(*(ptr)).

Parameters
ptrPointer to a registered struct instance.
Returns
A heap-allocated JSON string (caller must free), or NULL on error.

◆ CSILK_META_EXPAND

#define CSILK_META_EXPAND (   struct_type,
  field,
  type_enum,
  size,
  arr_len,
  is_ptr,
  nested_name 
)     {#field, type_enum, offsetof(struct_type, field), size, arr_len, is_ptr, nested_name},

Internal helper: expand a single field into a csilk_field_desc_t initialiser.

Used by the map macro passed to CSILK_REGISTER_REFLECT. Each invocation produces one array element.

Parameters
struct_typeThe owning struct type name.
fieldThe field name.
type_enumcsilk_field_type_t enum value for this field.
sizesizeof() the field's type.
arr_lenArray element count (0 for scalar/pointer).
is_ptrNon-zero if the field is a pointer type.
nested_nameRegistered type name for CSILK_TYPE_STRUCT fields (ignored for other types).

◆ CSILK_REGISTER_REFLECT

#define CSILK_REGISTER_REFLECT (   struct_type,
  map_macro 
)
Value:
static csilk_field_desc_t struct_type##_meta[] = { \
map_macro(CSILK_META_EXPAND){NULL, 0, 0, 0, 0, false, NULL}}; \
static void __attribute__((constructor)) auto_reg_##struct_type(void) \
{ \
size_t count = (sizeof(struct_type##_meta) / sizeof(csilk_field_desc_t)) - 1; \
csilk_reflect_register(#struct_type, struct_type##_meta, count); \
}
#define CSILK_META_EXPAND(struct_type, field, type_enum, size, arr_len, is_ptr, nested_name)
Internal helper: expand a single field into a csilk_field_desc_t initialiser.
Definition reflect.h:267
struct __attribute__((packed))
Packed binary header prefixed to every WAL record.
Definition workflow_wal.h:54

Automatically register a struct for reflection at program startup.

Generates a static array of csilk_field_desc_t from the map_macro and registers it via a GCC constructor function (runs before main()). This means no explicit initialisation call is needed — types are available as soon as the program starts.

// Define a struct
typedef struct { int32_t id; char* name; } User;
// Map its fields (one _() invocation per field)
#define USER_MAP(_) \
_(User, id, CSILK_TYPE_INT32, sizeof(int32_t), 0, false, NULL) \
_(User, name, CSILK_TYPE_STRING, sizeof(char*), 0, true, NULL)
// Auto-register (this macro invocation must appear at file scope)
CSILK_REGISTER_REFLECT(User, USER_MAP)
#define CSILK_REGISTER_REFLECT(struct_type, map_macro)
Automatically register a struct for reflection at program startup.
Definition reflect.h:299
Parameters
struct_typeThe struct type name (used as the registration key in the reflection hash map and for generating internal symbol names).
map_macroA macro that applies CSILK_META_EXPAND to each field. Must produce exactly one CSILK_META_EXPAND(struct_type, field, type_enum, size, arr_len, is_ptr, nested_name) call per field.

◆ csilk_type_name

#define csilk_type_name (   x)
Value:
_Generic((x), \
_Bool: "bool", \
signed char: "int8", \
unsigned char: "uint8", \
short: "int16", \
unsigned short: "uint16", \
int: "int32", \
unsigned int: "uint32", \
long: "int64", \
unsigned long: "uint64", \
long long: "int64", \
unsigned long long: "uint64", \
float: "float", \
double: "double", \
char*: "string", \
const char*: "string" CSILK_USER_TYPE_MAP, \
default: "unknown")
#define CSILK_USER_TYPE_MAP
User-extensible type-name mapping.
Definition reflect.h:196

Map a C expression's type to its reflected string name.

Uses C11 _Generic dispatch. Extend with CSILK_USER_TYPE_MAP for user-defined types.

Parameters
xExpression whose static type determines the returned name.
Returns
A string literal naming the type (e.g., "string", "int32").

◆ csilk_unmarshal

#define csilk_unmarshal (   json,
  ptr 
)    csilk_json_unmarshal(csilk_type_name(*(ptr)), json, ptr)

Convenience macro to deserialise a JSON string into a reflected struct.

Automatically deduces the type name via csilk_type_name(*(ptr)).

Parameters
jsonNUL-terminated JSON string.
ptrPointer to a registered struct instance (must be pre-allocated).
Returns
0 on success, -1 on error.

◆ CSILK_USER_TYPE_MAP

#define CSILK_USER_TYPE_MAP

User-extensible type-name mapping.

Define CSILK_USER_TYPE_MAP before including csilk_reflect.h to add custom type-to-string mappings via _Generic. The default map handles char* and const char* as "string".

#define CSILK_USER_TYPE_MAP \
int: "int32", \
double: "double"

Typedef Documentation

◆ csilk_reflect_foreach_cb

typedef void(* csilk_reflect_foreach_cb) (const char *name, const csilk_reflect_entry_t *entry, void *user_data)

Callback type for csilk_reflect_foreach.

Invoked once per registered type.

Parameters
nameThe registered type name.
entryThe type descriptor entry.
user_dataOpaque pointer forwarded from csilk_reflect_foreach.

Enumeration Type Documentation

◆ csilk_field_type_t

Supported C data types for struct field reflection.

Each enumerator corresponds to a C type that the reflection system can read/write when marshalling to or from JSON.

Enumerator
CSILK_TYPE_INT8 

8-bit signed integer (int8_t / char).

CSILK_TYPE_UINT8 

8-bit unsigned integer (uint8_t / unsigned char).

CSILK_TYPE_INT16 

16-bit signed integer (int16_t / short).

CSILK_TYPE_UINT16 

16-bit unsigned integer (uint16_t / unsigned short).

CSILK_TYPE_INT32 

32-bit signed integer (int32_t / int).

CSILK_TYPE_UINT32 

32-bit unsigned integer (uint32_t / unsigned int).

CSILK_TYPE_INT64 

64-bit signed integer (int64_t / long long).

CSILK_TYPE_UINT64 

64-bit unsigned integer (uint64_t / unsigned long long).

CSILK_TYPE_FLOAT 

Single-precision IEEE 754 float.

CSILK_TYPE_DOUBLE 

Double-precision IEEE 754 double.

CSILK_TYPE_BOOL 

Boolean (C99 _Bool / bool).

CSILK_TYPE_STRING 

String: supports both char[] fixed buffers and char* pointers.

CSILK_TYPE_STRUCT 

Nested struct (by value or pointer). nested_type_name identifies the type.

Function Documentation

◆ csilk_json_marshal()

char * csilk_json_marshal ( const char *  type_name,
const void *  ptr 
)

Serialise a reflected struct to a JSON string.

Walks the field descriptors for type_name and produces a compact JSON string (no extra whitespace). String fields are properly escaped.

Parameters
type_nameRegistered type name of the struct.
ptrPointer to the struct instance to serialise.
Returns
A heap-allocated NUL-terminated JSON string (caller must free with free()), or NULL on error.

Serialise a reflected struct to a JSON string.

◆ csilk_json_unmarshal()

int csilk_json_unmarshal ( const char *  type_name,
const char *  json_str,
void *  ptr 
)

Deserialise a JSON string into a reflected struct.

Parses the JSON and populates the struct fields according to the registered field descriptors. Numeric type checking and range clamping are performed where possible.

Parameters
type_nameRegistered type name of the target struct.
json_strNUL-terminated JSON string to parse.
[out]ptrPointer to the struct instance to populate (must already be allocated and zero-initialised).
Returns
1 on success, 0 on parse error or type mismatch.

Deserialise a JSON string into a reflected struct.

◆ csilk_reflect_find()

const csilk_reflect_entry_t * csilk_reflect_find ( const char *  name)

Look up a registered type by name.

Parameters
nameType name string.
Returns
Pointer to the csilk_reflect_entry_t, or NULL if name has not been registered.

Look up a registered type by name.

Searches the global registry for a type matching name.

Parameters
nameType name to find (case-sensitive).
Returns
Pointer to the type's reflection entry, or NULL if not found.
Note
Thread-safe. The returned pointer is valid for the lifetime of the registration.

◆ csilk_reflect_foreach()

void csilk_reflect_foreach ( csilk_reflect_foreach_cb  cb,
void *  user_data 
)

Iterate over all registered reflection types.

Calls cb for each type in the registration table. Safe to call at any point — types registered via CSILK_REGISTER_REFLECT are available via GCC constructor functions that run before main().

Parameters
cbCallback invoked for each registered type (must not be NULL).
user_dataOpaque pointer forwarded to every cb invocation.

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()).

Parameters
cbCallback invoked once per registered type.
user_dataOpaque pointer passed through to the callback.
Note
Thread-safe. The callback receives a const pointer to the entry, but this pointer should not be stored beyond the callback invocation.

◆ csilk_reflect_init()

void csilk_reflect_init ( void  )

Initialise the reflection subsystem.

Sets up internal data structures (mutexes for thread-safe registration). Safe to call multiple times — subsequent calls are no-ops.

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.

Note
The reflection registry is a global array of up to MAX_REG_STRUCTS (256) entries protected by a mutex. All public reflection functions are thread-safe.

◆ csilk_reflect_register()

void csilk_reflect_register ( const char *  name,
const csilk_field_desc_t *  fields,
size_t  count 
)

Manually register a struct type for reflection.

Types registered with this function are immediately available for marshal/unmarshal operations. The name must be unique.

Parameters
nameType name string (must remain valid for the lifetime of the program — typically a string literal).
fieldsNULL-terminated array of csilk_field_desc_t.
countNumber of valid entries in fields (excluding the NULL-sentinel terminator).

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.

Parameters
nameType name string (e.g., "my_request_t"). Must remain valid for the lifetime of the registration.
fieldsArray of csilk_field_desc_t describing each struct field.
countNumber of fields in the array.
Note
Thread-safe. If the registry is full (256 types), the registration is silently dropped. Types registered first take precedence.