diff --git a/doc/basics.md b/doc/basics.md index 93d6275a8..c94e73ce0 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -23,6 +23,7 @@ separate document](https://github.com/simdjson/simdjson/blob/master/doc/builder. * [2. Use `tag_invoke` for custom types (C++20)](#2-use-tag_invoke-for-custom-types-c20) * [3. Using static reflection (C++26)](#3-using-static-reflection-c26) + [Special cases](#special-cases) + + [Renaming and skipping fields with annotations](#renaming-and-skipping-fields-with-annotations) * [The simdjson::from shortcut (experimental, C++20)](#the-simdjsonfrom-shortcut-experimental-c20) - [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing) - [UTF-8 validation (alone)](#utf-8-validation-alone) @@ -1592,6 +1593,49 @@ You can also automatically serialize the `Car` instance to a JSON string, see our [Builder documentation](builder.md). +#### Renaming fields and skipping fields with annotations + +C++26 annotations provide a convenient way to customize (de)serialization +without writing `tag_invoke` functions. You can rename the JSON key that +corresponds to a C++ data member, or skip a member entirely. + +The syntax is: + +```cpp +// rename cppFieldName (in C++) to json_key_name (in JSON) +[[= simdjson::rename<"json_key_name">]] std::string cppFieldName; +// do not serialize or deserialize this field +[[= simdjson::skip]] int internalState; +``` + +Full examples: + +```cpp +struct RenamedFields { + [[= simdjson::rename<"first_name">]] std::string firstName = ""; + [[= simdjson::rename<"last_name">]] std::string lastName = ""; + int age = 0; +}; + +struct SkippedField { + std::string name = ""; + [[= simdjson::skip]] int internalCache = 0; +}; + +struct MixedAnnotations { + [[= simdjson::rename<"user_name">]] std::string userName = ""; + [[= simdjson::skip]] int sessionToken = 0; + int age = 0; +}; +``` + +- Serialization via `simdjson::to_json(r)` or `builder << r` will use the renamed + keys and omit skipped fields. +- Deserialization via `doc.get()` will map the JSON keys back + to the C++ fields. Skipped fields are never written during deserialization + (they keep their default-initialized value), and keys matching skipped fields + in the JSON input are ignored. + ### The simdjson::from shortcut (experimental, C++20) diff --git a/doc/builder.md b/doc/builder.md index ec170c662..71ee59d89 100644 --- a/doc/builder.md +++ b/doc/builder.md @@ -12,6 +12,7 @@ speed and high convenience. * [Overview: string_builder](#overview--string-builder) * [Example: string_builder](#example--string-builder) * [C++26 static reflection](#c--26-static-reflection) + + [Renaming fields and skipping fields with annotations](#renaming-fields-and-skipping-fields-with-annotations) + [Without `string_buffer` instance](#without--string-buffer--instance) + [Without `string_buffer` instance but with explicit error handling](#without--string-buffer--instance-but-with-explicit-error-handling) + [Pretty formatted (fractured JSON)](#pretty-formatted-fractured-json) @@ -260,6 +261,45 @@ automatically. In most cases, it should work automatically: ``` +#### Renaming fields and skipping fields with annotations + +When using C++26 static reflection for automatic serialization (and deserialization), +you can annotate your struct members to rename the corresponding JSON keys or to +exclude fields from the JSON representation. + + +The syntax is: + +```cpp +// rename cppFieldName (in C++) to json_key_name (in JSON) +[[= simdjson::rename<"json_key_name">]] std::string cppFieldName; +// do not serialize or deserialize this field +[[= simdjson::skip]] int internalState; +``` + +For example: + +```cpp +struct Person { + [[= simdjson::rename<"first_name">]] std::string firstName = ""; + [[= simdjson::rename<"last_name">]] std::string lastName = ""; + [[= simdjson::skip]] int internalCache = 0; + int age = 0; +}; +``` + +Serialization then produces: + +```cpp +Person p{"Alice", "Smith", 999, 30}; +std::string json = simdjson::to_json(p); +// json == R"({"first_name":"Alice","last_name":"Smith","age":30})" +// Note: internalCache is omitted entirely. +``` + +The `skip` annotation also affects deserialization: the field keeps its default value +and any corresponding key in the input JSON is ignored. + ### Without `string_buffer` instance In some instances, you might want to create a string directly from your own data type.