Skip to content

Implement JSON Configuration Field #3

@rtillery

Description

@rtillery

The JSON configuration field needs to be implemented so that the format of the output can be configured by the client. There are several options mentioned in the README.md. However, some of the desired use and behavior probably push toward a solution based on a union of a struct and a uint64_t that can be expressed as a number in the style field of the fmtster format. Some considerations:

  1. There needs to be a default style.
  2. The default style needs to be chosen by passing 0 (or empty) in the style field of the fmtster format. 0 is important to ensure that the type of the style field can consistently be a uint64_t, which cannot represent a blank entry.
  3. A value corresponding to a style needs to be able to be passed by the client, overriding the default style.
  4. The default style will be configurable by the client, so that the same style value does not need to be passed into every call (or parsed by every call). (The method for the client to set the default has not been worked out.)
  5. A structure containing all the configuration options would be easier for a client to use than constructing the
  6. The configuration structure will almost certainly be modified in future updates.

The style options being considered focus on the format of the spacing between the JSON-defined elements. At present, std::pair<string, ???> is not supported, and any other type supported by {fmt} is not affected by fmtster. So for now, all fmtster output begins with a C++ Standard Library container. There are two types of these containers, as far as serialization is concerned:

  • Elements have a single value
  • Elements are a key/value pair

The first of these is formatted in JSON as a JSON array, delimited by brackets. At this point, it is believed that there are three portions of the output which require style options:
[ <opt a> value, <opt b> value <opt c> ]

The second of the types of containers is formatted in JSON as a JSON object, delimited by braces. At this point, it is believed that there are seven portions of the output which require style options:
{ <opt 1> string <opt 2> : <opt 3> value, <opt 4> string <opt 5> : <opt 6> value <opt 7> }

There are various choices for each of these, many of which overlap. The approach that will be tried first will be to combine these into a selection of choices for each shown above. While the defaults of each of these will differ, the actual selection of choices will be the same for each. This means that some choices may not be appropriate for each , but the settings will be heeded anyway. Note that, because the choices are all the same, but the defaults differ, 0 will not be the default value for all these style options. This means that 0 will not be the default for each , so that the overall default value of the structure will not (via a union) map to 0. However, a value of 0 will be a valid setting, so some care will need to be taken to ensure no collision between a genuine style value of 0 (extremely unlikely, but nevertheless possible) and the intent to use 0 as a sentinel to represent whatever the current default style would be.

The choices for each field will be as listed below. There are currently 10 choices that make sense. These can be contained in four bits each. There may be up to four more fields added (much more likely to be just two, if at all), so the maximum number of four-bit options looks like it should be 14. 14 x 4 = 56. 56 bits fit within a 64-bit uint64_t with 8 bits remaining. It is the intention to use the remaining bits to represent some special circumstance style options, e.g. fitting a single element JSON object onto one line.

   spc/
\n tab ws ws
 0  0  0  0  - nothing
 0  0  0  1  - RESERVED
 0  0  1  0  - spc
 0  0  1  1  - spc spc
 0  1  0  0  - RESERVED
 0  1  0  1  - RESERVED
 0  1  1  0  - tab
 0  1  1  1  - tab tab
 1  0  0  0  - \n
 1  0  0  1  - RESERVED
 1  0  1  0  - \n spc
 1  0  1  1  - \n spc spc
 1  1  0  0  - RESERVED
 1  1  0  1  - RESERVED
 1  1  1  0  - \n tab
 1  1  1  1  - \n tab tab

\n represents a carriage return followed by indent (from the fourth format field) copies of the specified tab unit.
spc represents a single space
tab represents a single unit of the specified tab

Defaults at present look like they will be:

opt a: 1110: \n tab
opt b: 0010: spc
opt c: 0010: spc
opt 1: 1110: \n tab
opt 2: 0000: nothing
opt 3: 0010: spc
opt 4: 1110: \n tab
opt 5: 0000: nothing
opt 6: 0010: spc
opt 7: 1000: \n

This should be roughly equivalent to Google's documented style for JSON.

Using bitfields in a struct fmtster::JSONStyle is what is expected to start (adding a base struct/class for code reuse in serialization will follow), and then adding a new template<> struct fmt::formatter<fmtster::JSONStyle> that will use a union of this structure with a uint64_t to create a string representation of the configuration that is passed in the style field of the format. (This will be more difficult until Add Recursive Brace Support is resolved.) The number will then be parsed and converted back into a fmtster::JSONStyle using the same union approach.

Note that a single bit must be added that is always true, in order to prohibit a uint64_t value of 0, which would conflict with the sentinel value of 0 used to indicate use of the default style.

Some decision points:

  • Which numerical format is best for the string?
  • How can we optimize the conversion to/from the string?

Future considerations:

  • How can the following special cases be optimally fit into 7 or fewer bits?
    • Empty array same as style (use )
    • Empty array on same line (no space): []
    • Empty array on same line (one space): [ ]
    • Empty object same as style (use <opt 1>)
    • Empty object on same line (no space): {}
    • Empty object on same line (one space): { }
    • Single value array same as style
    • Single value array on same line if not array or object (opt a: no space/space, opt c: no space/space)
    • Single member object on same line if value not array or object (opt 1: no space/space, opt 2: no space/space, opt 3: no space/space, opt 7: no space/space)
    • Multi-set to repeated keys
    • Multi-set to single key with array as value

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions