Support Byte Arrays in Glaze
Add byte_array wrapper for explicit fixed-size character array serialization. This introduces glz::byte_array.
Currently: char arr[4] = {0, 0, 1, 0}; std::string json; glz::write_json(arr, json); // Previously: json == """" (empty string - WRONG) // Expected: json == ""\u0000\u0000\u0001\u0000"" (desired behavior)
This happens because there's no way to distinguish between a regular character array and a byte array in C/C++.
This introduces:
char arr[4] = {0, 0, 1, 0};
// Traditional behavior (unchanged) glz::write_json(arr, json); // → ""
// NEW: Explicit byte array behavior glz::write_json(glz::byte_array{arr}, json); // → "\u0000\u0000\u0001\u0000"
Tested: Null-only arrays: glz::byte_array{char[3]{0,0,0}} → "\u0000\u0000\u0000" Mixed content: glz::byte_array{char[4]{'a',0,'b','\n'}} → "a\u0000b\n" Normal strings: glz::byte_array{char[5]{'h','e','l','l','o'}} → "hello" Round-trip: Full serialization and deserialization support
This was built in collaboration with GitHub Copilot. My apologies if I got something wrong. I'm also happy to take a different approach if you'd rather.
@kaladron, this approach works. But, what you're wanting is already supported by wrapping your char array in a std::string_view and then using the option: escape_control_characters
char raw[4] = {0, 0, 1, 0};
std::string_view view{raw, sizeof(raw)};
std::string buffer{};
expect(not glz::write<opts_escape_control_characters{}>(view, buffer));
expect(buffer == R"("\u0000\u0000\u0001\u0000")");
I do think an explicitly named wrapper type would make sense. But, I'm not sure what to name it. I think glz::byte_array is a little too generic, and doesn't sound like a slow, auto escaping wrapper. Maybe something like glz::escape_bytes_json. What do you think?
I got a bit swamped this week - I'll get to this shortly. Thank you!
I've added a new wrapper to support this use case of escaping byte arrays. Merged in #2079. So, this feature closes this pull request and the issue. Thanks for bringing this to my attention and your suggestions that helped inform this solution!
New glz::escape_bytes_t wrapper:
glz::escape_bytes_t(Runtime Wrapper): A new class template that allows direct wrapping of char arrays or std::vectorto explicitly signal that their content should be serialized and deserialized as a fully escaped JSON string. This ensures all bytes, including nulls and control characters, are preserved. glz::escape_bytes(Meta Wrapper): A corresponding variable template for use with glz::meta (reflection), enabling specific struct members to be declared as escaped byte sequences.
Local Usage (glz::escape_bytes_t{value}):
char local_data[4] = {0, 'A', 0, 'B'};
std::string out;
glz::write_json(glz::escape_bytes_t{local_data}, out);
expect(out == R"("\u0000A\u0000B")");
char read_back_data[4];
glz::read_json(glz::escape_bytes_t{read_back_data}, out);
expect(read_back_data[0] == 0);
expect(read_back_data[1] == 'A');
expect(read_back_data[2] == 0);
expect(read_back_data[3] == 'B');