Serialization (JSON Print)
Relevant source files
The following files were used as context for generating this wiki page:
Serialization in libfastjson is the process of converting an in-memory fjson_object tree into a JSON-formatted string or byte stream. The project provides multiple pathways for serialization, ranging from simple string generation to high-performance buffered dumping via user-supplied callbacks.
The core serialization logic is primarily contained within json_print.c, which was introduced to provide a more optimized and flexible alternative to the legacy json_object_to_json_string approach found in json_object.c.
Core Serialization Architecture
The serialization system is built around a recursive descent of the fjson_object structure. It uses a buffering mechanism to minimize the number of calls to output functions, which significantly improves performance when writing to files or network sockets.
Serialization Flow
The following diagram illustrates the high-level flow of a serialization request through the buffered dump system.
Sources: json_print.c:380-456, json_object.c:168-185
Key Serialization Functions
The library provides several levels of API for serialization, depending on the desired output target and performance requirements.
Standard Serialization
These functions return a const char* pointing to an internal buffer managed by the JSON object itself.
| Function | Description |
|---|---|
fjson_object_to_json_string(jso) | Serializes an object to a string with default spacing. |
fjson_object_to_json_string_ext(jso, flags) | Serializes an object with custom formatting flags. |
Sources: json_object.h:184-213, json_object.c:168-185
Buffered Dumping (High Performance)
These functions utilize a callback mechanism (fjson_write_fn) to stream the JSON output, avoiding the need to allocate a single large contiguous string in memory.
| Function | Description |
|---|---|
fjson_object_dump(jso, func, ptr) | Dumps JSON to a callback using default spaced formatting. |
fjson_object_dump_ext(jso, flags, func, ptr) | Dumps JSON to a callback with specific formatting flags. |
fjson_object_dump_buffered(jso, flags, temp, size, func, ptr) | Dumps JSON using a caller-provided temporary buffer for performance tuning. |
Sources: json_print.c:421-456, json_object.h:142-175
Formatting and Output Flags
The serialization process can be customized using bitwise flags passed to the _ext versions of the functions.
| Flag | Value | Description |
|---|---|---|
FJSON_TO_STRING_PLAIN | 0 | No extra whitespace or formatting. |
FJSON_TO_STRING_SPACED | (1<<0) | Minimal whitespace for readability. |
FJSON_TO_STRING_PRETTY | (1<<1) | Formatted with newlines and indentation. |
FJSON_TO_STRING_NOZERO | (1<<2) | Drops trailing zeros for floating point values. |
FJSON_TO_STRING_PRETTY_TAB | (1<<3) | Uses tabs instead of spaces for indentation. |
Sources: json_object.h:46-80, json_print.c:197-215
Internal Components and Logic
The Buffer Structure
In json_print.c, an internal struct buffer is used to manage chunks of serialized data. When the filled size reaches the size limit, the overflow function (the user's callback) is invoked to flush the data.
struct buffer {
char *buffer;
size_t size;
size_t filled;
fjson_write_fn *overflow;
void *ptr;
};
Sources: json_print.c:85-91
String Escaping Optimization
String escaping is a performance-critical path. libfastjson uses a lookup table char_needsEscape[256] to quickly identify characters that require escaping (e.g., quotes, backslashes, control characters). This approach avoids complex branching inside the inner loops.
Sources: json_print.c:147-195, json_object.c:82-137
Numeric Serialization Handling
The library handles double values with specific logic for special cases like NaN and Infinity, as these are not strictly part of the JSON RFC but are supported for compatibility (ECMA 262). It also compensates for localization issues where printf might use a comma instead of a period as a decimal separator.
if(isnan(jso->o.c_double.value)) return buffer_append(buffer, "NaN", 3);
if(isinf(jso->o.c_double.value)) return buffer_printf(buffer, jso->o.c_double.value > 0 ? "Infinity" : "-Infinity");
Sources: json_print.c:303-346, json_object.c:486-532
File and Utility Operations
The json_util.c module provides convenience wrappers for serializing directly to the filesystem.
fjson_object_to_file(filename, obj): Writes an object to a file using plain formatting.fjson_object_to_file_ext(filename, obj, flags): Opens a file (withO_WRONLY | O_TRUNC | O_CREAT) and writes the serialized string returned byfjson_object_to_json_string_ext.fjson_object_write(obj, fp): Writes directly to an already openFILE*using the high-performance dump mechanism and an internalfwritewrapper.
Sources: json_util.c:101-147, json_print.c:481-490
Summary
The serialization system in libfastjson is designed for speed and flexibility. By providing both a string-based API for simplicity and a buffered callback API for performance, it allows developers to choose the most efficient method for their specific use case. The inclusion of optimized escaping and configurable formatting makes it suitable for high-throughput environments like log processing.