├── .github └── workflows │ └── test.yml ├── AUTHORS ├── CONTRIBUTORS ├── LICENSE ├── README.md ├── bench_test.go ├── go.mod ├── go.sum ├── images ├── benchmark-marshal-concrete-v1in2.png ├── benchmark-marshal-concrete.png ├── benchmark-marshal-interface.png ├── benchmark-marshal-rawvalue.png ├── benchmark-unmarshal-concrete-v1in2.png ├── benchmark-unmarshal-concrete.png ├── benchmark-unmarshal-interface.png └── benchmark-unmarshal-rawvalue.png ├── results ├── process.go └── results.log ├── testdata ├── JSONTestSuite │ ├── LICENSE │ ├── README.md │ ├── i_object_duplicated_key.json │ ├── i_object_duplicated_key_and_value.json │ ├── i_object_key_lone_2nd_surrogate.json │ ├── i_string_1st_surrogate_but_2nd_missing.json │ ├── i_string_1st_valid_surrogate_2nd_invalid.json │ ├── i_string_incomplete_surrogate_and_escape_valid.json │ ├── i_string_incomplete_surrogate_pair.json │ ├── i_string_incomplete_surrogates_escape_valid.json │ ├── i_string_invalid_lonely_surrogate.json │ ├── i_string_invalid_surrogate.json │ ├── i_string_inverted_surrogates_U+1D11E.json │ ├── i_string_lone_second_surrogate.json │ ├── i_structure_500_nested_arrays.json │ ├── i_structure_UTF-8_BOM_empty_object.json │ ├── n_array_1_true_without_comma.json │ ├── n_array_a_invalid_utf8.json │ ├── n_array_colon_instead_of_comma.json │ ├── n_array_comma_after_close.json │ ├── n_array_comma_and_number.json │ ├── n_array_double_comma.json │ ├── n_array_double_extra_comma.json │ ├── n_array_extra_close.json │ ├── n_array_extra_comma.json │ ├── n_array_incomplete.json │ ├── n_array_incomplete_invalid_value.json │ ├── n_array_inner_array_no_comma.json │ ├── n_array_invalid_utf8.json │ ├── n_array_items_separated_by_semicolon.json │ ├── n_array_just_comma.json │ ├── n_array_just_minus.json │ ├── n_array_missing_value.json │ ├── n_array_newlines_unclosed.json │ ├── n_array_number_and_comma.json │ ├── n_array_number_and_several_commas.json │ ├── n_array_spaces_vertical_tab_formfeed.json │ ├── n_array_star_inside.json │ ├── n_array_unclosed.json │ ├── n_array_unclosed_trailing_comma.json │ ├── n_array_unclosed_with_new_lines.json │ ├── n_array_unclosed_with_object_inside.json │ ├── n_incomplete_false.json │ ├── n_incomplete_null.json │ ├── n_incomplete_true.json │ ├── n_multidigit_number_then_00.json │ ├── n_number_++.json │ ├── n_number_+1.json │ ├── n_number_+Inf.json │ ├── n_number_-01.json │ ├── n_number_-1.0..json │ ├── n_number_-2..json │ ├── n_number_-NaN.json │ ├── n_number_.-1.json │ ├── n_number_.2e-3.json │ ├── n_number_0.1.2.json │ ├── n_number_0.3e+.json │ ├── n_number_0.3e.json │ ├── n_number_0.e1.json │ ├── n_number_0_capital_E+.json │ ├── n_number_0_capital_E.json │ ├── n_number_0e+.json │ ├── n_number_0e.json │ ├── n_number_1.0e+.json │ ├── n_number_1.0e-.json │ ├── n_number_1.0e.json │ ├── n_number_1_000.json │ ├── n_number_1eE2.json │ ├── n_number_2.e+3.json │ ├── n_number_2.e-3.json │ ├── n_number_2.e3.json │ ├── n_number_9.e+.json │ ├── n_number_Inf.json │ ├── n_number_NaN.json │ ├── n_number_U+FF11_fullwidth_digit_one.json │ ├── n_number_expression.json │ ├── n_number_hex_1_digit.json │ ├── n_number_hex_2_digits.json │ ├── n_number_infinity.json │ ├── n_number_invalid+-.json │ ├── n_number_invalid-negative-real.json │ ├── n_number_invalid-utf-8-in-bigger-int.json │ ├── n_number_invalid-utf-8-in-exponent.json │ ├── n_number_invalid-utf-8-in-int.json │ ├── n_number_minus_infinity.json │ ├── n_number_minus_sign_with_trailing_garbage.json │ ├── n_number_minus_space_1.json │ ├── n_number_neg_int_starting_with_zero.json │ ├── n_number_neg_real_without_int_part.json │ ├── n_number_neg_with_garbage_at_end.json │ ├── n_number_real_garbage_after_e.json │ ├── n_number_real_with_invalid_utf8_after_e.json │ ├── n_number_real_without_fractional_part.json │ ├── n_number_starting_with_dot.json │ ├── n_number_with_alpha.json │ ├── n_number_with_alpha_char.json │ ├── n_number_with_leading_zero.json │ ├── n_object_bad_value.json │ ├── n_object_bracket_key.json │ ├── n_object_comma_instead_of_colon.json │ ├── n_object_double_colon.json │ ├── n_object_emoji.json │ ├── n_object_garbage_at_end.json │ ├── n_object_key_with_single_quotes.json │ ├── n_object_lone_continuation_byte_in_key_and_trailing_comma.json │ ├── n_object_missing_colon.json │ ├── n_object_missing_key.json │ ├── n_object_missing_semicolon.json │ ├── n_object_missing_value.json │ ├── n_object_no-colon.json │ ├── n_object_non_string_key.json │ ├── n_object_non_string_key_but_huge_number_instead.json │ ├── n_object_repeated_null_null.json │ ├── n_object_several_trailing_commas.json │ ├── n_object_single_quote.json │ ├── n_object_trailing_comma.json │ ├── n_object_trailing_comment.json │ ├── n_object_trailing_comment_open.json │ ├── n_object_trailing_comment_slash_open.json │ ├── n_object_trailing_comment_slash_open_incomplete.json │ ├── n_object_two_commas_in_a_row.json │ ├── n_object_unquoted_key.json │ ├── n_object_unterminated-value.json │ ├── n_object_with_single_string.json │ ├── n_object_with_trailing_garbage.json │ ├── n_single_space.json │ ├── n_string_1_surrogate_then_escape.json │ ├── n_string_1_surrogate_then_escape_u.json │ ├── n_string_1_surrogate_then_escape_u1.json │ ├── n_string_1_surrogate_then_escape_u1x.json │ ├── n_string_UTF-16LE_with_BOM.json │ ├── n_string_UTF-8_invalid_sequence.json │ ├── n_string_UTF8_surrogate_U+D800.json │ ├── n_string_accentuated_char_no_quotes.json │ ├── n_string_backslash_00.json │ ├── n_string_escape_x.json │ ├── n_string_escaped_backslash_bad.json │ ├── n_string_escaped_ctrl_char_tab.json │ ├── n_string_escaped_emoji.json │ ├── n_string_incomplete_escape.json │ ├── n_string_incomplete_escaped_character.json │ ├── n_string_incomplete_surrogate.json │ ├── n_string_incomplete_surrogate_escape_invalid.json │ ├── n_string_invalid-utf-8-in-escape.json │ ├── n_string_invalid_backslash_esc.json │ ├── n_string_invalid_unicode_escape.json │ ├── n_string_invalid_utf-8.json │ ├── n_string_invalid_utf8_after_escape.json │ ├── n_string_iso_latin_1.json │ ├── n_string_leading_uescaped_thinspace.json │ ├── n_string_lone_utf8_continuation_byte.json │ ├── n_string_no_quotes_with_bad_escape.json │ ├── n_string_not_in_unicode_range.json │ ├── n_string_overlong_sequence_2_bytes.json │ ├── n_string_overlong_sequence_6_bytes.json │ ├── n_string_overlong_sequence_6_bytes_null.json │ ├── n_string_single_doublequote.json │ ├── n_string_single_quote.json │ ├── n_string_single_string_no_double_quotes.json │ ├── n_string_start_escape_unclosed.json │ ├── n_string_truncated-utf-8.json │ ├── n_string_unescaped_ctrl_char.json │ ├── n_string_unescaped_newline.json │ ├── n_string_unescaped_tab.json │ ├── n_string_unicode_CapitalU.json │ ├── n_string_utf16BE_no_BOM.json │ ├── n_string_utf16LE_no_BOM.json │ ├── n_string_with_trailing_garbage.json │ ├── n_structure_100000_opening_arrays.json │ ├── n_structure_U+2060_word_joined.json │ ├── n_structure_UTF8_BOM_no_data.json │ ├── n_structure_angle_bracket_..json │ ├── n_structure_angle_bracket_null.json │ ├── n_structure_array_trailing_garbage.json │ ├── n_structure_array_with_extra_array_close.json │ ├── n_structure_array_with_unclosed_string.json │ ├── n_structure_ascii-unicode-identifier.json │ ├── n_structure_capitalized_True.json │ ├── n_structure_close_unopened_array.json │ ├── n_structure_comma_instead_of_closing_brace.json │ ├── n_structure_double_array.json │ ├── n_structure_end_array.json │ ├── n_structure_incomplete_UTF8_BOM.json │ ├── n_structure_lone-invalid-utf-8.json │ ├── n_structure_lone-open-bracket.json │ ├── n_structure_no_data.json │ ├── n_structure_null-byte-outside-string.json │ ├── n_structure_number_with_trailing_garbage.json │ ├── n_structure_object_followed_by_closing_object.json │ ├── n_structure_object_unclosed_no_value.json │ ├── n_structure_object_with_comment.json │ ├── n_structure_object_with_trailing_garbage.json │ ├── n_structure_open_array_apostrophe.json │ ├── n_structure_open_array_comma.json │ ├── n_structure_open_array_object.json │ ├── n_structure_open_array_open_object.json │ ├── n_structure_open_array_open_string.json │ ├── n_structure_open_array_string.json │ ├── n_structure_open_object.json │ ├── n_structure_open_object_close_array.json │ ├── n_structure_open_object_comma.json │ ├── n_structure_open_object_open_array.json │ ├── n_structure_open_object_open_string.json │ ├── n_structure_open_object_string_with_apostrophes.json │ ├── n_structure_open_open.json │ ├── n_structure_single_eacute.json │ ├── n_structure_single_star.json │ ├── n_structure_trailing_#.json │ ├── n_structure_uescaped_LF_before_string.json │ ├── n_structure_unclosed_array.json │ ├── n_structure_unclosed_array_partial_null.json │ ├── n_structure_unclosed_array_unfinished_false.json │ ├── n_structure_unclosed_array_unfinished_true.json │ ├── n_structure_unclosed_object.json │ ├── n_structure_unicode-identifier.json │ ├── n_structure_whitespace_U+2060_word_joiner.json │ ├── n_structure_whitespace_formfeed.json │ ├── results.json │ ├── y_array_arraysWithSpaces.json │ ├── y_array_empty-string.json │ ├── y_array_empty.json │ ├── y_array_ending_with_newline.json │ ├── y_array_false.json │ ├── y_array_heterogeneous.json │ ├── y_array_null.json │ ├── y_array_with_1_and_newline.json │ ├── y_array_with_leading_space.json │ ├── y_array_with_several_null.json │ ├── y_array_with_trailing_space.json │ ├── y_number.json │ ├── y_number_0e+1.json │ ├── y_number_0e1.json │ ├── y_number_after_space.json │ ├── y_number_double_close_to_zero.json │ ├── y_number_double_huge_neg_exp.json │ ├── y_number_huge_exp.json │ ├── y_number_int_with_exp.json │ ├── y_number_minus_zero.json │ ├── y_number_neg_int_huge_exp.json │ ├── y_number_negative_int.json │ ├── y_number_negative_one.json │ ├── y_number_negative_zero.json │ ├── y_number_pos_double_huge_exp.json │ ├── y_number_real_capital_e.json │ ├── y_number_real_capital_e_neg_exp.json │ ├── y_number_real_capital_e_pos_exp.json │ ├── y_number_real_exponent.json │ ├── y_number_real_fraction_exponent.json │ ├── y_number_real_neg_exp.json │ ├── y_number_real_neg_overflow.json │ ├── y_number_real_pos_exponent.json │ ├── y_number_real_pos_overflow.json │ ├── y_number_real_underflow.json │ ├── y_number_simple_int.json │ ├── y_number_simple_real.json │ ├── y_number_too_big_neg_int.json │ ├── y_number_too_big_pos_int.json │ ├── y_number_very_big_negative_int.json │ ├── y_object.json │ ├── y_object_basic.json │ ├── y_object_empty.json │ ├── y_object_empty_key.json │ ├── y_object_escaped_null_in_key.json │ ├── y_object_extreme_numbers.json │ ├── y_object_long_strings.json │ ├── y_object_simple.json │ ├── y_object_string_unicode.json │ ├── y_object_with_newlines.json │ ├── y_string_1_2_3_bytes_UTF-8_sequences.json │ ├── y_string_accepted_surrogate_pair.json │ ├── y_string_accepted_surrogate_pairs.json │ ├── y_string_allowed_escapes.json │ ├── y_string_backslash_and_u_escaped_zero.json │ ├── y_string_backslash_doublequotes.json │ ├── y_string_comments.json │ ├── y_string_double_escape_a.json │ ├── y_string_double_escape_n.json │ ├── y_string_escaped_control_character.json │ ├── y_string_escaped_noncharacter.json │ ├── y_string_in_array.json │ ├── y_string_in_array_with_leading_space.json │ ├── y_string_last_surrogates_1_and_2.json │ ├── y_string_nbsp_uescaped.json │ ├── y_string_nonCharacterInUTF-8_U+10FFFF.json │ ├── y_string_nonCharacterInUTF-8_U+FFFF.json │ ├── y_string_null_escape.json │ ├── y_string_one-byte-utf-8.json │ ├── y_string_pi.json │ ├── y_string_reservedCharacterInUTF-8_U+1BFFF.json │ ├── y_string_simple_ascii.json │ ├── y_string_space.json │ ├── y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json │ ├── y_string_three-byte-utf-8.json │ ├── y_string_two-byte-utf-8.json │ ├── y_string_u+2028_line_sep.json │ ├── y_string_u+2029_par_sep.json │ ├── y_string_uEscape.json │ ├── y_string_uescaped_newline.json │ ├── y_string_unescaped_char_delete.json │ ├── y_string_unicode.json │ ├── y_string_unicodeEscapedBackslash.json │ ├── y_string_unicode_2.json │ ├── y_string_unicode_U+10FFFE_nonchar.json │ ├── y_string_unicode_U+1FFFE_nonchar.json │ ├── y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json │ ├── y_string_unicode_U+2064_invisible_plus.json │ ├── y_string_unicode_U+FDD0_nonchar.json │ ├── y_string_unicode_U+FFFE_nonchar.json │ ├── y_string_unicode_escaped_double_quote.json │ ├── y_string_utf8.json │ ├── y_string_with_del_character.json │ ├── y_structure_lonely_false.json │ ├── y_structure_lonely_int.json │ ├── y_structure_lonely_negative_real.json │ ├── y_structure_lonely_null.json │ ├── y_structure_lonely_string.json │ ├── y_structure_lonely_true.json │ ├── y_structure_string_empty.json │ ├── y_structure_trailing_newline.json │ ├── y_structure_true_in_array.json │ └── y_structure_whitespace_array.json ├── canada_geometry.json.gz ├── citm_catalog.json.gz ├── golang_source.json.gz ├── string_unicode.json.gz ├── synthea_fhir.json.gz └── twitter_status.json.gz └── testdata_test.go /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: [push, pull_request] 3 | jobs: 4 | test-format: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Install Go 8 | uses: actions/setup-go@v2 9 | with: 10 | go-version: 1.21.x 11 | - name: Checkout code 12 | uses: actions/checkout@v2 13 | - name: Format 14 | run: diff -u <(echo -n) <(gofmt -s -d .) 15 | - name: Test 16 | run: go test ./... 17 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at https://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at https://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSON Benchmarks 2 | 3 | Each of the charts below show the performance across 4 | several different JSON implementations: 5 | 6 | * `JSONv1` is `encoding/json` at `v1.23.5` 7 | * `JSONv1in2` is `github.com/go-json-experiment/json/v1` at `v0.0.0-20250127181117-bbe7ee0d7d2c` 8 | * `JSONv2` is `github.com/go-json-experiment/json` at `v0.0.0-20250127181117-bbe7ee0d7d2c` 9 | * `JSONIterator` is `github.com/json-iterator/go` at `v1.1.12` 10 | * `SegmentJSON` is `github.com/segmentio/encoding/json` at `v0.4.1` 11 | * `GoJSON` is `github.com/goccy/go-json` at `v0.10.4` 12 | * `SonicJSON` is `github.com/bytedance/sonic` at `v1.12.7` 13 | * `SonnetJSON` is `github.com/sugawarayuuta/sonnet` at `v0.0.0-20231004000330-239c7b6e4ce8` 14 | 15 | The `JSONv1in2` implementation replicates the `JSONv1` API and behavior 16 | purely in terms of the `JSONv2` implementation by setting the appropriate 17 | set of options to reproduce legacy v1 behavior. 18 | 19 | The Go toolchain used is `v1.23.5`. 20 | 21 | Based on the module proxy as of 2025-01-22, the relative popularity of each: 22 | * `JSONv1` has 1.3M imports 23 | * `JSONv1in2` has 8 imports 24 | * `JSONv2` has 213 imports 25 | * `JSONIterator` has 15k imports 26 | * `SegmentJSON` has 317 imports 27 | * `GoJSON` has 3k imports 28 | * `SonicJSON` has 1k imports 29 | * `SonnetJSON` has 13 imports 30 | 31 | Note that `JSONv2` deliberately dissuades users from depending on the package 32 | as it is an experiment and is subject to major breaking changes. 33 | 34 | Benchmarks were run across various datasets: 35 | 36 | * `CanadaGeometry` is a GeoJSON (RFC 7946) representation of Canada. 37 | It contains many JSON arrays of arrays of two-element arrays of numbers. 38 | * `CITMCatalog` contains many JSON objects using numeric names. 39 | * `SyntheaFHIR` is sample JSON data from the healthcare industry. 40 | It contains many nested JSON objects with mostly string values, 41 | where the set of unique string values is relatively small. 42 | * `TwitterStatus` is the JSON response from the Twitter API. 43 | It contains a mix of all different JSON kinds, where string values 44 | are a mix of both single-byte ASCII and multi-byte Unicode. 45 | * `GolangSource` is a simple tree representing the Go source code. 46 | It contains many nested JSON objects, each with the same schema. 47 | * `StringUnicode` contains many strings with multi-byte Unicode runes. 48 | 49 | All of the implementations other than `JSONv1`, `JSONv1in2`, `JSONv2`, and `Sonnet` make extensive use of `unsafe`. As such, we expect those to generally be faster, 50 | but at the cost of memory and type safety. `SonicJSON` goes a step even further 51 | and uses just-in-time compilation to generate machine code specialized 52 | for the Go type being marshaled or unmarshaled. 53 | Also, `SonicJSON` does not validate JSON strings for valid UTF-8, 54 | and so gains a notable performance boost on datasets with multi-byte Unicode. 55 | Benchmarks are performed based on the default marshal and unmarshal behavior 56 | of each package. Note that `JSONv2` aims to be safe and correct by default, 57 | which may not be the most performant strategy. 58 | 59 | `JSONv2` has several semantic changes relative to `JSONv1` that 60 | impacts performance: 61 | 62 | 1. When marshaling, `JSONv2` no longer sorts the keys of a Go map. 63 | This will improve performance. 64 | 65 | 2. When marshaling or unmarshaling, `JSONv2` always checks 66 | to make sure JSON object names are unique. 67 | This will hurt performance, but is more correct. 68 | 69 | 3. When marshaling or unmarshaling, `JSONv2` always 70 | shallow copies the underlying value for a Go interface and 71 | shallow copies the key and value for entries in a Go map. 72 | This is done to keep the value as addressable so that `JSONv2` can 73 | call methods and functions that operate on a pointer receiver. 74 | This will hurt performance, but is more correct. 75 | 76 | 4. When marshaling or unmarshaling, `JSONv2` supports calling 77 | type-defined methods or caller-defined functions with the current 78 | `jsontext.Encoder` or `jsontext.Decoder`. The `Encoder` or `Decoder` must 79 | contain a state machine to validate calls according to the JSON grammar. 80 | Maintaining this state will hurt performance. 81 | The `JSONv1` API provides no means for obtaining the `Encoder` or `Decoder` 82 | so it never needed to explicitly maintain a state machine. 83 | Conformance to the JSON grammar is implicitly accomplished 84 | by matching against the structure of the call stack. 85 | 86 | All of the charts are unit-less since the values are normalized 87 | relative to `JSONv1`, which is why `JSONv1` always has a value of 1. 88 | A lower value is better (i.e., runs faster). 89 | 90 | Benchmarks were performed on an AMD Ryzen 9 9950X. 91 | 92 | ## Marshal Performance 93 | 94 | ### Concrete types 95 | 96 | ![Benchmark Marshal Concrete](images/benchmark-marshal-concrete.png) 97 | 98 | * This compares marshal performance when serializing 99 | [from concrete types](/testdata_test.go). 100 | * Relative to `JSONv1`, `JSONv2` is 1.4x faster to 1.2x slower. 101 | * Relative to `JSONv1in2`, `JSONv2` is at performance parity. 102 | * Relative to `JSONIterator`, `JSONv2` is up to 1.2x faster. 103 | * Relative to `SegmentJSON`, `JSONv2` is up to 2.0x slower. 104 | * Relative to `GoJSON`, `JSONv2` is 1.1x faster to 1.4x slower. 105 | * Relative to `SonicJSON`, `JSONv2` is 1.2x to 3.4x slower 106 | (ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8). 107 | * Relative to `SonnetJSON`, `JSONv2` is up to 1.5x slower. 108 | * For `JSONv1` and `JSONv2`, marshaling from concrete types is 109 | significantly limited by the performance of Go reflection. 110 | 111 | ### Interface types 112 | 113 | ![Benchmark Marshal Interface](images/benchmark-marshal-interface.png) 114 | 115 | * This compares marshal performance when serializing from 116 | `any`, `map[string]any`, and `[]any` types. 117 | * Relative to `JSONv1`, `JSONv2` is 1.6x to 3.6x faster. 118 | * Relative to `JSONv1in2`, `JSONv2` is up to 2.2x faster. 119 | * Relative to `JSONIterator`, `JSONv2` is up to 2.6x faster. 120 | * Relative to `SegmentJSON`, `JSONv2` is 1.1x to 3.5x faster. 121 | * Relative to `GoJSON`, `JSONv2` is 1.5x to 3.5x faster. 122 | * Relative to `SonicJSON`, `JSONv2` is 1.4x faster to 1.3x slower 123 | (ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8). 124 | * Relative to `SonnetJSON`, `JSONv2` is up to 1.8x faster. 125 | * `JSONv2` is generally as fast or faster than the alternatives. 126 | One advantange is because it does not sort the keys for a `map[string]any`, 127 | while alternatives (except `JSONIterator`, `SonicJSON` and `SonnetJSON`) 128 | do sort the keys. 129 | 130 | ### RawValue types 131 | 132 | ![Benchmark Marshal Rawvalue](images/benchmark-marshal-rawvalue.png) 133 | 134 | * This compares performance when marshaling from a `jsontext.Value`. 135 | This mostly exercises the underlying encoder and 136 | hides the cost of Go reflection. 137 | * Relative to `JSONv1`, `JSONv2` is 5.6x to 12.0x faster. 138 | * Relative to `JSONv1in2`, `JSONv2` is up to 1.3x slower 139 | (since `JSONv2` needs to check for duplicate object names). 140 | * `JSONIterator` is blazingly fast because 141 | [it does not validate whether the raw value is valid](https://go.dev/play/p/bun9IXQCKRe) 142 | and simply copies it to the output. 143 | * Relative to `SegmentJSON`, `JSONv2` is 1.4x to 2.6x faster. 144 | * Relative to `GoJSON`, `JSONv2` is 2.7x faster to 1.4x slower. 145 | * Relative to `SonicJSON`, `JSONv2` is up to 1.8x faster 146 | (ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8). 147 | * Relative to `SonnetJSON`, `JSONv2` is at performance parity. 148 | * Aside from `JSONIterator` and `JSONv1in2`, 149 | `JSONv2` is generally as fast or fastest. 150 | 151 | ## Unmarshal Performance 152 | 153 | ### Concrete types 154 | 155 | ![Benchmark Unmarshal Concrete](images/benchmark-unmarshal-concrete.png) 156 | 157 | * This compares unmarshal performance when deserializing 158 | [into concrete types](/testdata_test.go). 159 | * Relative to `JSONv1`, `JSONv2` is 2.7x to 10.2x faster. 160 | * Relative to `JSONv1in2`, `JSONv2` is 1.1x to 1.3x faster. 161 | * Relative to `JSONIterator`, `JSONv2` is 1.3x faster to 1.5x slower. 162 | * Relative to `SegmentJSON`, `JSONv2` is up to 1.9x slower. 163 | * Relative to `GoJSON`, `JSONv2` is 1.3x to 1.8x slower. 164 | * Relative to `SonicJSON`, `JSONv2` is up to 2.8x slower 165 | (ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8). 166 | * Relative to `SonnetJSON`, `JSONv2` is up to 2.1x slower. 167 | * For `JSONv1` and `JSONv2`, unmarshaling into concrete types is 168 | significantly limited by the performance of Go reflection. 169 | 170 | ### Interface types 171 | 172 | ![Benchmark Unmarshal Interface](images/benchmark-unmarshal-interface.png) 173 | 174 | * This compares unmarshal performance when deserializing into 175 | `any`, `map[string]any`, and `[]any` types. 176 | * Relative to `JSONv1`, `JSONv2` is 2.3x to 5.7x faster. 177 | * Relative to `JSONv1in2`, `JSONv2` is 1.8x to 2.6x faster 178 | (since `JSONv1in2` lacks a specialized fast-path for interface types). 179 | * Relative to `JSONIterator`, `JSONv2` is up to 2.1x faster. 180 | * Relative to `SegmentJSON`, `JSONv2` is 2.5x to 4.6x faster. 181 | * Relative to `GoJSON`, `JSONv2` is up to 1.4x faster. 182 | * Relative to `SonicJSON`, `JSONv2` is 1.2x faster to 1.1x slower 183 | (ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8). 184 | * Relative to `SonnetJSON`, `JSONv2` is 1.2x to 1.8x slower. 185 | * Aside from `SonnetJSON`, `JSONv2` is generally just as fast 186 | or faster than all the alternatives. 187 | 188 | ### RawValue types 189 | 190 | ![Benchmark Unmarshal Rawvalue](images/benchmark-unmarshal-rawvalue.png) 191 | 192 | * This compares performance when unmarshaling into a `jsontext.Value`. 193 | This mostly exercises the underlying decoder and 194 | hides away most of the cost of Go reflection. 195 | * Relative to `JSONv1`, `JSONv2` is 10.2x to 21.1x faster. 196 | * Relative to `JSONv1in2`, `JSONv2` is 1.3x to 1.9x faster. 197 | * Relative to `JSONIterator`, `JSONv2` is up to 2.2x faster. 198 | * Relative to `SegmentJSON`, `JSONv2` is up to 2.0x slower. 199 | * Relative to `GoJSON`, `JSONv2` is 1.6x faster to 1.4x slower. 200 | * Relative to `SonicJSON`, `JSONv2` is up to 2.1x faster 201 | (ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8). 202 | * Relative to `SonnetJSON`, `JSONv2` is 1.2x faster to 1.3x slower. 203 | * `JSONv1` takes a 204 | [lexical scanning approach](https://talks.golang.org/2011/lex.slide#1), 205 | which performs a virtual function call for every byte of input. 206 | In contrast, `JSONv2` makes heavy use of iterative and linear parsing logic 207 | (with extra complexity to resume parsing when encountering segmented buffers). 208 | * Aside from `SegmentJSON`, `JSONv2` is generally just as fast 209 | or faster than all the alternatives. 210 | 211 | # Streaming 212 | 213 | When reading from an `io.Reader` and writing to an `io.Writer`, 214 | a JSON implementation should not need a buffer much larger than 215 | the largest JSON token encountered within the entire JSON value. 216 | For example, marshaling and unmarshaling a `[{},{},{},{},{},...]` 217 | that is a gigabyte in size should not need to buffer the entire JSON array, 218 | but only enough to buffer each individual `{` or `}`. 219 | An implementation with true streaming support will use 220 | a fixed amount of memory regardless of the total size of the JSON value. 221 | 222 | The following implementations have true streaming support: 223 | 224 | | Implementation | Marshal | Unmarshal | 225 | | -------------- | ------- | --------- | 226 | | JSONv1 | ❌ | ❌ | 227 | | JSONv1in2 | ❌ | ❌ | 228 | | JSONv2 | ✔️ | ✔️ | 229 | | JSONIterator | ❌ | ✔️ | 230 | | SegmentJSON | ❌ | ❌ | 231 | | GoJSON | ❌ | ❌ | 232 | | SonicJSON | ❌ | ❌ | 233 | | SonnetJSON | ❌ | ❌ | 234 | 235 | * `JSONv2` was designed from the beginning to have true streaming support. 236 | * `JSONIterator` (perhaps in honor of the "iterator" in its name) 237 | prioritize true streaming, but only for unmarshaling. 238 | 239 | See [`TestStreaming`](/bench_test.go#:~:text=TestStreaming) for more information. 240 | 241 | # Correctness 242 | 243 | A package may be fast, but it must still be correct and realiable. 244 | 245 | * `GoJSON` non-deterministically fails on some tests in this module: 246 | ``` 247 | --- FAIL: TestRoundtrip/TwitterStatus/Interface/GoJSON/MarshalWrite (0.04s) 248 | Marshal error: encoder: opcode has not been implemented 249 | ``` 250 | ``` 251 | --- FAIL: TestRoundtrip/GolangSource/Interface/GoJSON/MarshalWrite (0.16s) 252 | Marshal error: opcode SliceEnd has not been implemented 253 | ``` 254 | ``` 255 | --- FAIL: TestRoundtrip/GolangSource/Interface/GoJSON/Marshal 256 | Marshal error: invalid character ',' after object key 257 | ``` 258 | ``` 259 | --- FAIL: TestRoundtrip/TwitterStatus/Interface/GoJSON/MarshalWrite (0.01s) 260 | panic: runtime error: slice bounds out of range [10409248:74824] 261 | 262 | goroutine 111 [running]: 263 | testing.tRunner.func1.2({0xa3c220, 0xc002cec228}) 264 | go1.23.5/src/testing/testing.go:1632 +0x230 265 | testing.tRunner.func1() 266 | go1.23.5/src/testing/testing.go:1635 +0x35e 267 | panic({0xa3c220?, 0xc002cec228?}) 268 | go1.23.5/src/runtime/panic.go:785 +0x132 269 | github.com/goccy/go-json/internal/encoder/vm.Run(0xc00308a000, {0xc003088000?, 0x0?, 0x400?}, 0xc000ce9880?) 270 | github.com/goccy/go-json@v0.10.4/internal/encoder/vm/vm.go:440 +0x25ae5 271 | github.com/goccy/go-json.encodeRunCode(0xc00308a000?, {0xc003088000?, 0x0?, 0xc0001a53c0?}, 0xc002fb5d38?) 272 | github.com/goccy/go-json@v0.10.4/encode.go:310 +0x56 273 | github.com/goccy/go-json.encode(0xc00308a000, {0x9be140, 0xc002022fb0}) 274 | github.com/goccy/go-json@v0.10.4/encode.go:235 +0x205 275 | github.com/goccy/go-json.(*Encoder).encodeWithOption(0xc003093e58, 0xc00308a000, {0x9be140, 0xc002022fb0}, {0x0, 0x0, 0xc002fb5e90?}) 276 | github.com/goccy/go-json@v0.10.4/encode.go:77 +0x129 277 | github.com/goccy/go-json.(*Encoder).EncodeWithOption(0xc002fb5e58, {0x9be140, 0xc002022fb0}, {0x0, 0x0, 0x0}) 278 | github.com/goccy/go-json@v0.10.4/encode.go:42 +0x89 279 | github.com/goccy/go-json.(*Encoder).Encode(...) 280 | github.com/goccy/go-json@v0.10.4/encode.go:34 281 | jsonbench.init.func19({0xb55e20?, 0xc003086000?}, {0x9be140?, 0xc002022fb0?}) 282 | github.com/go-json-experiment/jsonbench/bench_test.go:121 +0x69 283 | jsonbench.TestRoundtrip.func3(0xc001fd0ea0) 284 | github.com/go-json-experiment/jsonbench/bench_test.go:175 +0x135 285 | testing.tRunner(0xc001fd0ea0, 0xc0004efa80) 286 | go1.23.5/src/testing/testing.go:1690 +0xf4 287 | created by testing.(*T).Run in goroutine 9 288 | go1.23.5/src/testing/testing.go:1743 +0x390 289 | exit status 2 290 | ``` 291 | ``` 292 | --- FAIL: TestRoundtrip/TwitterStatus/Interface/GoJSON/MarshalWrite (0.03s) 293 | panic: runtime error: invalid memory address or nil pointer dereference 294 | [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x859f9e] 295 | 296 | goroutine 114 [running]: 297 | testing.tRunner.func1.2({0x9f1ee0, 0xf8a7b0}) 298 | go1.23.5/src/testing/testing.go:1632 +0x230 299 | testing.tRunner.func1() 300 | go1.23.5/src/testing/testing.go:1635 +0x35e 301 | panic({0x9f1ee0?, 0xf8a7b0?}) 302 | go1.23.5/src/runtime/panic.go:785 +0x132 303 | github.com/goccy/go-json/internal/encoder/vm.Run(0xc003f32000, {0xc003f30000?, 0x0?, 0x400?}, 0xc003f3a000?) 304 | github.com/goccy/go-json@v0.10.4/internal/encoder/vm/vm.go:26 +0x5e 305 | github.com/goccy/go-json.encodeRunCode(0xc003f32000?, {0xc003f30000?, 0xc0026301c0?, 0xc00069cc40?}, 0xc003f21d38?) 306 | github.com/goccy/go-json@v0.10.4/encode.go:310 +0x56 307 | github.com/goccy/go-json.encode(0xc003f32000, {0x9be140, 0xc00203e580}) 308 | github.com/goccy/go-json@v0.10.4/encode.go:235 +0x205 309 | github.com/goccy/go-json.(*Encoder).encodeWithOption(0xc003f43e58, 0xc003f32000, {0x9be140, 0xc00203e580}, {0x0, 0x0, 0xc003f21e90?}) 310 | github.com/goccy/go-json@v0.10.4/encode.go:77 +0x129 311 | github.com/goccy/go-json.(*Encoder).EncodeWithOption(0xc003f21e58, {0x9be140, 0xc00203e580}, {0x0, 0x0, 0x0}) 312 | github.com/goccy/go-json@v0.10.4/encode.go:42 +0x89 313 | github.com/goccy/go-json.(*Encoder).Encode(...) 314 | github.com/goccy/go-json@v0.10.4/encode.go:34 315 | jsonbench.init.func19({0xb55e20?, 0xc003f28000?}, {0x9be140?, 0xc00203e580?}) 316 | github.com/go-json-experiment/jsonbench/bench_test.go:121 +0x69 317 | jsonbench.TestRoundtrip.func3(0xc00262e1a0) 318 | github.com/go-json-experiment/jsonbench/bench_test.go:175 +0x135 319 | testing.tRunner(0xc00262e1a0, 0xc000538c00) 320 | go1.23.5/src/testing/testing.go:1690 +0xf4 321 | created by testing.(*T).Run in goroutine 65 322 | go1.23.5/src/testing/testing.go:1743 +0x390 323 | exit status 2 324 | ``` 325 | ``` 326 | unexpected fault address 0x49af0034 327 | fatal error: fault 328 | [signal SIGSEGV: segmentation violation code=0x1 addr=0x49af0034 pc=0x859ffa] 329 | 330 | goroutine 27 gp=0xc0000d7880 m=29 mp=0xc006a0a008 [running]: 331 | runtime.throw({0xa79779?, 0x4871aa?}) 332 | go1.23.5/src/runtime/panic.go:1067 +0x48 fp=0xc0030b5908 sp=0xc0030b58d8 pc=0x473928 333 | runtime.sigpanic() 334 | go1.23.5/src/runtime/signal_unix.go:931 +0x26c fp=0xc0030b5968 sp=0xc0030b5908 pc=0x47552c 335 | github.com/goccy/go-json/internal/encoder/vm.Run(0xc0030ae000, {0xc00012fc00?, 0x0?, 0x400?}, 0xc003610000?) 336 | github.com/goccy/go-json@v0.10.4/internal/encoder/vm/vm.go:32 +0xba fp=0xc0030b7cb8 sp=0xc0030b5968 pc=0x859ffa 337 | github.com/goccy/go-json.encodeRunCode(0xc0030ae000?, {0xc00012fc00?, 0xc0000d7880?, 0xc000638a00?}, 0xc003088d38?) 338 | github.com/goccy/go-json@v0.10.4/encode.go:310 +0x56 fp=0xc0030b7cf0 sp=0xc0030b7cb8 pc=0x881056 339 | github.com/goccy/go-json.encode(0xc0030ae000, {0x9be140, 0xc000e90360}) 340 | github.com/goccy/go-json@v0.10.4/encode.go:235 +0x205 fp=0xc0030b7d70 sp=0xc0030b7cf0 pc=0x880be5 341 | github.com/goccy/go-json.(*Encoder).encodeWithOption(0xc0030b7e58, 0xc0030ae000, {0x9be140, 0xc000e90360}, {0x0, 0x0, 0xc0004aae90?}) 342 | github.com/goccy/go-json@v0.10.4/encode.go:77 +0x129 fp=0xc0030b7dc8 sp=0xc0030b7d70 pc=0x880729 343 | github.com/goccy/go-json.(*Encoder).EncodeWithOption(0xc003088e58, {0x9be140, 0xc000e90360}, {0x0, 0x0, 0x0}) 344 | github.com/goccy/go-json@v0.10.4/encode.go:42 +0x89 fp=0xc0030b7e28 sp=0xc0030b7dc8 pc=0x880569 345 | github.com/goccy/go-json.(*Encoder).Encode(...) 346 | github.com/goccy/go-json@v0.10.4/encode.go:34 347 | jsonbench.init.func19({0xb55e20?, 0xc00308aae0?}, {0x9be140?, 0xc000e90360?}) 348 | github.com/go-json-experiment/jsonbench/bench_test.go:121 +0x69 fp=0xc0030b7ea0 sp=0xc0030b7e28 pc=0x991b89 349 | jsonbench.TestRoundtrip.func3(0xc0004c5ba0) 350 | github.com/go-json-experiment/jsonbench/bench_test.go:175 +0x135 fp=0xc0030b7f70 sp=0xc0030b7ea0 pc=0x992f95 351 | testing.tRunner(0xc0004c5ba0, 0xc000277a00) 352 | go1.23.5/src/testing/testing.go:1690 +0xf4 fp=0xc0030b7fc0 sp=0xc0030b7f70 pc=0x535954 353 | testing.(*T).Run.gowrap1() 354 | go1.23.5/src/testing/testing.go:1743 +0x25 fp=0xc0030b7fe0 sp=0xc0030b7fc0 pc=0x536945 355 | runtime.goexit({}) 356 | go1.23.5/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0030b7fe8 sp=0xc0030b7fe0 pc=0x47b8e1 357 | created by testing.(*T).Run in goroutine 63 358 | go1.23.5/src/testing/testing.go:1743 +0x390 359 | ``` 360 | ``` 361 | runtime: marked free object in span 0x7f784c8c0910, elemsize=896 freeindex=3 (bad use of unsafe.Pointer? try -d=checkptr) 362 | 0xc0037b0000 alloc unmarked 363 | 0xc0037b0380 alloc marked 364 | 0xc0037b0700 alloc marked 365 | 0xc0037b0a80 free marked zombie 366 | 0x000000c0037b0a80: 0x0000000000a5ae00 0x0000000000000017 367 | 0x000000c0037b0a90: 0x000000c0037b0b00 0x000000c0037b0ce0 368 | 0x000000c0037b0aa0: 0x0000000000000000 0x0000000000000000 369 | 0x000000c0037b0ab0: 0x0000000000000000 0x0000000000000000 370 | 0x000000c0037b0ac0: 0x00000000009ed520 0x0000000000000000 371 | 0x000000c0037b0ad0: 0x0000000000000000 0x0000000000000000 372 | 0x000000c0037b0ae0: 0x0000000000000000 0x0000000000000000 373 | 0x000000c0037b0af0: 0x0000000000000000 0x0000000000000000 374 | 0x000000c0037b0b00: 0x0000001000000013 0x000000c0037b0b78 375 | 0x000000c0037b0b10: 0x0000000000000000 0x0000000000000000 376 | 0x000000c0037b0b20: 0x0000000000000000 0x0000000000000000 377 | 0x000000c0037b0b30: 0x0000000000000000 0x00000000009cc4c0 378 | 0x000000c0037b0b40: 0x0000000000000000 0x0000000000000000 379 | 0x000000c0037b0b50: 0x0000000000000000 0x0000000000000000 380 | 0x000000c0037b0b60: 0x0000000000000001 0x0000000000000000 381 | 0x000000c0037b0b70: 0x0000000000000000 0x0000000000000008 382 | 0x000000c0037b0b80: 0x000000c0037b0bf0 0x000000c0037b0ce0 383 | 0x000000c0037b0b90: 0x0000000000000000 0x0000000000000000 384 | 0x000000c0037b0ba0: 0x0000000000000000 0x0000000000000000 385 | 0x000000c0037b0bb0: 0x00000000009e1f40 0x0000000000000000 386 | 0x000000c0037b0bc0: 0x0000000000000000 0x0000000000000000 387 | 0x000000c0037b0bd0: 0x0000000000000000 0x0000000000000002 388 | 0x000000c0037b0be0: 0x0000000000000000 0x0000000000000000 389 | 0x000000c0037b0bf0: 0x0000002000000001 0x000000c0037b0c68 390 | 0x000000c0037b0c00: 0x0000000000000000 0x0000000000000000 391 | 0x000000c0037b0c10: 0x0000000000000000 0x0000000000000000 392 | 0x000000c0037b0c20: 0x0004000000000000 0x00000000009e1f40 393 | 0x000000c0037b0c30: 0x0000000000000000 0x0000000000000000 394 | 0x000000c0037b0c40: 0x0000000800000000 0x0000000000000001 395 | 0x000000c0037b0c50: 0x0000000000000003 0x0000000000000000 396 | 0x000000c0037b0c60: 0x0000000000000000 0x0000000000000007 397 | 0x000000c0037b0c70: 0x000000c0037b0b00 0x000000c0037b0ce0 398 | 0x000000c0037b0c80: 0x0000000000000000 0x0000000000000000 399 | 0x000000c0037b0c90: 0x0000000000000000 0x0000000000000000 400 | 0x000000c0037b0ca0: 0x00000000009cc4c0 0x0000000000000000 401 | 0x000000c0037b0cb0: 0x0000000000000000 0x0000000000000000 402 | 0x000000c0037b0cc0: 0x0000000000000000 0x0000000000000004 403 | 0x000000c0037b0cd0: 0x0000000000000000 0x0000000000000000 404 | 0x000000c0037b0ce0: 0x0000000000000009 0x000000c0037b0d58 405 | 0x000000c0037b0cf0: 0x0000000000000000 0x0000000000000000 406 | 0x000000c0037b0d00: 0x0000000000000000 0x0000000000000000 407 | 0x000000c0037b0d10: 0x0000000000000000 0x00000000009ed520 408 | 0x000000c0037b0d20: 0x0000000000000000 0x0000000000000000 409 | 0x000000c0037b0d30: 0x0000000000000000 0x0000000000000000 410 | 0x000000c0037b0d40: 0x0000000000000005 0x0000000000000000 411 | 0x000000c0037b0d50: 0x0000000000000000 0x000000400000000d 412 | 0x000000c0037b0d60: 0x0000000000000000 0x0000000000000000 413 | 0x000000c0037b0d70: 0x0000000000000000 0x0000000000000000 414 | 0x000000c0037b0d80: 0x0000000000000000 0x0000000000000000 415 | 0x000000c0037b0d90: 0x00000000009ed520 0x0000000000000000 416 | 0x000000c0037b0da0: 0x0000000000000000 0x0000005000000048 417 | 0x000000c0037b0db0: 0x0000000000000000 0x0000000000000006 418 | 0x000000c0037b0dc0: 0x0000000000000000 0x0000000000000000 419 | 0x000000c0037b0dd0: 0x0000000000000000 0x0000000000000000 420 | 0x000000c0037b0de0: 0x0000000000000000 0x0000000000000000 421 | 0x000000c0037b0df0: 0x0000000000000000 0x0000000000000000 422 | 0xc0037b0e00 alloc marked 423 | 0xc0037b1180 alloc marked 424 | 0xc0037b1500 free unmarked 425 | 0xc0037b1880 free unmarked 426 | 0xc0037b1c00 free unmarked 427 | fatal error: found pointer to free object 428 | ``` 429 | 430 | ## Use of `unsafe` 431 | 432 | While it is possible to use [`unsafe`](https://pkg.go.dev/unsafe) correctly, 433 | it is difficult to do so as you lose the benefits of type safety. 434 | Even experienced Go programmers have introduced bugs with `unsafe` that 435 | could lead to memory corruption, remote code execution, or worse. 436 | 437 | The following table shows whether each implementation uses `unsafe`: 438 | 439 | | Implementation | Uses `unsafe` | 440 | | -------------- | ------------- | 441 | | JSONv1 | 🛡️ no | 442 | | JSONv1in2 | 🛡️ no | 443 | | JSONv2 | 🛡️ no | 444 | | JSONIterator | 💣 yes | 445 | | SegmentJSON | 💣 yes | 446 | | GoJSON | 💣 yes | 447 | | SonicJSON | 💣 yes | 448 | | SonnetJSON | 🛡️ no | 449 | 450 | Notes: 451 | * `GoJSON` has reproducible races and bugs that lead to memory corruption. 452 | It is not safe for production use. 453 | * `SonicJSON` includes a just-in-time compiler, which makes it harder 454 | to statically verify that the resulting assembly at runtime is safe. 455 | * `SonnetJSON` is admirably fast while still avoiding use of `unsafe`. 456 | 457 | Our test suite was unable to trigger any memory corruption bugs 458 | in `JSONIterator`, `SegmentJSON`, or `SonicJSON`, which do use `unsafe`. 459 | Similarly, our test quite was unable to trigger any memory corruption bugs 460 | in `JSONv1`, `JSONv1in2`, `JSONv2`, and `SonnetJSON`, 461 | which do not use `unsafe`, but could still have race conditions. 462 | The inability to trigger bugs does not imply that there are no bugs. 463 | Caveat emptor. 464 | 465 | ## UTF-8 Validation 466 | 467 | According to [RFC 8259, section 8.1](https://datatracker.ietf.org/doc/html/rfc8259#section-8.1), 468 | a JSON value must be encoded using UTF-8. 469 | 470 | The following table shows how each implementation handles invalid UTF-8: 471 | 472 | | Implementation | Marshal | Unmarshal | 473 | | -------------- | ------------ | ----------- | 474 | | JSONv1 | ⚠️ replaced | ⚠️ replaced | 475 | | JSONv1in2 | ⚠️ replaced | ⚠️ replaced | 476 | | JSONv2 | ✔️ rejected | ✔️ rejected | 477 | | JSONIterator | ⚠️ replaced | ❌ ignored | 478 | | SegmentJSON | ⚠️ replaced | ⚠️ replaced | 479 | | GoJSON | ⚠️ replaced | ❌ ignored | 480 | | SonicJSON | ❌ ignored | ❌ ignored | 481 | | SonnetJSON | ⚠️ replaced | ⚠️ replaced | 482 | 483 | Notes: 484 | * "Rejected" means that the presence of invalid UTF-8 results in an error. 485 | This is the most correct behavior. 486 | * "Replaced" means that invalid UTF-8 bytes is replaced with `utf8.RuneError`. 487 | This can be arguably correct behavior for marshaling since it produces 488 | valid UTF-8 in the output, but silently corrupts strings with invalid UTF-8. 489 | This is incorrect behavior for unmarshaling since it treats 490 | non-complaint JSON as valid. 491 | * "Ignored" means that invalid UTF-8 is not checked for at all and 492 | is passed through during serialization. This is incorrect behavior. 493 | * Only `JSONv2` rejects invalid UTF-8 for both marshaling and unmarshaling. 494 | It provides an `AllowInvalidUTF8` option to opt into the "replaced" behavior. 495 | * `JSONv1` and `SegmentJSON` both follow the "replaced" behavior. 496 | * `JSONIterator` and `Segment` use the "replaced" behavior for marshaling 497 | and the incorrect "ignored" behavior for unmarshaling. 498 | * `SonicJSON` alone uses the incorrect "ignored" behavior 499 | for both marshaling and unmarshaling. 500 | 501 | See [`TestValidateUTF8`](/bench_test.go#:~:text=TestValidateUTF8) for more information. 502 | 503 | ## Duplicate Object Names 504 | 505 | [RFC 8259, section 4](https://datatracker.ietf.org/doc/html/rfc8259#section-4) 506 | specifies that handling of a JSON object with duplicate names results in 507 | undefined behavior where compliant parsers may use the first member, 508 | the last member, all the members, or report an error. 509 | [RFC 7493, section 2.3](https://datatracker.ietf.org/doc/html/rfc7493#section-2.3) 510 | specifies that JSON objects must not have duplicate names. 511 | Rejecting duplicate object names is more correct, 512 | but incurs a performance cost verifying this property. 513 | 514 | The following table shows how each implementation handles duplicate object names: 515 | 516 | | Implementation | Marshal | Unmarshal | 517 | | -------------- | ------------ | ----------- | 518 | | JSONv1 | ❌ allowed | ❌ allowed | 519 | | JSONv1in2 | ❌ allowed | ❌ allowed | 520 | | JSONv2 | ✔️ rejected | ✔️ rejected | 521 | | JSONIterator | ❌ allowed | ❌ allowed | 522 | | SegmentJSON | ❌ allowed | ❌ allowed | 523 | | GoJSON | ❌ allowed | ❌ allowed | 524 | | SonicJSON | ❌ allowed | ❌ allowed | 525 | | SonnetJSON | ❌ allowed | ❌ allowed | 526 | 527 | See [`TestDuplicateNames`](/bench_test.go#:~:text=TestDuplicateNames) for more information. 528 | 529 | ## Parsing Test Suite 530 | 531 | ["Parsing JSON is a Minefield 💣"](https://seriot.ch/projects/parsing_json.html) 532 | (posted 2016-10-26) performed one of the first thorough comparisons of 533 | JSON parsers and their behavior on various edge-cases. 534 | At the time, [RFC 7159](https://www.rfc-editor.org/rfc/rfc7159.html) 535 | was the authoritative standard, but has since been superseded by 536 | [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.html). 537 | Consequently, the expected results of some of the test cases from the article 538 | were changed to be more compliant with RFC 8259. 539 | 540 | The following table shows the number of test case failures 541 | for each implementation when tested against RFC 8259: 542 | 543 | | Implementation | String | Number | Object | Array | Other | 544 | | -------------- | ------ | ------- | ------ | ------- | ------ | 545 | | JSONv1 | ❌ 10x | ✔️ | ✔️ | ✔️ | ✔️ | 546 | | JSONv1in2 | ❌ 10x | ✔️ | ✔️ | ✔️ | ✔️ | 547 | | JSONv2 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | 548 | | JSONIterator | ❌ 10x | ❌ 4x | ✔️ | ✔️ | ✔️ | 549 | | SegmentJSON | ❌ 10x | ✔️ | ✔️ | ✔️ | ✔️ | 550 | | GoJSON | ❌ 30x | ❌ 52x | ❌ 20x | ❌ 17x | ❌ 10x | 551 | | SonicJSON | ❌ 28x | ✔️ | ✔️ | ❌ 1x | ✔️ | 552 | | SonnetJSON | ❌ 10x | ✔️ | ✔️ | ✔️ | ✔️ | 553 | 554 | * `JSONv1`, `JSONIterator`, and `SegmentJSON` all fail on the same set of 555 | JSON string tests that are related to UTF-8 validation. 556 | Presumably, `JSONIterator` and `SegmentJSON` copied `JSONv1`'s behavior 557 | because they aim to be drop-in replacements for `JSONv1`. 558 | * `GoJSON` and `SonicJSON` fails many more JSON string tests both in areas that 559 | relate to UTF-8 validation, but also in cases where the input is clearly 560 | not a valid JSON string (as agreed upon by the other implementations). 561 | * `JSONIterator` fails some JSON number tests. Some of these relate to values 562 | that are vastly beyond the representation of numeric Go types. 563 | These failures are technically permitted by [RFC 8259, section 9](https://datatracker.ietf.org/doc/html/rfc8259#section-9) when transforming JSON into another data representation. 564 | However, our tests were parsing the input into a `jsontext.Value`, 565 | where the limits of numeric precision should not play a relevant role. 566 | In other cases, `JSONIterator` permitted parsing of JSON numbers that 567 | are not valid (as agreed upon by the other implementations). 568 | * `GoJSON` fails many other test cases in all categories. 569 | 570 | [RFC 7493](https://www.rfc-editor.org/rfc/rfc7493.html) 571 | is compatible with RFC 8259 in that it makes strict decisions 572 | about behavior that RFC 8259 leaves undefined. 573 | In particular, it rejects escaped surrogate pairs that are invalid and 574 | rejects JSON object with duplicate names. 575 | 576 | The following table shows **additional** test case failures 577 | for each implementation when tested against RFC 7493: 578 | 579 | | Implementation | String | Number | Object | Array | Other | 580 | | -------------- | ------ | ------ | ------ | ----- | ----- | 581 | | JSONv1 | ❌ 9x | ✔️ | ❌ 3x | ✔️ | ✔️ | 582 | | JSONv1in2 | ❌ 9x | ✔️ | ❌ 3x | ✔️ | ✔️ | 583 | | JSONv2 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | 584 | | JSONIterator | ❌ 9x | ✔️ | ❌ 3x | ✔️ | ✔️ | 585 | | SegmentJSON | ❌ 9x | ✔️ | ❌ 3x | ✔️ | ✔️ | 586 | | GoJSON | ❌ 9x | ✔️ | ❌ 3x | ✔️ | ✔️ | 587 | | SonicJSON | ❌ 9x | ✔️ | ❌ 3x | ✔️ | ✔️ | 588 | | SonnetJSON | ❌ 9x | ✔️ | ❌ 3x | ✔️ | ✔️ | 589 | 590 | * `JSONv2` passes all cases since it targets compliance with RFC 7493. 591 | 592 | See [`TestParseSuite`](/bench_test.go#:~:text=TestParseSuite) for more information. 593 | 594 | ## MarshalJSON Validation 595 | 596 | A JSON implementation should not trust that the output of a `MarshalJSON` method 597 | is valid JSON nor formatted in the same way as surrounding JSON. 598 | Consequently, it should parse and reformat the JSON output to be consistent. 599 | 600 | The following table shows which implementations validate `MarshalJSON` output: 601 | 602 | | Implementation | Validates | 603 | | -------------- | --------- | 604 | | JSONv1 | ✔️ yes | 605 | | JSONv1in2 | ✔️ yes | 606 | | JSONv2 | ✔️ yes | 607 | | JSONIterator | ❌ no | 608 | | SegmentJSON | ✔️ yes | 609 | | GoJSON | ✔️ yes | 610 | | SonicJSON | ✔️ yes | 611 | | SonnetJSON | ✔️ yes | 612 | 613 | * `JSONIterator` naively mem-copies the result of `MarshalJSON` to 614 | the JSON output, resulting in drastic performance gains over 615 | alternative implementations. 616 | 617 | See [`TestValidateMarshalJSON`](/bench_test.go#:~:text=TestValidateMarshalJSON) for more information. 618 | 619 | ## Deterministic Map Ordering 620 | 621 | [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259) 622 | specifies that JSON objects are an "unordered collection". 623 | Thus, a compliant JSON marshaler need not serialize Go maps entries 624 | in any particular order. 625 | 626 | The `JSONv1` implementation historically sorted keys, which consequently 627 | set the precedence for other JSON implementations to do likewise. 628 | The `JSONv2` implementation no longer sorts keys for better performance 629 | and because it does not violate any specified facet of correctness. 630 | 631 | The following table shows which implementations deterministically marshal maps: 632 | 633 | | Implementation | Deterministic | 634 | | -------------- | ------------- | 635 | | JSONv1 | ✔️ yes | 636 | | JSONv1in2 | ✔️ yes | 637 | | JSONv2 | ❌ no | 638 | | JSONIterator | ❌ no | 639 | | SegmentJSON | ✔️ yes | 640 | | GoJSON | ✔️ yes | 641 | | SonicJSON | ❌ no | 642 | | SonnetJSON | ❌ no | 643 | 644 | See [`TestMapDeterminism`](/bench_test.go#:~:text=TestMapDeterminism) for more information. 645 | 646 | ## Observable Changes With Unmarshal Errors 647 | 648 | Implementations differ regarding how much of the output value is modified 649 | when an unmarshaling error is encountered. 650 | 651 | There are generally two reasonable behaviors: 652 | 1. Make no mutating changes to the output if the input is invalid. 653 | 2. Make as many changes as possible up until the input becomes invalid. 654 | 655 | The following table shows what changes are observable if the input is invalid: 656 | 657 | | Implementation | Observable Changes | 658 | | -------------- | ------------------ | 659 | | JSONv1 | ✔️ none | 660 | | JSONv1in2 | ✔️ none | 661 | | JSONv2 | ⚠️ all | 662 | | JSONIterator | ⚠️ all | 663 | | SegmentJSON | ❌ some | 664 | | GoJSON | ❌ some | 665 | | SonicJSON | ⚠️ all | 666 | | SonnetJSON | ❌ some | 667 | 668 | * The `JSONv1` implementation alone takes the first approach. 669 | This fundamentally requires a two-pass parsing, where the first pass 670 | validates the JSON input, and the second pass does the actual unmarshal work. 671 | All other implementations abandon this semantic since it is non-performant. 672 | * `JSONv2`, `JSONIterator`, and `Sonic` take the second approach of unmarshaling 673 | into the output as much as possible up until an error is encountered. 674 | * `SegmentJSON` and `GoJSON` hold to an odd position between the two extremes. 675 | 676 | See [`TestUnmarshalErrors`](/bench_test.go#:~:text=TestUnmarshalErrors) for more information. 677 | 678 | # Binary Size 679 | 680 | For use in embedded or mobile applications, a small binary size is a priority. 681 | The following table shows the binary sizes of each JSON implementation for 682 | a simple Go program that just links in `json.Marshal` and `json.Unmarshal`. 683 | These were built with `GOOS=linux` and `GOARCH=amd64`. 684 | 685 | | Implementation | Size | 686 | | -------------- | -------- | 687 | | JSONv1 | 2.511 MiB | 688 | | JSONv1in2 | 3.460 MiB | 689 | | JSONv2 | 3.394 MiB | 690 | | JSONIterator | 3.354 MiB | 691 | | SegmentJSON | 3.035 MiB | 692 | | GoJSON | 3.720 MiB | 693 | | SonicJSON | 7.100 MiB | 694 | | SonnetJSON | 2.479 MiB | 695 | 696 | * `JSONv2` adds more functionality than the other packages, 697 | so some amount of binary size increase is expected. 698 | * `SonicJSON` is the largest since it includes a just-in-time compiler. 699 | 700 | See [`TestBinarySize`](/bench_test.go#:~:text=TestBinarySize) for more information. 701 | -------------------------------------------------------------------------------- /bench_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package jsonbench 6 | 7 | import ( 8 | "bytes" 9 | "compress/gzip" 10 | "flag" 11 | "fmt" 12 | "io" 13 | "os" 14 | "os/exec" 15 | "path/filepath" 16 | "reflect" 17 | "runtime" 18 | "sort" 19 | "strconv" 20 | "strings" 21 | "testing" 22 | 23 | jsonv1 "encoding/json" 24 | 25 | sonicjson "github.com/bytedance/sonic" 26 | sonicdec "github.com/bytedance/sonic/decoder" 27 | sonicenc "github.com/bytedance/sonic/encoder" 28 | jsonv2 "github.com/go-json-experiment/json" 29 | jsontext "github.com/go-json-experiment/json/jsontext" 30 | jsonv1in2 "github.com/go-json-experiment/json/v1" 31 | gojson "github.com/goccy/go-json" 32 | jsoniter "github.com/json-iterator/go" 33 | segjson "github.com/segmentio/encoding/json" 34 | sonnetjson "github.com/sugawarayuuta/sonnet" 35 | 36 | "github.com/google/go-cmp/cmp" 37 | "github.com/google/go-cmp/cmp/cmpopts" 38 | "github.com/tailscale/hujson" 39 | "tailscale.com/util/must" 40 | ) 41 | 42 | func mustRead(path string) []byte { 43 | b := must.Get(os.ReadFile(path)) 44 | zr := must.Get(gzip.NewReader(bytes.NewReader(b))) 45 | b = must.Get(io.ReadAll(zr)) 46 | return b 47 | } 48 | 49 | func equalRawValue(x, y jsontext.Value) bool { 50 | normalize := func(v jsontext.Value) jsontext.Value { 51 | if v == nil { 52 | v = jsontext.Value("null") 53 | } 54 | v = v.Clone() 55 | v.Canonicalize() 56 | return v 57 | } 58 | return bytes.Equal(normalize(x), normalize(y)) 59 | } 60 | 61 | var testdata = []struct { 62 | name string 63 | new func() any 64 | data []byte 65 | }{ 66 | {"CanadaGeometry", func() any { return new(canadaRoot) }, mustRead("testdata/canada_geometry.json.gz")}, 67 | {"CITMCatalog", func() any { return new(citmRoot) }, mustRead("testdata/citm_catalog.json.gz")}, 68 | {"SyntheaFHIR", func() any { return new(syntheaRoot) }, mustRead("testdata/synthea_fhir.json.gz")}, 69 | {"TwitterStatus", func() any { return new(twitterRoot) }, mustRead("testdata/twitter_status.json.gz")}, 70 | {"GolangSource", func() any { return new(golangRoot) }, mustRead("testdata/golang_source.json.gz")}, 71 | {"StringUnicode", func() any { return new(stringRoot) }, mustRead("testdata/string_unicode.json.gz")}, 72 | } 73 | 74 | var arshalers = []struct { 75 | name string 76 | pkgPath string 77 | marshal func(any) ([]byte, error) 78 | unmarshal func([]byte, any) error 79 | marshalWrite func(io.Writer, any) error 80 | unmarshalRead func(io.Reader, any) error 81 | }{{ 82 | name: "JSONv1", 83 | pkgPath: "encoding/json", 84 | marshal: jsonv1.Marshal, 85 | unmarshal: jsonv1.Unmarshal, 86 | marshalWrite: func(w io.Writer, v any) error { return jsonv1.NewEncoder(w).Encode(v) }, 87 | unmarshalRead: func(r io.Reader, v any) error { return jsonv1.NewDecoder(r).Decode(v) }, 88 | }, { 89 | name: "JSONv1in2", 90 | pkgPath: "github.com/go-json-experiment/json/v1", 91 | marshal: jsonv1in2.Marshal, 92 | unmarshal: jsonv1in2.Unmarshal, 93 | marshalWrite: func(w io.Writer, v any) error { return jsonv1in2.NewEncoder(w).Encode(v) }, 94 | unmarshalRead: func(r io.Reader, v any) error { return jsonv1in2.NewDecoder(r).Decode(v) }, 95 | }, { 96 | name: "JSONv2", 97 | pkgPath: "github.com/go-json-experiment/json", 98 | marshal: func(v any) ([]byte, error) { return jsonv2.Marshal(v) }, 99 | unmarshal: func(b []byte, v any) error { return jsonv2.Unmarshal(b, v) }, 100 | marshalWrite: func(w io.Writer, v any) error { return jsonv2.MarshalWrite(w, v) }, 101 | unmarshalRead: func(r io.Reader, v any) error { return jsonv2.UnmarshalRead(r, v) }, 102 | }, { 103 | name: "JSONIterator", 104 | pkgPath: "github.com/json-iterator/go", 105 | marshal: jsoniter.Marshal, 106 | unmarshal: jsoniter.Unmarshal, 107 | marshalWrite: func(w io.Writer, v any) error { return jsoniter.NewEncoder(w).Encode(v) }, 108 | unmarshalRead: func(r io.Reader, v any) error { return jsoniter.NewDecoder(r).Decode(v) }, 109 | }, { 110 | name: "SegmentJSON", 111 | pkgPath: "github.com/segmentio/encoding/json", 112 | marshal: segjson.Marshal, 113 | unmarshal: segjson.Unmarshal, 114 | marshalWrite: func(w io.Writer, v any) error { return segjson.NewEncoder(w).Encode(v) }, 115 | unmarshalRead: func(r io.Reader, v any) error { return segjson.NewDecoder(r).Decode(v) }, 116 | }, { 117 | name: "GoJSON", 118 | pkgPath: "github.com/goccy/go-json", 119 | marshal: gojson.Marshal, 120 | unmarshal: gojson.Unmarshal, 121 | marshalWrite: func(w io.Writer, v any) error { return gojson.NewEncoder(w).Encode(v) }, 122 | unmarshalRead: func(r io.Reader, v any) error { return gojson.NewDecoder(r).Decode(v) }, 123 | }, { 124 | name: "SonicJSON", 125 | pkgPath: "github.com/bytedance/sonic", 126 | marshal: sonicjson.Marshal, 127 | unmarshal: sonicjson.Unmarshal, 128 | marshalWrite: func(w io.Writer, v any) error { return sonicenc.NewStreamEncoder(w).Encode(v) }, 129 | unmarshalRead: func(r io.Reader, v any) error { return sonicdec.NewStreamDecoder(r).Decode(v) }, 130 | }, { 131 | name: "SonnetJSON", 132 | pkgPath: "github.com/sugawarayuuta/sonnet", 133 | marshal: sonnetjson.Marshal, 134 | unmarshal: sonnetjson.Unmarshal, 135 | marshalWrite: func(w io.Writer, v any) error { return sonnetjson.NewEncoder(w).Encode(v) }, 136 | unmarshalRead: func(r io.Reader, v any) error { return sonnetjson.NewDecoder(r).Decode(v) }, 137 | }} 138 | 139 | func TestRoundtrip(t *testing.T) { 140 | for _, td := range testdata { 141 | td := td 142 | 143 | types := []struct { 144 | name string 145 | new func() any 146 | }{ 147 | {"Concrete", td.new}, 148 | {"Interface", func() any { return new(any) }}, 149 | {"RawValue", func() any { return new(jsontext.Value) }}, 150 | } 151 | for _, tt := range types { 152 | tt := tt 153 | 154 | // Use v1 as the reference point for correctness. 155 | wantVal := tt.new() 156 | must.Do(jsonv1.Unmarshal(td.data, wantVal)) 157 | 158 | // Check all other arshal implementation with respect to v1. 159 | for _, a := range arshalers { 160 | a := a 161 | if a.name == "V1" { 162 | continue // no need to test v1 with itself 163 | } 164 | 165 | for _, name := range []string{"Marshal", "MarshalWrite"} { 166 | t.Run(fmt.Sprintf("%s/%s/%s/%s", td.name, tt.name, a.name, name), func(t *testing.T) { 167 | t.Parallel() 168 | 169 | var gotBuf []byte 170 | switch name { 171 | case "Marshal": 172 | gotBuf = must.Get(a.marshal(wantVal)) 173 | case "MarshalWrite": 174 | bb := new(bytes.Buffer) 175 | must.Do(a.marshalWrite(bb, wantVal)) 176 | gotBuf = bb.Bytes() 177 | } 178 | 179 | // Checking the marshaled output is tricky. 180 | // Unmarshal it and verify it matches the result 181 | // obtained from unmarshaling using v1. 182 | gotVal := tt.new() 183 | must.Do(jsonv1.Unmarshal(gotBuf, gotVal)) 184 | if !reflect.DeepEqual(gotVal, wantVal) { 185 | if diff := cmp.Diff(gotVal, wantVal, 186 | cmpopts.EquateEmpty(), 187 | cmp.Comparer(equalRawValue), 188 | ); diff != "" { 189 | t.Fatalf("mismatch (-got +want):\n%s", diff) 190 | } 191 | } 192 | }) 193 | } 194 | 195 | for _, name := range []string{"Unmarshal", "UnmarshalRead"} { 196 | t.Run(fmt.Sprintf("%s/%s/%s/%s", td.name, tt.name, a.name, name), func(t *testing.T) { 197 | t.Parallel() 198 | 199 | gotVal := tt.new() 200 | switch name { 201 | case "Unmarshal": 202 | must.Do(a.unmarshal(td.data, gotVal)) 203 | case "UnmarshalRead": 204 | must.Do(a.unmarshalRead(bytes.NewReader(td.data), gotVal)) 205 | } 206 | 207 | if !reflect.DeepEqual(gotVal, wantVal) { 208 | if diff := cmp.Diff(gotVal, wantVal, 209 | cmp.Comparer(equalRawValue), 210 | ); diff != "" { 211 | t.Fatalf("mismatch (-got +want):\n%s", diff) 212 | } 213 | } 214 | }) 215 | } 216 | } 217 | } 218 | } 219 | } 220 | 221 | // TestStreaming tests whether the implementation is truly streaming, 222 | // meaning that encoding and decoding should not allocate any buffers 223 | // as large as the entire JSON value. 224 | func TestStreaming(t *testing.T) { 225 | wantStreaming := map[string]bool{ 226 | "JSONv1/Marshal": false, 227 | "JSONv1/Unmarshal": false, 228 | "JSONv1in2/Marshal": false, 229 | "JSONv1in2/Unmarshal": false, 230 | "JSONv2/Marshal": true, 231 | "JSONv2/Unmarshal": true, 232 | "JSONIterator/Marshal": false, 233 | "JSONIterator/Unmarshal": true, 234 | "SegmentJSON/Marshal": false, 235 | "SegmentJSON/Unmarshal": false, 236 | "GoJSON/Marshal": false, 237 | "GoJSON/Unmarshal": false, 238 | "SonicJSON/Marshal": false, 239 | "SonicJSON/Unmarshal": false, 240 | "SonnetJSON/Marshal": false, 241 | "SonnetJSON/Unmarshal": false, 242 | } 243 | 244 | const size = 1e6 245 | value := "[" + strings.TrimSuffix(strings.Repeat("{},", size), ",") + "]" 246 | for _, a := range arshalers { 247 | for _, funcName := range []string{"Marshal", "Unmarshal"} { 248 | name := fmt.Sprintf("%s/%s", a.name, funcName) 249 | t.Run(name, func(t *testing.T) { 250 | // Run GC multiple times to fully clear any sync.Pools. 251 | for i := 0; i < 10; i++ { 252 | runtime.GC() 253 | } 254 | 255 | // Measure allocations beforehand. 256 | var statsBefore runtime.MemStats 257 | runtime.ReadMemStats(&statsBefore) 258 | 259 | // Streaming marshal/unmarshal a large JSON array. 260 | switch funcName { 261 | case "Marshal": 262 | in := make([]struct{}, size) 263 | out := io.Discard 264 | must.Do(a.marshalWrite(out, &in)) 265 | case "Unmarshal": 266 | in := strings.NewReader(value) 267 | out := make([]struct{}, 0, size) 268 | must.Do(a.unmarshalRead(in, &out)) 269 | } 270 | 271 | // Measure allocations afterwards. 272 | var statsAfter runtime.MemStats 273 | runtime.ReadMemStats(&statsAfter) 274 | 275 | // True streaming implementations only use a small fixed buffer. 276 | allocBytes := statsAfter.TotalAlloc - statsBefore.TotalAlloc 277 | allocObjects := statsAfter.Mallocs - statsBefore.Mallocs 278 | gotStreaming := allocBytes < 1<<16 279 | if gotStreaming != wantStreaming[name] { 280 | t.Errorf("streaming = %v, want %v", gotStreaming, wantStreaming[a.name]) 281 | } 282 | t.Logf("%d bytes allocated, %d objects allocted", allocBytes, allocObjects) 283 | }) 284 | } 285 | } 286 | } 287 | 288 | // Per RFC 8259, section 8.1, JSON text must be encoded using UTF-8. 289 | func TestValidateUTF8(t *testing.T) { 290 | type mode string 291 | const ( 292 | ignored mode = "ignored" // invalid UTF-8 is ignored 293 | replaced mode = "replaced" // invalid UTF-8 is replaced with utf8.RuneError 294 | rejected mode = "rejected" // invalid UTF-8 is rejected 295 | ) 296 | wantModes := map[string]mode{ 297 | "JSONv1/Marshal": replaced, 298 | "JSONv1/Unmarshal": replaced, 299 | "JSONv1in2/Marshal": replaced, 300 | "JSONv1in2/Unmarshal": replaced, 301 | "JSONv2/Marshal": rejected, 302 | "JSONv2/Unmarshal": rejected, 303 | "JSONIterator/Marshal": replaced, 304 | "JSONIterator/Unmarshal": ignored, 305 | "SegmentJSON/Marshal": replaced, 306 | "SegmentJSON/Unmarshal": replaced, 307 | "GoJSON/Marshal": replaced, 308 | "GoJSON/Unmarshal": ignored, 309 | "SonicJSON/Marshal": ignored, 310 | "SonicJSON/Unmarshal": ignored, 311 | "SonnetJSON/Marshal": replaced, 312 | "SonnetJSON/Unmarshal": replaced, 313 | } 314 | for _, a := range arshalers { 315 | t.Run(a.name+"/Marshal", func(t *testing.T) { 316 | var got mode 317 | switch b, err := a.marshal("\xbe\xef\xff"); { 318 | case err == nil && string(b) == "\"\xbe\xef\xff\"": 319 | got = ignored 320 | case err == nil && string(b) == `"\ufffd\ufffd\ufffd"`: 321 | got = replaced 322 | case err != nil: 323 | got = rejected 324 | default: 325 | t.Errorf("unknown mode: json.Marshal = (%s, %v)", b, err) 326 | } 327 | if want := wantModes[a.name+"/Marshal"]; got != want { 328 | t.Errorf("mode = %s, want %s", got, want) 329 | } 330 | }) 331 | t.Run(a.name+"/Unmarshal", func(t *testing.T) { 332 | var got mode 333 | var s string 334 | switch err := a.unmarshal([]byte("\"\xbe\xef\xff\""), &s); { 335 | case err == nil && s == "\xbe\xef\xff": 336 | got = ignored 337 | case err == nil && s == "\ufffd\ufffd\ufffd": 338 | got = replaced 339 | case err != nil: 340 | got = rejected 341 | default: 342 | t.Errorf("unknown mode: json.Unmarshal = (%q, %v)", s, err) 343 | } 344 | if want := wantModes[a.name+"/Unmarshal"]; got != want { 345 | t.Errorf("mode = %s, want %s", got, want) 346 | } 347 | }) 348 | } 349 | } 350 | 351 | type duplicateText int 352 | 353 | func (duplicateText) MarshalText() ([]byte, error) { 354 | return []byte("duplicate"), nil 355 | } 356 | 357 | // RFC 8259 leaves handling of duplicate JSON object names as undefined. 358 | // RFC 7493 forbids the presence of duplicate JSON object names. 359 | func TestDuplicateNames(t *testing.T) { 360 | wantAllowDuplicates := map[string]bool{ 361 | "JSONv1": true, 362 | "JSONv1in2": true, 363 | "JSONv2": false, 364 | "JSONIterator": true, 365 | "SegmentJSON": true, 366 | "GoJSON": true, 367 | "SonicJSON": true, 368 | "SonnetJSON": true, 369 | } 370 | for _, a := range arshalers { 371 | t.Run(a.name+"/Marshal", func(t *testing.T) { 372 | _, err := a.marshal(map[duplicateText]int{0: 0, 1: 1}) 373 | gotAllowDuplicates := err == nil 374 | if gotAllowDuplicates != wantAllowDuplicates[a.name] { 375 | t.Errorf("AllowDuplicates = %v, want %v", gotAllowDuplicates, wantAllowDuplicates[a.name]) 376 | } 377 | }) 378 | } 379 | for _, a := range arshalers { 380 | t.Run(a.name+"/Unmarshal", func(t *testing.T) { 381 | var out map[string]int 382 | err := a.unmarshal([]byte(`{"duplicate":0,"duplicate":1}`), &out) 383 | gotAllowDuplicates := err == nil 384 | if gotAllowDuplicates != wantAllowDuplicates[a.name] { 385 | t.Errorf("AllowDuplicates = %v, want %v", gotAllowDuplicates, wantAllowDuplicates[a.name]) 386 | } 387 | }) 388 | } 389 | } 390 | 391 | var updateParseSuiteResults = flag.Bool("update-parse-suite-results", false, "update the results from running the parsing test suite") 392 | 393 | // TestParseSuite tests each JSON implementation against a suite of tests 394 | // that it correctly parses or rejects a given JSON input. 395 | // This test suite comes from "Parsing JSON is a Minefield 💣". 396 | // See https://seriot.ch/projects/parsing_json.html. 397 | func TestParseSuite(t *testing.T) { 398 | type results struct { 399 | GotPassingWantFailing map[string][]string 400 | GotFailingWantPassing map[string][]string 401 | GotPassingWantEither map[string][]string 402 | GotFailingWantEither map[string][]string 403 | } 404 | 405 | const dir = "testdata/JSONTestSuite" 406 | entries := must.Get(os.ReadDir(dir)) 407 | sort.Slice(entries, func(i, j int) bool { return entries[i].Name() < entries[j].Name() }) 408 | gotResults := results{make(map[string][]string), make(map[string][]string), make(map[string][]string), make(map[string][]string)} 409 | for _, entry := range entries { 410 | name := entry.Name() 411 | if !strings.HasSuffix(name, ".json") || name == "results.json" { 412 | continue 413 | } 414 | b := must.Get(os.ReadFile(filepath.Join(dir, name))) 415 | name = strings.TrimSuffix(name, ".json") 416 | for _, a := range arshalers { 417 | prefix, suffix, _ := strings.Cut(name, "_") 418 | switch err := a.unmarshal(b, new(jsontext.Value)); { 419 | case prefix == "n" && err == nil: 420 | gotResults.GotPassingWantFailing[suffix] = append(gotResults.GotPassingWantFailing[suffix], a.name) 421 | case prefix == "y" && err != nil: 422 | gotResults.GotFailingWantPassing[suffix] = append(gotResults.GotFailingWantPassing[suffix], a.name) 423 | case prefix == "i" && err == nil: 424 | gotResults.GotPassingWantEither[suffix] = append(gotResults.GotPassingWantEither[suffix], a.name) 425 | case prefix == "i" && err != nil: 426 | gotResults.GotFailingWantEither[suffix] = append(gotResults.GotFailingWantEither[suffix], a.name) 427 | } 428 | } 429 | } 430 | 431 | if *updateParseSuiteResults { 432 | b := must.Get(jsonv1.Marshal(gotResults)) 433 | b = append(bytes.TrimSuffix(b, []byte("}")), "\n}"...) // formatting hint for hujson.Format 434 | b, _ = hujson.Format(b) 435 | must.Do(os.WriteFile(filepath.Join(dir, "results.json"), b, 0664)) 436 | } else { 437 | want := must.Get(os.ReadFile(filepath.Join(dir, "results.json"))) 438 | var wantResults results 439 | must.Do(jsonv1.Unmarshal(want, &wantResults)) 440 | if diff := cmp.Diff(gotResults, wantResults); diff != "" { 441 | t.Fatalf("mismatch (-got +want):\n%s", diff) 442 | } 443 | } 444 | } 445 | 446 | // The output of a MarshalJSON method should be validated. 447 | func TestValidateMarshalJSON(t *testing.T) { 448 | type mode string 449 | const ( 450 | ignored mode = "ignored" // invalid MarshalJSON output ignored 451 | rejected mode = "rejected" // invalid MarshalJSON output rejected 452 | ) 453 | wantModes := map[string]mode{ 454 | "JSONv1": rejected, 455 | "JSONv1in2": rejected, 456 | "JSONv2": rejected, 457 | "JSONIterator": ignored, 458 | "SegmentJSON": rejected, 459 | "GoJSON": rejected, 460 | "SonicJSON": rejected, 461 | "SonnetJSON": rejected, 462 | } 463 | for _, a := range arshalers { 464 | t.Run(a.name, func(t *testing.T) { 465 | var got mode 466 | if _, err := a.marshal(jsontext.Value("")); err == nil { 467 | got = ignored 468 | } else { 469 | got = rejected 470 | } 471 | if want := wantModes[a.name]; got != want { 472 | t.Errorf("mode = %s, want %s", got, want) 473 | } 474 | }) 475 | } 476 | } 477 | 478 | // JSON specification does not specify any ordering for JSON object members. 479 | // Sorting the order is convenient, but is a performance cost. 480 | func TestMapDeterminism(t *testing.T) { 481 | wantDeterministic := map[string]bool{ 482 | "JSONv1": true, 483 | "JSONv1in2": true, 484 | "JSONv2": false, 485 | "JSONIterator": false, 486 | "SegmentJSON": true, 487 | "GoJSON": true, 488 | "SonicJSON": false, 489 | "SonnetJSON": false, 490 | } 491 | for _, a := range arshalers { 492 | t.Run(a.name, func(t *testing.T) { 493 | const iterations = 10 494 | in := map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} 495 | outs := make(map[string]bool) 496 | for i := 0; i < iterations; i++ { 497 | b, err := a.marshal(in) 498 | if err != nil { 499 | t.Fatalf("json.Marshal error: %v", err) 500 | } 501 | outs[string(b)] = true 502 | } 503 | gotDeterministic := len(outs) == 1 504 | wantDeterministic := wantDeterministic[a.name] 505 | switch { 506 | case gotDeterministic && !wantDeterministic: 507 | t.Log("deterministic = true, want false") 508 | case !gotDeterministic && wantDeterministic: 509 | t.Error("deterministic = false, want true") 510 | } 511 | }) 512 | } 513 | } 514 | 515 | // Implementations differ regarding how much of the output value is modified 516 | // when an unmarshaling error is encountered. 517 | // 518 | // There are generally two reasonable behaviors: 519 | // 1. Make no mutating changes to the output if the input is invalid. 520 | // 2. Make as many changes as possible up until the input becomes invalid. 521 | func TestUnmarshalErrors(t *testing.T) { 522 | type Struct struct{ A, B, C []int } 523 | want := map[string]Struct{ 524 | "JSONv1": {}, // none 525 | "JSONv1in2": {}, // none 526 | "JSONv2": {A: []int{1}, B: []int{2, 0}}, // all 527 | "JSONIterator": {A: []int{1}, B: []int{2, 0}}, // all 528 | "SegmentJSON": {A: []int{1}, B: []int{2}}, // some 529 | "GoJSON": {A: []int{1}}, // some 530 | "SonicJSON": {A: []int{1}, B: []int{2, 0}}, // all 531 | "SonnetJSON": {A: []int{1}}, // some 532 | } 533 | for _, a := range arshalers { 534 | t.Run(a.name, func(t *testing.T) { 535 | var out Struct 536 | err := a.unmarshal([]byte(`{"A":[1],"B":[2,invalid`), &out) 537 | if err == nil { 538 | t.Errorf("json.Unmarshal error is nil, want non-nil") 539 | } 540 | if !reflect.DeepEqual(out, want[a.name]) { 541 | t.Errorf("json.Unmarshal = %v, want %v", out, want[a.name]) 542 | } 543 | }) 544 | } 545 | } 546 | 547 | var checkBinarySize = flag.Bool("check-binary-size", false, "check binary sizes of each JSON implementation") 548 | 549 | func TestBinarySize(t *testing.T) { 550 | if !*checkBinarySize { 551 | t.Skip("--check-binary-size is not specified") 552 | } 553 | dir := must.Get(os.MkdirTemp(must.Get(os.Getwd()), "binsize")) 554 | defer os.RemoveAll(dir) 555 | t.Logf("GOOS:%s GOARCH:%s", runtime.GOOS, runtime.GOARCH) 556 | for _, a := range arshalers { 557 | t.Run(a.name, func(t *testing.T) { 558 | var bb bytes.Buffer 559 | bb.WriteString("package main\n") 560 | bb.WriteString("import json " + strconv.Quote(a.pkgPath) + "\n") 561 | bb.WriteString("var v any\n") 562 | bb.WriteString("func main() {\n") 563 | bb.WriteString("v, v = json.Marshal(v)\n") 564 | bb.WriteString("v = json.Unmarshal(v.([]byte), v)\n") 565 | bb.WriteString("}\n") 566 | must.Do(os.WriteFile(filepath.Join(dir, "main.go"), bb.Bytes(), 0664)) 567 | 568 | cmd := exec.Command("go", "build", "main.go") 569 | cmd.Dir = dir 570 | must.Do(cmd.Run()) 571 | 572 | t.Logf("size: %0.3f MiB", float64(must.Get(os.Stat(filepath.Join(dir, "main"))).Size())/(1<<20)) 573 | }) 574 | } 575 | } 576 | 577 | func Benchmark(b *testing.B) { 578 | for _, td := range testdata { 579 | types := []struct { 580 | name string 581 | new func() any 582 | }{ 583 | {"Concrete", td.new}, 584 | {"Interface", func() any { return new(any) }}, 585 | {"RawValue", func() any { return new(jsontext.Value) }}, 586 | } 587 | for _, tt := range types { 588 | for _, a := range arshalers { 589 | val := tt.new() 590 | must.Do(a.unmarshal(td.data, val)) 591 | b.Run(fmt.Sprintf("%s/%s/%s/Marshal", td.name, tt.name, a.name), func(b *testing.B) { 592 | b.ReportAllocs() 593 | for i := 0; i < b.N; i++ { 594 | must.Get(a.marshal(val)) 595 | } 596 | }) 597 | b.Run(fmt.Sprintf("%s/%s/%s/Unmarshal", td.name, tt.name, a.name), func(b *testing.B) { 598 | b.ReportAllocs() 599 | for i := 0; i < b.N; i++ { 600 | must.Do(a.unmarshal(td.data, tt.new())) 601 | } 602 | }) 603 | } 604 | } 605 | } 606 | } 607 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module jsonbench 2 | 3 | go 1.23 4 | 5 | toolchain go1.23.5 6 | 7 | require ( 8 | github.com/bytedance/sonic v1.12.7 9 | github.com/go-json-experiment/json v0.0.0-20250127181117-bbe7ee0d7d2c 10 | github.com/goccy/go-json v0.10.4 11 | github.com/google/go-cmp v0.5.9 12 | github.com/json-iterator/go v1.1.12 13 | github.com/segmentio/encoding v0.4.1 14 | github.com/sugawarayuuta/sonnet v0.0.0-20231004000330-239c7b6e4ce8 15 | github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a 16 | tailscale.com v1.48.1 17 | ) 18 | 19 | require ( 20 | github.com/bytedance/sonic/loader v0.2.3 // indirect 21 | github.com/cloudwego/base64x v0.1.5 // indirect 22 | github.com/klauspost/cpuid/v2 v2.2.9 // indirect 23 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 24 | github.com/modern-go/reflect2 v1.0.2 // indirect 25 | github.com/segmentio/asm v1.2.0 // indirect 26 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 27 | golang.org/x/arch v0.13.0 // indirect 28 | golang.org/x/sys v0.29.0 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q= 2 | github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I= 3 | github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= 4 | github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0= 5 | github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= 6 | github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= 7 | github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= 8 | github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/go-json-experiment/json v0.0.0-20250127181117-bbe7ee0d7d2c h1:yj4doSXUAvsxYRqmQNxyhmkl+Dl5QnaMo7YuCzXzRpw= 13 | github.com/go-json-experiment/json v0.0.0-20250127181117-bbe7ee0d7d2c/go.mod h1:BWmvoE1Xia34f3l/ibJweyhrT+aROb/FQ6d+37F0e2s= 14 | github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= 15 | github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 16 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 17 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 18 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 19 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 20 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 21 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 22 | github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= 23 | github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= 24 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= 25 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 26 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 27 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 28 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 29 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 30 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 31 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 32 | github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= 33 | github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= 34 | github.com/segmentio/encoding v0.4.1 h1:KLGaLSW0jrmhB58Nn4+98spfvPvmo4Ci1P/WIQ9wn7w= 35 | github.com/segmentio/encoding v0.4.1/go.mod h1:/d03Cd8PoaDeceuhUUUQWjU0KhWjrmYrWPgtJHYZSnI= 36 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 37 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 38 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 39 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 40 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 41 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 42 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 43 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 44 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 45 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 46 | github.com/sugawarayuuta/sonnet v0.0.0-20231004000330-239c7b6e4ce8 h1:u+kxnRXxx+0O5SiefP3oTt4jeeIx+rYf1jkdW2qd2Ss= 47 | github.com/sugawarayuuta/sonnet v0.0.0-20231004000330-239c7b6e4ce8/go.mod h1:6M53rd6DvbzoLbFnL3bjCsDSkCYh4i2yqW04hxr1/5o= 48 | github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= 49 | github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= 50 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 51 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 52 | golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA= 53 | golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 54 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 55 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 56 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 57 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 58 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 59 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 60 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= 61 | tailscale.com v1.48.1 h1:xHpPXMiCdibpC8UuXiKZpKIWjoRB+TC4CtVLDupu5wA= 62 | tailscale.com v1.48.1/go.mod h1:RWW4emjviEEAIqr6P6bbZZGXr19BdAdtwtUVfW9SBvU= 63 | -------------------------------------------------------------------------------- /images/benchmark-marshal-concrete-v1in2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-marshal-concrete-v1in2.png -------------------------------------------------------------------------------- /images/benchmark-marshal-concrete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-marshal-concrete.png -------------------------------------------------------------------------------- /images/benchmark-marshal-interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-marshal-interface.png -------------------------------------------------------------------------------- /images/benchmark-marshal-rawvalue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-marshal-rawvalue.png -------------------------------------------------------------------------------- /images/benchmark-unmarshal-concrete-v1in2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-unmarshal-concrete-v1in2.png -------------------------------------------------------------------------------- /images/benchmark-unmarshal-concrete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-unmarshal-concrete.png -------------------------------------------------------------------------------- /images/benchmark-unmarshal-interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-unmarshal-interface.png -------------------------------------------------------------------------------- /images/benchmark-unmarshal-rawvalue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/images/benchmark-unmarshal-rawvalue.png -------------------------------------------------------------------------------- /results/process.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | 7 | // This program processes the benchmark output and 8 | // outputs a series of tab-separated tables. 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | "math" 14 | "os" 15 | "sort" 16 | "strconv" 17 | "strings" 18 | ) 19 | 20 | func appendIfNotExist[T comparable](vs []T, v T) []T { 21 | for i := 0; i < len(vs); i++ { 22 | if vs[i] == v { 23 | return vs 24 | } 25 | } 26 | return append(vs, v) 27 | } 28 | 29 | func main() { 30 | // Read the benchmark output. 31 | files := []string{"results.log"} 32 | if len(os.Args) > 1 { 33 | files = os.Args[1:] 34 | } 35 | var lines []string 36 | for _, file := range files { 37 | b, err := os.ReadFile(file) 38 | if err != nil { 39 | panic(err) 40 | } 41 | lines = append(lines, strings.Split(string(b), "\n")...) 42 | } 43 | 44 | var tests, types, impls, funcs []string 45 | runtimes := make(map[string]metric) 46 | allocBytes := make(map[string]metric) 47 | numAllocs := make(map[string]metric) 48 | metrics := []struct { 49 | name string 50 | metrics map[string]metric 51 | }{ 52 | {"Runtimes", runtimes}, 53 | {"AllocBytes", allocBytes}, 54 | {"NumAllocs", numAllocs}, 55 | } 56 | 57 | // Parse the benchmark output. 58 | for _, line := range lines { 59 | fields := strings.Split(line, "\t") 60 | if len(fields) != 5 || !strings.HasPrefix(fields[0], "Benchmark/") { 61 | continue 62 | } 63 | name := strings.TrimPrefix(strings.TrimSuffix(strings.TrimRight(strings.TrimSpace(fields[0]), "012345789"), "-"), "Benchmark/") 64 | segments := strings.Split(name, "/") 65 | if len(segments) != 4 { 66 | continue 67 | } 68 | tests = appendIfNotExist(tests, segments[0]) 69 | types = appendIfNotExist(types, segments[1]) 70 | impls = appendIfNotExist(impls, segments[2]) 71 | funcs = appendIfNotExist(funcs, segments[3]) 72 | for _, field := range fields[1:] { 73 | field = strings.TrimSpace(field) 74 | switch { 75 | case strings.HasSuffix(field, " ns/op"): 76 | if n, err := strconv.ParseInt(strings.TrimSuffix(field, " ns/op"), 10, 64); err == nil { 77 | runtimes[name] = runtimes[name].Add(n) 78 | } 79 | case strings.HasSuffix(field, " B/op"): 80 | if n, err := strconv.ParseInt(strings.TrimSuffix(field, " B/op"), 10, 64); err == nil { 81 | allocBytes[name] = allocBytes[name].Add(n) 82 | } 83 | case strings.HasSuffix(field, " allocs/op"): 84 | if n, err := strconv.ParseInt(strings.TrimSuffix(field, " allocs/op"), 10, 64); err == nil { 85 | numAllocs[name] = numAllocs[name].Add(n) 86 | } 87 | } 88 | } 89 | } 90 | 91 | // Output tab-separated tables for all the results. 92 | for _, met := range metrics { 93 | for _, fun := range funcs { 94 | for _, typ := range types { 95 | fmt.Printf("%s/%s/%s", met.name, fun, typ) 96 | for _, imp := range impls { 97 | fmt.Printf("\t%s", imp) 98 | } 99 | fmt.Println() 100 | for _, td := range tests { 101 | fmt.Printf("%s", td) 102 | var m0 float64 103 | for i, imp := range impls { 104 | name := fmt.Sprintf("%s/%s/%s/%s", td, typ, imp, fun) 105 | m := met.metrics[name].Mean() 106 | if i == 0 { 107 | m0 = m 108 | m = 1.0 109 | } else { 110 | m = m / m0 111 | } 112 | fmt.Printf("\t%0.6f", m) 113 | } 114 | fmt.Println() 115 | } 116 | fmt.Println() 117 | } 118 | } 119 | } 120 | } 121 | 122 | type metric []int64 123 | 124 | func (r metric) Add(n int64) metric { 125 | return append(r, n) 126 | } 127 | func (r metric) Mean() float64 { 128 | var sum float64 129 | for _, n := range r { 130 | sum += float64(n) 131 | } 132 | return sum / float64(len(r)) 133 | } 134 | func (r metric) Median() float64 { 135 | r = append(metric(nil), r...) 136 | sort.Slice(r, func(i, j int) bool { return r[i] < r[j] }) 137 | if len(r) > 0 { 138 | return float64(r[len(r)/2]) 139 | } 140 | return math.NaN() 141 | } 142 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Nicolas Seriot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/README.md: -------------------------------------------------------------------------------- 1 | # JSON Test Suite 2 | 3 | ["Parsing JSON is a Minefield 💣"](https://seriot.ch/projects/parsing_json.html) 4 | (posted 2016-10-26) performed one of the first thorough comparisons of 5 | JSON parser implementations and their behavior on various edge-cases. 6 | The test cases from that article have been copied into this directory. 7 | At the time, [RFC 7159](https://www.rfc-editor.org/rfc/rfc7159.html) 8 | was the authoritative standard, but has since been superseded by 9 | [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.html). 10 | Consequently, the expected results of some of the test cases from the article 11 | were changed to be more compliant with RFC 8259. 12 | 13 | # Changes to test cases 14 | 15 | ## Require rejection of invalid UTF-8 16 | 17 | [RFC 8259, section 8.1](https://www.rfc-editor.org/rfc/rfc8259.html#section-8.1) 18 | requires that JSON text be formatted using UTF-8. 19 | 20 | The classification of the following cases was changed: 21 | 22 | | Case name | Verdict difference | 23 | | ------------------------------------- | -------------------------------- | 24 | | string_invalid_utf-8 | either pass or fail ⇨ must fail | 25 | | string_UTF8_surrogate_U+D800 | either pass or fail ⇨ must fail | 26 | | string_UTF-8_invalid_sequence | either pass or fail ⇨ must fail | 27 | | string_iso_latin_1 | either pass or fail ⇨ must fail | 28 | | string_lone_utf8_continuation_byte | either pass or fail ⇨ must fail | 29 | | string_not_in_unicode_range | either pass or fail ⇨ must fail | 30 | | string_overlong_sequence_2_bytes | either pass or fail ⇨ must fail | 31 | | string_overlong_sequence_6_bytes | either pass or fail ⇨ must fail | 32 | | string_overlong_sequence_6_bytes_null | either pass or fail ⇨ must fail | 33 | | string_truncated-utf-8 | either pass or fail ⇨ must fail | 34 | | string_UTF-16LE_with_BOM | either pass or fail ⇨ must fail | 35 | | string_utf16BE_no_BOM | either pass or fail ⇨ must fail | 36 | | string_utf16LE_no_BOM | either pass or fail ⇨ must fail | 37 | 38 | One exception is that a byte order mark (U+FEFF) at the start may be ignored 39 | by an implementation (in contrast to treating it as an error). For this reason, 40 | "structure_UTF-8_BOM_empty_object" is left as "either pass or fail". 41 | 42 | [RFC 8259, section 8.2](https://www.rfc-editor.org/rfc/rfc8259.html#section-8.2) 43 | specifies that it is undefined how invalid escaped surrogate pairs are handled. 44 | An implementation may accept or reject such cases. 45 | 46 | The classification of the following cases was left unchanged: 47 | 48 | | Case name | Verdict | 49 | | -------------------------------------------- | ------------------- | 50 | | structure_UTF-8_BOM_empty_object | either pass or fail | 51 | | object_key_lone_2nd_surrogate | either pass or fail | 52 | | string_1st_surrogate_but_2nd_missing | either pass or fail | 53 | | string_1st_valid_surrogate_2nd_invalid | either pass or fail | 54 | | string_incomplete_surrogate_and_escape_valid | either pass or fail | 55 | | string_incomplete_surrogate_pair | either pass or fail | 56 | | string_incomplete_surrogates_escape_valid | either pass or fail | 57 | | string_invalid_lonely_surrogate | either pass or fail | 58 | | string_invalid_surrogate | either pass or fail | 59 | | string_inverted_surrogates_U+1D11E | either pass or fail | 60 | | string_lone_second_surrogate | either pass or fail | 61 | 62 | Note that these cases are expected to be rejected under 63 | [RFC 7493, section 2.1](https://datatracker.ietf.org/doc/html/rfc7493#section-2.1). 64 | RFC 7493 is compatible with RFC 8259 in that it makes strict decisions 65 | about behavior that RFC 8259 leaves undefined. 66 | 67 | ## Permit rejection of duplicate object names 68 | 69 | [RFC 8259, section 4](https://datatracker.ietf.org/doc/html/rfc8259#section-4) 70 | says: 71 | 72 | > When the names within an object are not unique, 73 | > the behavior of software that receives such an object is unpredictable. 74 | > Many implementations report the last name/value pair only. 75 | > Other implementations report an error or fail to parse the object, and 76 | > some implementations report all of the name/value pairs, including duplicates. 77 | 78 | Thus, handling of duplicate object names is undefined behavior. 79 | Rejecting such occurences is within the realm of permitted behavior. 80 | 81 | The classification of the following cases was changed: 82 | 83 | | Case name | Verdict difference | 84 | | ------------------------------- | -------------------------------- | 85 | | object_duplicated_key_and_value | must pass ⇨ either pass or fail | 86 | | object_duplicated_key | must pass ⇨ either pass or fail | 87 | 88 | Note that these cases are expected to be rejected under 89 | [RFC 7493, section 2.3](https://datatracker.ietf.org/doc/html/rfc7493#section-2.3): 90 | 91 | > Objects in I-JSON messages MUST NOT have members with duplicate names. 92 | > In this context, "duplicate" means that the names, 93 | > after processing any escaped characters, 94 | > are identical sequences of Unicode characters. 95 | 96 | RFC 7493 is compatible with RFC 8259 in that it makes strict decisions 97 | about behavior that RFC 8259 leaves undefined. 98 | 99 | This decision is further guided by a number of real security vulnerabilities 100 | that relied on duplicate object names to bypass checks: 101 | * https://justi.cz/security/2017/11/14/couchdb-rce-npm.html 102 | * https://nvd.nist.gov/vuln/detail/cve-2022-25757 103 | * https://bishopfox.com/blog/json-interoperability-vulnerabilities 104 | 105 | ## Require acceptance of large numbers 106 | 107 | [RFC 8259, section 6](https://www.rfc-editor.org/rfc/rfc8259.html#section-6) 108 | describes the ABNF grammar for a JSON number that can have arbitrarily 109 | large representations. It does warn that implementations may not be 110 | able to represent the JSON number. However, the expected failure mode seems 111 | to be one where the implementation "will approximate JSON numbers within 112 | the expected precision" rather than outright fail on parsing. 113 | 114 | [RFC 8259, section 9](https://www.rfc-editor.org/rfc/rfc8259.html#section-9) 115 | later says that an "implementation may set limits on the range and precision 116 | of numbers." However, this is in the context transforming JSON text into 117 | some other data representation. Our tests are only concerned about whether 118 | we can validate the input JSON, and not about transformation. 119 | It's a question of the difference between syntax and semantics. 120 | Thus, this exemption clause does not apply in our context. 121 | 122 | The classification of the following cases was changed: 123 | 124 | | Case name | Verdict difference | 125 | | ---------------------------- | -------------------------------- | 126 | | number_double_huge_neg_exp | either pass or fail ⇨ must pass | 127 | | number_huge_exp | either pass or fail ⇨ must pass | 128 | | number_neg_int_huge_exp | either pass or fail ⇨ must pass | 129 | | number_pos_double_huge_exp | either pass or fail ⇨ must pass | 130 | | number_real_neg_overflow | either pass or fail ⇨ must pass | 131 | | number_real_pos_overflow | either pass or fail ⇨ must pass | 132 | | number_real_underflow | either pass or fail ⇨ must pass | 133 | | number_too_big_neg_int | either pass or fail ⇨ must pass | 134 | | number_too_big_pos_int | either pass or fail ⇨ must pass | 135 | | number_very_big_negative_int | either pass or fail ⇨ must pass | 136 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_object_duplicated_key.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"c"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_object_duplicated_key_and_value.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"b"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_object_key_lone_2nd_surrogate.json: -------------------------------------------------------------------------------- 1 | {"\uDFAA":0} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_1st_surrogate_but_2nd_missing.json: -------------------------------------------------------------------------------- 1 | ["\uDADA"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_1st_valid_surrogate_2nd_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD888\u1234"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_incomplete_surrogate_and_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\n"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_incomplete_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uDd1ea"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_incomplete_surrogates_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\n"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_invalid_lonely_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_invalid_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800abc"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_inverted_surrogates_U+1D11E.json: -------------------------------------------------------------------------------- 1 | ["\uDd1e\uD834"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_string_lone_second_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uDFAA"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_structure_500_nested_arrays.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/i_structure_UTF-8_BOM_empty_object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_1_true_without_comma.json: -------------------------------------------------------------------------------- 1 | [1 true] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_a_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_array_a_invalid_utf8.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_colon_instead_of_comma.json: -------------------------------------------------------------------------------- 1 | ["": 1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_comma_after_close.json: -------------------------------------------------------------------------------- 1 | [""], -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_comma_and_number.json: -------------------------------------------------------------------------------- 1 | [,1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_double_comma.json: -------------------------------------------------------------------------------- 1 | [1,,2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_double_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["x",,] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_extra_close.json: -------------------------------------------------------------------------------- 1 | ["x"]] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["",] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_incomplete.json: -------------------------------------------------------------------------------- 1 | ["x" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_incomplete_invalid_value.json: -------------------------------------------------------------------------------- 1 | [x -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_inner_array_no_comma.json: -------------------------------------------------------------------------------- 1 | [3[4]] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_array_invalid_utf8.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_items_separated_by_semicolon.json: -------------------------------------------------------------------------------- 1 | [1:2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_just_comma.json: -------------------------------------------------------------------------------- 1 | [,] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_just_minus.json: -------------------------------------------------------------------------------- 1 | [-] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_missing_value.json: -------------------------------------------------------------------------------- 1 | [ , ""] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_newlines_unclosed.json: -------------------------------------------------------------------------------- 1 | ["a", 2 | 4 3 | ,1, -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_number_and_comma.json: -------------------------------------------------------------------------------- 1 | [1,] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_number_and_several_commas.json: -------------------------------------------------------------------------------- 1 | [1,,] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_spaces_vertical_tab_formfeed.json: -------------------------------------------------------------------------------- 1 | [" a"\f] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_star_inside.json: -------------------------------------------------------------------------------- 1 | [*] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_unclosed.json: -------------------------------------------------------------------------------- 1 | ["" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_unclosed_trailing_comma.json: -------------------------------------------------------------------------------- 1 | [1, -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_unclosed_with_new_lines.json: -------------------------------------------------------------------------------- 1 | [1, 2 | 1 3 | ,1 -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_array_unclosed_with_object_inside.json: -------------------------------------------------------------------------------- 1 | [{} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_incomplete_false.json: -------------------------------------------------------------------------------- 1 | [fals] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_incomplete_null.json: -------------------------------------------------------------------------------- 1 | [nul] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_incomplete_true.json: -------------------------------------------------------------------------------- 1 | [tru] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_multidigit_number_then_00.json: -------------------------------------------------------------------------------- 1 | 123 -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_++.json: -------------------------------------------------------------------------------- 1 | [++1234] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_+1.json: -------------------------------------------------------------------------------- 1 | [+1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_+Inf.json: -------------------------------------------------------------------------------- 1 | [+Inf] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_-01.json: -------------------------------------------------------------------------------- 1 | [-01] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_-1.0..json: -------------------------------------------------------------------------------- 1 | [-1.0.] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_-2..json: -------------------------------------------------------------------------------- 1 | [-2.] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_-NaN.json: -------------------------------------------------------------------------------- 1 | [-NaN] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_.-1.json: -------------------------------------------------------------------------------- 1 | [.-1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_.2e-3.json: -------------------------------------------------------------------------------- 1 | [.2e-3] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0.1.2.json: -------------------------------------------------------------------------------- 1 | [0.1.2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0.3e+.json: -------------------------------------------------------------------------------- 1 | [0.3e+] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0.3e.json: -------------------------------------------------------------------------------- 1 | [0.3e] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0.e1.json: -------------------------------------------------------------------------------- 1 | [0.e1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0_capital_E+.json: -------------------------------------------------------------------------------- 1 | [0E+] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0_capital_E.json: -------------------------------------------------------------------------------- 1 | [0E] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0e+.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_0e.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_1.0e+.json: -------------------------------------------------------------------------------- 1 | [1.0e+] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_1.0e-.json: -------------------------------------------------------------------------------- 1 | [1.0e-] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_1.0e.json: -------------------------------------------------------------------------------- 1 | [1.0e] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_1_000.json: -------------------------------------------------------------------------------- 1 | [1 000.0] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_1eE2.json: -------------------------------------------------------------------------------- 1 | [1eE2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_2.e+3.json: -------------------------------------------------------------------------------- 1 | [2.e+3] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_2.e-3.json: -------------------------------------------------------------------------------- 1 | [2.e-3] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_2.e3.json: -------------------------------------------------------------------------------- 1 | [2.e3] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_9.e+.json: -------------------------------------------------------------------------------- 1 | [9.e+] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_Inf.json: -------------------------------------------------------------------------------- 1 | [Inf] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_NaN.json: -------------------------------------------------------------------------------- 1 | [NaN] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_U+FF11_fullwidth_digit_one.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_expression.json: -------------------------------------------------------------------------------- 1 | [1+2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_hex_1_digit.json: -------------------------------------------------------------------------------- 1 | [0x1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_hex_2_digits.json: -------------------------------------------------------------------------------- 1 | [0x42] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_infinity.json: -------------------------------------------------------------------------------- 1 | [Infinity] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_invalid+-.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_invalid-negative-real.json: -------------------------------------------------------------------------------- 1 | [-123.123foo] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_invalid-utf-8-in-bigger-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_number_invalid-utf-8-in-bigger-int.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_invalid-utf-8-in-exponent.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_number_invalid-utf-8-in-exponent.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_invalid-utf-8-in-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_number_invalid-utf-8-in-int.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_minus_infinity.json: -------------------------------------------------------------------------------- 1 | [-Infinity] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_minus_sign_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [-foo] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_minus_space_1.json: -------------------------------------------------------------------------------- 1 | [- 1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_neg_int_starting_with_zero.json: -------------------------------------------------------------------------------- 1 | [-012] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_neg_real_without_int_part.json: -------------------------------------------------------------------------------- 1 | [-.123] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_neg_with_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | [-1x] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_real_garbage_after_e.json: -------------------------------------------------------------------------------- 1 | [1ea] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_real_with_invalid_utf8_after_e.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_number_real_with_invalid_utf8_after_e.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_real_without_fractional_part.json: -------------------------------------------------------------------------------- 1 | [1.] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_starting_with_dot.json: -------------------------------------------------------------------------------- 1 | [.123] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_with_alpha.json: -------------------------------------------------------------------------------- 1 | [1.2a-3] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_with_alpha_char.json: -------------------------------------------------------------------------------- 1 | [1.8011670033376514H-308] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_number_with_leading_zero.json: -------------------------------------------------------------------------------- 1 | [012] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_bad_value.json: -------------------------------------------------------------------------------- 1 | ["x", truth] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_bracket_key.json: -------------------------------------------------------------------------------- 1 | {[: "x"} 2 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_comma_instead_of_colon.json: -------------------------------------------------------------------------------- 1 | {"x", null} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_double_colon.json: -------------------------------------------------------------------------------- 1 | {"x"::"b"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_emoji.json: -------------------------------------------------------------------------------- 1 | {🇨🇭} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | {"a":"a" 123} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_key_with_single_quotes.json: -------------------------------------------------------------------------------- 1 | {key: 'value'} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_lone_continuation_byte_in_key_and_trailing_comma.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_object_lone_continuation_byte_in_key_and_trailing_comma.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_missing_colon.json: -------------------------------------------------------------------------------- 1 | {"a" b} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_missing_key.json: -------------------------------------------------------------------------------- 1 | {:"b"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_missing_semicolon.json: -------------------------------------------------------------------------------- 1 | {"a" "b"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_missing_value.json: -------------------------------------------------------------------------------- 1 | {"a": -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_no-colon.json: -------------------------------------------------------------------------------- 1 | {"a" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_non_string_key.json: -------------------------------------------------------------------------------- 1 | {1:1} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_non_string_key_but_huge_number_instead.json: -------------------------------------------------------------------------------- 1 | {9999E9999:1} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_repeated_null_null.json: -------------------------------------------------------------------------------- 1 | {null:null,null:null} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_several_trailing_commas.json: -------------------------------------------------------------------------------- 1 | {"id":0,,,,,} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_single_quote.json: -------------------------------------------------------------------------------- 1 | {'a':0} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_trailing_comma.json: -------------------------------------------------------------------------------- 1 | {"id":0,} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_trailing_comment.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**/ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_trailing_comment_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**// -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_trailing_comment_slash_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}// -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_trailing_comment_slash_open_incomplete.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_two_commas_in_a_row.json: -------------------------------------------------------------------------------- 1 | {"a":"b",,"c":"d"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_unquoted_key.json: -------------------------------------------------------------------------------- 1 | {a: "b"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_unterminated-value.json: -------------------------------------------------------------------------------- 1 | {"a":"a -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_with_single_string.json: -------------------------------------------------------------------------------- 1 | { "foo" : "bar", "a" } -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}# -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_single_space.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_1_surrogate_then_escape.json: -------------------------------------------------------------------------------- 1 | ["\uD800\"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_1_surrogate_then_escape_u.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_1_surrogate_then_escape_u1.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_1_surrogate_then_escape_u1x.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1x"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_UTF-16LE_with_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_UTF-16LE_with_BOM.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_UTF-8_invalid_sequence.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_UTF-8_invalid_sequence.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_UTF8_surrogate_U+D800.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_UTF8_surrogate_U+D800.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_accentuated_char_no_quotes.json: -------------------------------------------------------------------------------- 1 | [é] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_backslash_00.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_escape_x.json: -------------------------------------------------------------------------------- 1 | ["\x00"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_escaped_backslash_bad.json: -------------------------------------------------------------------------------- 1 | ["\\\"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_escaped_ctrl_char_tab.json: -------------------------------------------------------------------------------- 1 | ["\ "] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_escaped_emoji.json: -------------------------------------------------------------------------------- 1 | ["\🌀"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_incomplete_escape.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_incomplete_escaped_character.json: -------------------------------------------------------------------------------- 1 | ["\u00A"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_incomplete_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_incomplete_surrogate_escape_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\x"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_invalid-utf-8-in-escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_invalid-utf-8-in-escape.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_invalid_backslash_esc.json: -------------------------------------------------------------------------------- 1 | ["\a"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_invalid_unicode_escape.json: -------------------------------------------------------------------------------- 1 | ["\uqqqq"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_invalid_utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_invalid_utf-8.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_invalid_utf8_after_escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_invalid_utf8_after_escape.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_iso_latin_1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_iso_latin_1.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_leading_uescaped_thinspace.json: -------------------------------------------------------------------------------- 1 | [\u0020"asd"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_lone_utf8_continuation_byte.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_lone_utf8_continuation_byte.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_no_quotes_with_bad_escape.json: -------------------------------------------------------------------------------- 1 | [\n] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_not_in_unicode_range.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_not_in_unicode_range.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_overlong_sequence_2_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_overlong_sequence_2_bytes.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_overlong_sequence_6_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_overlong_sequence_6_bytes.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_overlong_sequence_6_bytes_null.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_overlong_sequence_6_bytes_null.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_single_doublequote.json: -------------------------------------------------------------------------------- 1 | " -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_single_quote.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_single_string_no_double_quotes.json: -------------------------------------------------------------------------------- 1 | abc -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_start_escape_unclosed.json: -------------------------------------------------------------------------------- 1 | ["\ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_truncated-utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_truncated-utf-8.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_unescaped_ctrl_char.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_unescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new 2 | line"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_unescaped_tab.json: -------------------------------------------------------------------------------- 1 | [" "] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_unicode_CapitalU.json: -------------------------------------------------------------------------------- 1 | "\UA66D" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_utf16BE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_utf16BE_no_BOM.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_utf16LE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_string_utf16LE_no_BOM.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_string_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | ""x -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_U+2060_word_joined.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_UTF8_BOM_no_data.json: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_angle_bracket_..json: -------------------------------------------------------------------------------- 1 | <.> -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_angle_bracket_null.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_array_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [1]x -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_array_with_extra_array_close.json: -------------------------------------------------------------------------------- 1 | [1]] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_array_with_unclosed_string.json: -------------------------------------------------------------------------------- 1 | ["asd] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_ascii-unicode-identifier.json: -------------------------------------------------------------------------------- 1 | aå -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_capitalized_True.json: -------------------------------------------------------------------------------- 1 | [True] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_close_unopened_array.json: -------------------------------------------------------------------------------- 1 | 1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_comma_instead_of_closing_brace.json: -------------------------------------------------------------------------------- 1 | {"x": true, -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_double_array.json: -------------------------------------------------------------------------------- 1 | [][] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_end_array.json: -------------------------------------------------------------------------------- 1 | ] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_incomplete_UTF8_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_structure_incomplete_UTF8_BOM.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_lone-invalid-utf-8.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_lone-open-bracket.json: -------------------------------------------------------------------------------- 1 | [ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_no_data.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/JSONTestSuite/n_structure_no_data.json -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_null-byte-outside-string.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_number_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | 2@ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_object_followed_by_closing_object.json: -------------------------------------------------------------------------------- 1 | {}} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_object_unclosed_no_value.json: -------------------------------------------------------------------------------- 1 | {"": -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_object_with_comment.json: -------------------------------------------------------------------------------- 1 | {"a":/*comment*/"b"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a": true} "x" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_array_apostrophe.json: -------------------------------------------------------------------------------- 1 | [' -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_array_comma.json: -------------------------------------------------------------------------------- 1 | [, -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_array_open_object.json: -------------------------------------------------------------------------------- 1 | [{ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_array_open_string.json: -------------------------------------------------------------------------------- 1 | ["a -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_array_string.json: -------------------------------------------------------------------------------- 1 | ["a" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_object.json: -------------------------------------------------------------------------------- 1 | { -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_object_close_array.json: -------------------------------------------------------------------------------- 1 | {] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_object_comma.json: -------------------------------------------------------------------------------- 1 | {, -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_object_open_array.json: -------------------------------------------------------------------------------- 1 | {[ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_object_open_string.json: -------------------------------------------------------------------------------- 1 | {"a -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_object_string_with_apostrophes.json: -------------------------------------------------------------------------------- 1 | {'a' -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_open_open.json: -------------------------------------------------------------------------------- 1 | ["\{["\{["\{["\{ -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_single_eacute.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_single_star.json: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_trailing_#.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}#{} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_uescaped_LF_before_string.json: -------------------------------------------------------------------------------- 1 | [\u000A""] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_unclosed_array.json: -------------------------------------------------------------------------------- 1 | [1 -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_unclosed_array_partial_null.json: -------------------------------------------------------------------------------- 1 | [ false, nul -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_unclosed_array_unfinished_false.json: -------------------------------------------------------------------------------- 1 | [ true, fals -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_unclosed_array_unfinished_true.json: -------------------------------------------------------------------------------- 1 | [ false, tru -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_unclosed_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"asd" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_unicode-identifier.json: -------------------------------------------------------------------------------- 1 | å -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_whitespace_U+2060_word_joiner.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/n_structure_whitespace_formfeed.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/results.json: -------------------------------------------------------------------------------- 1 | { 2 | "GotPassingWantFailing": { 3 | "array_1_true_without_comma": ["GoJSON"], 4 | "array_a_invalid_utf8": ["GoJSON"], 5 | "array_colon_instead_of_comma": ["GoJSON"], 6 | "array_comma_and_number": ["GoJSON"], 7 | "array_double_comma": ["GoJSON"], 8 | "array_double_extra_comma": ["GoJSON"], 9 | "array_extra_comma": ["GoJSON"], 10 | "array_inner_array_no_comma": ["GoJSON"], 11 | "array_invalid_utf8": ["GoJSON"], 12 | "array_items_separated_by_semicolon": ["GoJSON"], 13 | "array_just_comma": ["GoJSON"], 14 | "array_just_minus": ["GoJSON", "SonicJSON"], 15 | "array_missing_value": ["GoJSON"], 16 | "array_number_and_comma": ["GoJSON"], 17 | "array_number_and_several_commas": ["GoJSON"], 18 | "array_spaces_vertical_tab_formfeed": ["GoJSON"], 19 | "array_star_inside": ["GoJSON"], 20 | "incomplete_false": ["GoJSON"], 21 | "incomplete_null": ["GoJSON"], 22 | "incomplete_true": ["GoJSON"], 23 | "multidigit_number_then_00": ["JSONIterator", "GoJSON"], 24 | "number_++": ["GoJSON"], 25 | "number_+1": ["GoJSON"], 26 | "number_+Inf": ["GoJSON"], 27 | "number_-01": ["JSONIterator", "GoJSON"], 28 | "number_-1.0.": ["GoJSON"], 29 | "number_-2.": ["GoJSON"], 30 | "number_-NaN": ["GoJSON"], 31 | "number_.-1": ["GoJSON"], 32 | "number_.2e-3": ["GoJSON"], 33 | "number_0.1.2": ["GoJSON"], 34 | "number_0.3e": ["GoJSON"], 35 | "number_0.3e+": ["GoJSON"], 36 | "number_0.e1": ["GoJSON"], 37 | "number_0_capital_E": ["GoJSON"], 38 | "number_0_capital_E+": ["GoJSON"], 39 | "number_0e": ["GoJSON"], 40 | "number_0e+": ["GoJSON"], 41 | "number_1.0e": ["GoJSON"], 42 | "number_1.0e+": ["GoJSON"], 43 | "number_1.0e-": ["GoJSON"], 44 | "number_1_000": ["GoJSON"], 45 | "number_1eE2": ["GoJSON"], 46 | "number_2.e+3": ["GoJSON"], 47 | "number_2.e-3": ["GoJSON"], 48 | "number_2.e3": ["GoJSON"], 49 | "number_9.e+": ["GoJSON"], 50 | "number_Inf": ["GoJSON"], 51 | "number_NaN": ["GoJSON"], 52 | "number_U+FF11_fullwidth_digit_one": ["GoJSON"], 53 | "number_expression": ["GoJSON"], 54 | "number_hex_1_digit": ["GoJSON"], 55 | "number_hex_2_digits": ["GoJSON"], 56 | "number_infinity": ["GoJSON"], 57 | "number_invalid+-": ["GoJSON"], 58 | "number_invalid-negative-real": ["GoJSON"], 59 | "number_invalid-utf-8-in-bigger-int": ["GoJSON"], 60 | "number_invalid-utf-8-in-exponent": ["GoJSON"], 61 | "number_invalid-utf-8-in-int": ["GoJSON"], 62 | "number_minus_infinity": ["GoJSON"], 63 | "number_minus_sign_with_trailing_garbage": ["GoJSON"], 64 | "number_minus_space_1": ["GoJSON"], 65 | "number_neg_int_starting_with_zero": ["JSONIterator", "GoJSON"], 66 | "number_neg_real_without_int_part": ["JSONIterator", "GoJSON"], 67 | "number_neg_with_garbage_at_end": ["GoJSON"], 68 | "number_real_garbage_after_e": ["GoJSON"], 69 | "number_real_with_invalid_utf8_after_e": ["GoJSON"], 70 | "number_real_without_fractional_part": ["GoJSON"], 71 | "number_starting_with_dot": ["GoJSON"], 72 | "number_with_alpha": ["GoJSON"], 73 | "number_with_alpha_char": ["GoJSON"], 74 | "number_with_leading_zero": ["GoJSON"], 75 | "object_bad_value": ["GoJSON"], 76 | "object_bracket_key": ["GoJSON"], 77 | "object_comma_instead_of_colon": ["GoJSON"], 78 | "object_double_colon": ["GoJSON"], 79 | "object_emoji": ["GoJSON"], 80 | "object_garbage_at_end": ["GoJSON"], 81 | "object_key_with_single_quotes": ["GoJSON"], 82 | "object_lone_continuation_byte_in_key_and_trailing_comma": ["GoJSON"], 83 | "object_missing_colon": ["GoJSON"], 84 | "object_missing_key": ["GoJSON"], 85 | "object_missing_semicolon": ["GoJSON"], 86 | "object_non_string_key": ["GoJSON"], 87 | "object_non_string_key_but_huge_number_instead": ["GoJSON"], 88 | "object_repeated_null_null": ["GoJSON"], 89 | "object_several_trailing_commas": ["GoJSON"], 90 | "object_single_quote": ["GoJSON"], 91 | "object_trailing_comma": ["GoJSON"], 92 | "object_two_commas_in_a_row": ["GoJSON"], 93 | "object_unquoted_key": ["GoJSON"], 94 | "object_with_single_string": ["GoJSON"], 95 | "string_1_surrogate_then_escape_u": ["GoJSON", "SonicJSON"], 96 | "string_1_surrogate_then_escape_u1": ["GoJSON", "SonicJSON"], 97 | "string_1_surrogate_then_escape_u1x": ["GoJSON", "SonicJSON"], 98 | "string_UTF-8_invalid_sequence": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 99 | "string_UTF8_surrogate_U+D800": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 100 | "string_accentuated_char_no_quotes": ["GoJSON"], 101 | "string_backslash_00": ["SonicJSON"], 102 | "string_escape_x": ["GoJSON", "SonicJSON"], 103 | "string_escaped_ctrl_char_tab": ["GoJSON", "SonicJSON"], 104 | "string_escaped_emoji": ["GoJSON", "SonicJSON"], 105 | "string_incomplete_escaped_character": ["GoJSON", "SonicJSON"], 106 | "string_incomplete_surrogate": ["GoJSON", "SonicJSON"], 107 | "string_incomplete_surrogate_escape_invalid": ["GoJSON", "SonicJSON"], 108 | "string_invalid-utf-8-in-escape": ["GoJSON", "SonicJSON"], 109 | "string_invalid_backslash_esc": ["GoJSON", "SonicJSON"], 110 | "string_invalid_unicode_escape": ["GoJSON", "SonicJSON"], 111 | "string_invalid_utf-8": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 112 | "string_invalid_utf8_after_escape": ["GoJSON", "SonicJSON"], 113 | "string_iso_latin_1": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 114 | "string_leading_uescaped_thinspace": ["GoJSON"], 115 | "string_lone_utf8_continuation_byte": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 116 | "string_no_quotes_with_bad_escape": ["GoJSON"], 117 | "string_not_in_unicode_range": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 118 | "string_overlong_sequence_2_bytes": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 119 | "string_overlong_sequence_6_bytes": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 120 | "string_overlong_sequence_6_bytes_null": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 121 | "string_single_quote": ["GoJSON"], 122 | "string_truncated-utf-8": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 123 | "string_unescaped_ctrl_char": ["SonicJSON"], 124 | "string_unescaped_newline": ["GoJSON", "SonicJSON"], 125 | "string_unescaped_tab": ["GoJSON", "SonicJSON"], 126 | "string_unicode_CapitalU": ["GoJSON", "SonicJSON"], 127 | "structure_U+2060_word_joined": ["GoJSON"], 128 | "structure_angle_bracket_null": ["GoJSON"], 129 | "structure_capitalized_True": ["GoJSON"], 130 | "structure_object_with_comment": ["GoJSON"], 131 | "structure_uescaped_LF_before_string": ["GoJSON"], 132 | "structure_whitespace_U+2060_word_joiner": ["GoJSON"], 133 | "structure_whitespace_formfeed": ["GoJSON"] 134 | }, 135 | "GotFailingWantPassing": { 136 | "number_huge_exp": ["JSONIterator"], 137 | "number_neg_int_huge_exp": ["JSONIterator"], 138 | "number_pos_double_huge_exp": ["JSONIterator"], 139 | "number_real_neg_overflow": ["JSONIterator"], 140 | "number_real_pos_overflow": ["JSONIterator"] 141 | }, 142 | "GotPassingWantEither": { 143 | "object_duplicated_key": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 144 | "object_duplicated_key_and_value": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 145 | "object_key_lone_2nd_surrogate": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 146 | "string_1st_surrogate_but_2nd_missing": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 147 | "string_1st_valid_surrogate_2nd_invalid": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 148 | "string_incomplete_surrogate_and_escape_valid": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 149 | "string_incomplete_surrogate_pair": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 150 | "string_incomplete_surrogates_escape_valid": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 151 | "string_invalid_lonely_surrogate": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 152 | "string_invalid_surrogate": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 153 | "string_inverted_surrogates_U+1D11E": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 154 | "string_lone_second_surrogate": ["JSONv1", "JSONv1in2", "JSONIterator", "SegmentJSON", "GoJSON", "SonicJSON", "SonnetJSON"], 155 | "structure_500_nested_arrays": [ 156 | "JSONv1", 157 | "JSONv1in2", 158 | "JSONv2", 159 | "JSONIterator", 160 | "SegmentJSON", 161 | "GoJSON", 162 | "SonicJSON", 163 | "SonnetJSON" 164 | ] 165 | }, 166 | "GotFailingWantEither": { 167 | "object_duplicated_key": ["JSONv2"], 168 | "object_duplicated_key_and_value": ["JSONv2"], 169 | "object_key_lone_2nd_surrogate": ["JSONv2"], 170 | "string_1st_surrogate_but_2nd_missing": ["JSONv2"], 171 | "string_1st_valid_surrogate_2nd_invalid": ["JSONv2"], 172 | "string_incomplete_surrogate_and_escape_valid": ["JSONv2"], 173 | "string_incomplete_surrogate_pair": ["JSONv2"], 174 | "string_incomplete_surrogates_escape_valid": ["JSONv2"], 175 | "string_invalid_lonely_surrogate": ["JSONv2"], 176 | "string_invalid_surrogate": ["JSONv2"], 177 | "string_inverted_surrogates_U+1D11E": ["JSONv2"], 178 | "string_lone_second_surrogate": ["JSONv2"], 179 | "structure_UTF-8_BOM_empty_object": [ 180 | "JSONv1", 181 | "JSONv1in2", 182 | "JSONv2", 183 | "JSONIterator", 184 | "SegmentJSON", 185 | "GoJSON", 186 | "SonicJSON", 187 | "SonnetJSON" 188 | ] 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_arraysWithSpaces.json: -------------------------------------------------------------------------------- 1 | [[] ] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_empty-string.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_empty.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_ending_with_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_false.json: -------------------------------------------------------------------------------- 1 | [false] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_heterogeneous.json: -------------------------------------------------------------------------------- 1 | [null, 1, "1", {}] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_null.json: -------------------------------------------------------------------------------- 1 | [null] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_with_1_and_newline.json: -------------------------------------------------------------------------------- 1 | [1 2 | ] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_with_several_null.json: -------------------------------------------------------------------------------- 1 | [1,null,null,null,2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_array_with_trailing_space.json: -------------------------------------------------------------------------------- 1 | [2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number.json: -------------------------------------------------------------------------------- 1 | [123e65] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_0e+1.json: -------------------------------------------------------------------------------- 1 | [0e+1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_0e1.json: -------------------------------------------------------------------------------- 1 | [0e1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_after_space.json: -------------------------------------------------------------------------------- 1 | [ 4] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_double_close_to_zero.json: -------------------------------------------------------------------------------- 1 | [-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] 2 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_double_huge_neg_exp.json: -------------------------------------------------------------------------------- 1 | [123.456e-789] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_huge_exp.json: -------------------------------------------------------------------------------- 1 | [0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_int_with_exp.json: -------------------------------------------------------------------------------- 1 | [20e1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_minus_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_neg_int_huge_exp.json: -------------------------------------------------------------------------------- 1 | [-1e+9999] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_negative_int.json: -------------------------------------------------------------------------------- 1 | [-123] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_negative_one.json: -------------------------------------------------------------------------------- 1 | [-1] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_negative_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_pos_double_huge_exp.json: -------------------------------------------------------------------------------- 1 | [1.5e+9999] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_capital_e.json: -------------------------------------------------------------------------------- 1 | [1E22] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_capital_e_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1E-2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_capital_e_pos_exp.json: -------------------------------------------------------------------------------- 1 | [1E+2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_exponent.json: -------------------------------------------------------------------------------- 1 | [123e45] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_fraction_exponent.json: -------------------------------------------------------------------------------- 1 | [123.456e78] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1e-2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_neg_overflow.json: -------------------------------------------------------------------------------- 1 | [-123123e100000] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_pos_exponent.json: -------------------------------------------------------------------------------- 1 | [1e+2] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_pos_overflow.json: -------------------------------------------------------------------------------- 1 | [123123e100000] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_real_underflow.json: -------------------------------------------------------------------------------- 1 | [123e-10000000] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_simple_int.json: -------------------------------------------------------------------------------- 1 | [123] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_simple_real.json: -------------------------------------------------------------------------------- 1 | [123.456789] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_too_big_neg_int.json: -------------------------------------------------------------------------------- 1 | [-123123123123123123123123123123] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_too_big_pos_int.json: -------------------------------------------------------------------------------- 1 | [100000000000000000000] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_number_very_big_negative_int.json: -------------------------------------------------------------------------------- 1 | [-237462374673276894279832749832423479823246327846] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf", "dfg":"fgh"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_basic.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_empty.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_empty_key.json: -------------------------------------------------------------------------------- 1 | {"":0} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_escaped_null_in_key.json: -------------------------------------------------------------------------------- 1 | {"foo\u0000bar": 42} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_extreme_numbers.json: -------------------------------------------------------------------------------- 1 | { "min": -1.0e+28, "max": 1.0e+28 } -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_long_strings.json: -------------------------------------------------------------------------------- 1 | {"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_simple.json: -------------------------------------------------------------------------------- 1 | {"a":[]} -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_string_unicode.json: -------------------------------------------------------------------------------- 1 | {"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_object_with_newlines.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": "b" 3 | } -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_1_2_3_bytes_UTF-8_sequences.json: -------------------------------------------------------------------------------- 1 | ["\u0060\u012a\u12AB"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_accepted_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uD801\udc37"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_accepted_surrogate_pairs.json: -------------------------------------------------------------------------------- 1 | ["\ud83d\ude39\ud83d\udc8d"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_allowed_escapes.json: -------------------------------------------------------------------------------- 1 | ["\"\\\/\b\f\n\r\t"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_backslash_and_u_escaped_zero.json: -------------------------------------------------------------------------------- 1 | ["\\u0000"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_backslash_doublequotes.json: -------------------------------------------------------------------------------- 1 | ["\""] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_comments.json: -------------------------------------------------------------------------------- 1 | ["a/*b*/c/*d//e"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_double_escape_a.json: -------------------------------------------------------------------------------- 1 | ["\\a"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_double_escape_n.json: -------------------------------------------------------------------------------- 1 | ["\\n"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_escaped_control_character.json: -------------------------------------------------------------------------------- 1 | ["\u0012"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_escaped_noncharacter.json: -------------------------------------------------------------------------------- 1 | ["\uFFFF"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_in_array.json: -------------------------------------------------------------------------------- 1 | ["asd"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_in_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [ "asd"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_last_surrogates_1_and_2.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFF"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_nbsp_uescaped.json: -------------------------------------------------------------------------------- 1 | ["new\u00A0line"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_nonCharacterInUTF-8_U+10FFFF.json: -------------------------------------------------------------------------------- 1 | ["􏿿"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_nonCharacterInUTF-8_U+FFFF.json: -------------------------------------------------------------------------------- 1 | ["￿"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_null_escape.json: -------------------------------------------------------------------------------- 1 | ["\u0000"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_one-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u002c"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_pi.json: -------------------------------------------------------------------------------- 1 | ["π"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_reservedCharacterInUTF-8_U+1BFFF.json: -------------------------------------------------------------------------------- 1 | ["𛿿"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_simple_ascii.json: -------------------------------------------------------------------------------- 1 | ["asd "] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_space.json: -------------------------------------------------------------------------------- 1 | " " -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd1e"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_three-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0821"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_two-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0123"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_u+2028_line_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_u+2029_par_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_uEscape.json: -------------------------------------------------------------------------------- 1 | ["\u0061\u30af\u30EA\u30b9"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_uescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new\u000Aline"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unescaped_char_delete.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode.json: -------------------------------------------------------------------------------- 1 | ["\uA66D"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicodeEscapedBackslash.json: -------------------------------------------------------------------------------- 1 | ["\u005C"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_2.json: -------------------------------------------------------------------------------- 1 | ["⍂㈴⍂"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_U+10FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFE"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_U+1FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uD83F\uDFFE"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json: -------------------------------------------------------------------------------- 1 | ["\u200B"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_U+2064_invisible_plus.json: -------------------------------------------------------------------------------- 1 | ["\u2064"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_U+FDD0_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFDD0"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_U+FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFFFE"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_unicode_escaped_double_quote.json: -------------------------------------------------------------------------------- 1 | ["\u0022"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_utf8.json: -------------------------------------------------------------------------------- 1 | ["€𝄞"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_string_with_del_character.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_lonely_false.json: -------------------------------------------------------------------------------- 1 | false -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_lonely_int.json: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_lonely_negative_real.json: -------------------------------------------------------------------------------- 1 | -0.1 -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_lonely_null.json: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_lonely_string.json: -------------------------------------------------------------------------------- 1 | "asd" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_lonely_true.json: -------------------------------------------------------------------------------- 1 | true -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_string_empty.json: -------------------------------------------------------------------------------- 1 | "" -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_trailing_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] 2 | -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_true_in_array.json: -------------------------------------------------------------------------------- 1 | [true] -------------------------------------------------------------------------------- /testdata/JSONTestSuite/y_structure_whitespace_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/canada_geometry.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/canada_geometry.json.gz -------------------------------------------------------------------------------- /testdata/citm_catalog.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/citm_catalog.json.gz -------------------------------------------------------------------------------- /testdata/golang_source.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/golang_source.json.gz -------------------------------------------------------------------------------- /testdata/string_unicode.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/string_unicode.json.gz -------------------------------------------------------------------------------- /testdata/synthea_fhir.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/synthea_fhir.json.gz -------------------------------------------------------------------------------- /testdata/twitter_status.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-json-experiment/jsonbench/a05b1d16f57185a257748aed79c08336adc2caa5/testdata/twitter_status.json.gz -------------------------------------------------------------------------------- /testdata_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package jsonbench 6 | 7 | import ( 8 | "time" 9 | 10 | "github.com/go-json-experiment/json/jsontext" 11 | ) 12 | 13 | type ( 14 | canadaRoot struct { 15 | Type string `json:"type"` 16 | Features []struct { 17 | Type string `json:"type"` 18 | Properties struct { 19 | Name string `json:"name"` 20 | } `json:"properties"` 21 | Geometry struct { 22 | Type string `json:"type"` 23 | Coordinates [][][2]float64 `json:"coordinates"` 24 | } `json:"geometry"` 25 | } `json:"features"` 26 | } 27 | ) 28 | 29 | type ( 30 | citmRoot struct { 31 | AreaNames map[int64]string `json:"areaNames"` 32 | AudienceSubCategoryNames map[int64]string `json:"audienceSubCategoryNames"` 33 | BlockNames map[int64]string `json:"blockNames"` 34 | Events map[int64]struct { 35 | Description string `json:"description"` 36 | ID int `json:"id"` 37 | Logo string `json:"logo"` 38 | Name string `json:"name"` 39 | SubTopicIds []int `json:"subTopicIds"` 40 | SubjectCode any `json:"subjectCode"` 41 | Subtitle any `json:"subtitle"` 42 | TopicIds []int `json:"topicIds"` 43 | } `json:"events"` 44 | Performances []struct { 45 | EventID int `json:"eventId"` 46 | ID int `json:"id"` 47 | Logo any `json:"logo"` 48 | Name any `json:"name"` 49 | Prices []struct { 50 | Amount int `json:"amount"` 51 | AudienceSubCategoryID int64 `json:"audienceSubCategoryId"` 52 | SeatCategoryID int64 `json:"seatCategoryId"` 53 | } `json:"prices"` 54 | SeatCategories []struct { 55 | Areas []struct { 56 | AreaID int `json:"areaId"` 57 | BlockIds []any `json:"blockIds"` 58 | } `json:"areas"` 59 | SeatCategoryID int `json:"seatCategoryId"` 60 | } `json:"seatCategories"` 61 | SeatMapImage any `json:"seatMapImage"` 62 | Start int64 `json:"start"` 63 | VenueCode string `json:"venueCode"` 64 | } `json:"performances"` 65 | SeatCategoryNames map[uint64]string `json:"seatCategoryNames"` 66 | SubTopicNames map[uint64]string `json:"subTopicNames"` 67 | SubjectNames map[uint64]string `json:"subjectNames"` 68 | TopicNames map[uint64]string `json:"topicNames"` 69 | TopicSubTopics map[uint64][]uint64 `json:"topicSubTopics"` 70 | VenueNames map[string]string `json:"venueNames"` 71 | } 72 | ) 73 | 74 | type ( 75 | golangRoot struct { 76 | Tree *golangNode `json:"tree"` 77 | Username string `json:"username"` 78 | } 79 | golangNode struct { 80 | Name string `json:"name"` 81 | Kids []golangNode `json:"kids"` 82 | CLWeight float64 `json:"cl_weight"` 83 | Touches int `json:"touches"` 84 | MinT uint64 `json:"min_t"` 85 | MaxT uint64 `json:"max_t"` 86 | MeanT uint64 `json:"mean_t"` 87 | } 88 | ) 89 | 90 | type ( 91 | stringRoot struct { 92 | Arabic string `json:"Arabic"` 93 | ArabicPresentationFormsA string `json:"Arabic Presentation Forms-A"` 94 | ArabicPresentationFormsB string `json:"Arabic Presentation Forms-B"` 95 | Armenian string `json:"Armenian"` 96 | Arrows string `json:"Arrows"` 97 | Bengali string `json:"Bengali"` 98 | Bopomofo string `json:"Bopomofo"` 99 | BoxDrawing string `json:"Box Drawing"` 100 | CJKCompatibility string `json:"CJK Compatibility"` 101 | CJKCompatibilityForms string `json:"CJK Compatibility Forms"` 102 | CJKCompatibilityIdeographs string `json:"CJK Compatibility Ideographs"` 103 | CJKSymbolsAndPunctuation string `json:"CJK Symbols and Punctuation"` 104 | CJKUnifiedIdeographs string `json:"CJK Unified Ideographs"` 105 | CJKUnifiedIdeographsExtensionA string `json:"CJK Unified Ideographs Extension A"` 106 | CJKUnifiedIdeographsExtensionB string `json:"CJK Unified Ideographs Extension B"` 107 | Cherokee string `json:"Cherokee"` 108 | CurrencySymbols string `json:"Currency Symbols"` 109 | Cyrillic string `json:"Cyrillic"` 110 | CyrillicSupplementary string `json:"Cyrillic Supplementary"` 111 | Devanagari string `json:"Devanagari"` 112 | EnclosedAlphanumerics string `json:"Enclosed Alphanumerics"` 113 | EnclosedCJKLettersAndMonths string `json:"Enclosed CJK Letters and Months"` 114 | Ethiopic string `json:"Ethiopic"` 115 | GeometricShapes string `json:"Geometric Shapes"` 116 | Georgian string `json:"Georgian"` 117 | GreekAndCoptic string `json:"Greek and Coptic"` 118 | Gujarati string `json:"Gujarati"` 119 | Gurmukhi string `json:"Gurmukhi"` 120 | HangulCompatibilityJamo string `json:"Hangul Compatibility Jamo"` 121 | HangulJamo string `json:"Hangul Jamo"` 122 | HangulSyllables string `json:"Hangul Syllables"` 123 | Hebrew string `json:"Hebrew"` 124 | Hiragana string `json:"Hiragana"` 125 | IPAExtentions string `json:"IPA Extentions"` 126 | KangxiRadicals string `json:"Kangxi Radicals"` 127 | Katakana string `json:"Katakana"` 128 | Khmer string `json:"Khmer"` 129 | KhmerSymbols string `json:"Khmer Symbols"` 130 | Latin string `json:"Latin"` 131 | LatinExtendedAdditional string `json:"Latin Extended Additional"` 132 | Latin1Supplement string `json:"Latin-1 Supplement"` 133 | LatinExtendedA string `json:"Latin-Extended A"` 134 | LatinExtendedB string `json:"Latin-Extended B"` 135 | LetterlikeSymbols string `json:"Letterlike Symbols"` 136 | Malayalam string `json:"Malayalam"` 137 | MathematicalAlphanumericSymbols string `json:"Mathematical Alphanumeric Symbols"` 138 | MathematicalOperators string `json:"Mathematical Operators"` 139 | MiscellaneousSymbols string `json:"Miscellaneous Symbols"` 140 | Mongolian string `json:"Mongolian"` 141 | NumberForms string `json:"Number Forms"` 142 | Oriya string `json:"Oriya"` 143 | PhoneticExtensions string `json:"Phonetic Extensions"` 144 | SupplementalArrowsB string `json:"Supplemental Arrows-B"` 145 | Syriac string `json:"Syriac"` 146 | Tamil string `json:"Tamil"` 147 | Thaana string `json:"Thaana"` 148 | Thai string `json:"Thai"` 149 | UnifiedCanadianAboriginalSyllabics string `json:"Unified Canadian Aboriginal Syllabics"` 150 | YiRadicals string `json:"Yi Radicals"` 151 | YiSyllables string `json:"Yi Syllables"` 152 | } 153 | ) 154 | 155 | type ( 156 | syntheaRoot struct { 157 | Entry []struct { 158 | FullURL string `json:"fullUrl"` 159 | Request *struct { 160 | Method string `json:"method"` 161 | URL string `json:"url"` 162 | } `json:"request"` 163 | Resource *struct { 164 | AbatementDateTime time.Time `json:"abatementDateTime"` 165 | AchievementStatus syntheaCode `json:"achievementStatus"` 166 | Active bool `json:"active"` 167 | Activity []struct { 168 | Detail *struct { 169 | Code syntheaCode `json:"code"` 170 | Location syntheaReference `json:"location"` 171 | Status string `json:"status"` 172 | } `json:"detail"` 173 | } `json:"activity"` 174 | Address []syntheaAddress `json:"address"` 175 | Addresses []syntheaReference `json:"addresses"` 176 | AuthoredOn time.Time `json:"authoredOn"` 177 | BillablePeriod syntheaRange `json:"billablePeriod"` 178 | BirthDate string `json:"birthDate"` 179 | CareTeam []struct { 180 | Provider syntheaReference `json:"provider"` 181 | Reference string `json:"reference"` 182 | Role syntheaCode `json:"role"` 183 | Sequence int64 `json:"sequence"` 184 | } `json:"careTeam"` 185 | Category []syntheaCode `json:"category"` 186 | Claim syntheaReference `json:"claim"` 187 | Class syntheaCoding `json:"class"` 188 | ClinicalStatus syntheaCode `json:"clinicalStatus"` 189 | Code syntheaCode `json:"code"` 190 | Communication []struct { 191 | Language syntheaCode `json:"language"` 192 | } `json:"communication"` 193 | Component []struct { 194 | Code syntheaCode `json:"code"` 195 | ValueQuantity syntheaCoding `json:"valueQuantity"` 196 | } `json:"component"` 197 | Contained []struct { 198 | Beneficiary syntheaReference `json:"beneficiary"` 199 | ID string `json:"id"` 200 | Intent string `json:"intent"` 201 | Payor []syntheaReference `json:"payor"` 202 | Performer []syntheaReference `json:"performer"` 203 | Requester syntheaReference `json:"requester"` 204 | ResourceType string `json:"resourceType"` 205 | Status string `json:"status"` 206 | Subject syntheaReference `json:"subject"` 207 | Type syntheaCode `json:"type"` 208 | } `json:"contained"` 209 | Created time.Time `json:"created"` 210 | DeceasedDateTime time.Time `json:"deceasedDateTime"` 211 | Description syntheaCode `json:"description"` 212 | Diagnosis []struct { 213 | DiagnosisReference syntheaReference `json:"diagnosisReference"` 214 | Sequence int64 `json:"sequence"` 215 | Type []syntheaCode `json:"type"` 216 | } `json:"diagnosis"` 217 | DosageInstruction []struct { 218 | AsNeededBoolean bool `json:"asNeededBoolean"` 219 | DoseAndRate []struct { 220 | DoseQuantity *struct { 221 | Value float64 `json:"value"` 222 | } `json:"doseQuantity"` 223 | Type syntheaCode `json:"type"` 224 | } `json:"doseAndRate"` 225 | Sequence int64 `json:"sequence"` 226 | Timing *struct { 227 | Repeat *struct { 228 | Frequency int64 `json:"frequency"` 229 | Period float64 `json:"period"` 230 | PeriodUnit string `json:"periodUnit"` 231 | } `json:"repeat"` 232 | } `json:"timing"` 233 | } `json:"dosageInstruction"` 234 | EffectiveDateTime time.Time `json:"effectiveDateTime"` 235 | Encounter syntheaReference `json:"encounter"` 236 | Extension []syntheaExtension `json:"extension"` 237 | Gender string `json:"gender"` 238 | Goal []syntheaReference `json:"goal"` 239 | ID string `json:"id"` 240 | Identifier []struct { 241 | System string `json:"system"` 242 | Type syntheaCode `json:"type"` 243 | Use string `json:"use"` 244 | Value string `json:"value"` 245 | } `json:"identifier"` 246 | Insurance []struct { 247 | Coverage syntheaReference `json:"coverage"` 248 | Focal bool `json:"focal"` 249 | Sequence int64 `json:"sequence"` 250 | } `json:"insurance"` 251 | Insurer syntheaReference `json:"insurer"` 252 | Intent string `json:"intent"` 253 | Issued time.Time `json:"issued"` 254 | Item []struct { 255 | Adjudication []struct { 256 | Amount syntheaCurrency `json:"amount"` 257 | Category syntheaCode `json:"category"` 258 | } `json:"adjudication"` 259 | Category syntheaCode `json:"category"` 260 | DiagnosisSequence []int64 `json:"diagnosisSequence"` 261 | Encounter []syntheaReference `json:"encounter"` 262 | InformationSequence []int64 `json:"informationSequence"` 263 | LocationCodeableConcept syntheaCode `json:"locationCodeableConcept"` 264 | Net syntheaCurrency `json:"net"` 265 | ProcedureSequence []int64 `json:"procedureSequence"` 266 | ProductOrService syntheaCode `json:"productOrService"` 267 | Sequence int64 `json:"sequence"` 268 | ServicedPeriod syntheaRange `json:"servicedPeriod"` 269 | } `json:"item"` 270 | LifecycleStatus string `json:"lifecycleStatus"` 271 | ManagingOrganization []syntheaReference `json:"managingOrganization"` 272 | MaritalStatus syntheaCode `json:"maritalStatus"` 273 | MedicationCodeableConcept syntheaCode `json:"medicationCodeableConcept"` 274 | MultipleBirthBoolean bool `json:"multipleBirthBoolean"` 275 | Name jsontext.Value `json:"name"` 276 | NumberOfInstances int64 `json:"numberOfInstances"` 277 | NumberOfSeries int64 `json:"numberOfSeries"` 278 | OccurrenceDateTime time.Time `json:"occurrenceDateTime"` 279 | OnsetDateTime time.Time `json:"onsetDateTime"` 280 | Outcome string `json:"outcome"` 281 | Participant []struct { 282 | Individual syntheaReference `json:"individual"` 283 | Member syntheaReference `json:"member"` 284 | Role []syntheaCode `json:"role"` 285 | } `json:"participant"` 286 | Patient syntheaReference `json:"patient"` 287 | Payment *struct { 288 | Amount syntheaCurrency `json:"amount"` 289 | } `json:"payment"` 290 | PerformedPeriod syntheaRange `json:"performedPeriod"` 291 | Period syntheaRange `json:"period"` 292 | Prescription syntheaReference `json:"prescription"` 293 | PrimarySource bool `json:"primarySource"` 294 | Priority syntheaCode `json:"priority"` 295 | Procedure []struct { 296 | ProcedureReference syntheaReference `json:"procedureReference"` 297 | Sequence int64 `json:"sequence"` 298 | } `json:"procedure"` 299 | Provider syntheaReference `json:"provider"` 300 | ReasonCode []syntheaCode `json:"reasonCode"` 301 | ReasonReference []syntheaReference `json:"reasonReference"` 302 | RecordedDate time.Time `json:"recordedDate"` 303 | Referral syntheaReference `json:"referral"` 304 | Requester syntheaReference `json:"requester"` 305 | ResourceType string `json:"resourceType"` 306 | Result []syntheaReference `json:"result"` 307 | Series []struct { 308 | BodySite syntheaCoding `json:"bodySite"` 309 | Instance []struct { 310 | Number int64 `json:"number"` 311 | SopClass syntheaCoding `json:"sopClass"` 312 | Title string `json:"title"` 313 | UID string `json:"uid"` 314 | } `json:"instance"` 315 | Modality syntheaCoding `json:"modality"` 316 | Number int64 `json:"number"` 317 | NumberOfInstances int64 `json:"numberOfInstances"` 318 | Started string `json:"started"` 319 | UID string `json:"uid"` 320 | } `json:"series"` 321 | ServiceProvider syntheaReference `json:"serviceProvider"` 322 | Started time.Time `json:"started"` 323 | Status string `json:"status"` 324 | Subject syntheaReference `json:"subject"` 325 | SupportingInfo []struct { 326 | Category syntheaCode `json:"category"` 327 | Sequence int64 `json:"sequence"` 328 | ValueReference syntheaReference `json:"valueReference"` 329 | } `json:"supportingInfo"` 330 | Telecom []map[string]string `json:"telecom"` 331 | Text map[string]string `json:"text"` 332 | Total jsontext.Value `json:"total"` 333 | Type jsontext.Value `json:"type"` 334 | Use string `json:"use"` 335 | VaccineCode syntheaCode `json:"vaccineCode"` 336 | ValueCodeableConcept syntheaCode `json:"valueCodeableConcept"` 337 | ValueQuantity syntheaCoding `json:"valueQuantity"` 338 | VerificationStatus syntheaCode `json:"verificationStatus"` 339 | } `json:"resource"` 340 | } `json:"entry"` 341 | ResourceType string `json:"resourceType"` 342 | Type string `json:"type"` 343 | } 344 | syntheaCode struct { 345 | Coding []syntheaCoding `json:"coding"` 346 | Text string `json:"text"` 347 | } 348 | syntheaCoding struct { 349 | Code string `json:"code"` 350 | Display string `json:"display"` 351 | System string `json:"system"` 352 | Unit string `json:"unit"` 353 | Value float64 `json:"value"` 354 | } 355 | syntheaReference struct { 356 | Display string `json:"display"` 357 | Reference string `json:"reference"` 358 | } 359 | syntheaAddress struct { 360 | City string `json:"city"` 361 | Country string `json:"country"` 362 | Extension []syntheaExtension `json:"extension"` 363 | Line []string `json:"line"` 364 | PostalCode string `json:"postalCode"` 365 | State string `json:"state"` 366 | } 367 | syntheaExtension struct { 368 | URL string `json:"url"` 369 | ValueAddress syntheaAddress `json:"valueAddress"` 370 | ValueCode string `json:"valueCode"` 371 | ValueDecimal float64 `json:"valueDecimal"` 372 | ValueString string `json:"valueString"` 373 | Extension []syntheaExtension `json:"extension"` 374 | } 375 | syntheaRange struct { 376 | End time.Time `json:"end"` 377 | Start time.Time `json:"start"` 378 | } 379 | syntheaCurrency struct { 380 | Currency string `json:"currency"` 381 | Value float64 `json:"value"` 382 | } 383 | ) 384 | 385 | type ( 386 | twitterRoot struct { 387 | Statuses []twitterStatus `json:"statuses"` 388 | SearchMetadata struct { 389 | CompletedIn float64 `json:"completed_in"` 390 | MaxID int64 `json:"max_id"` 391 | MaxIDStr int64 `json:"max_id_str,string"` 392 | NextResults string `json:"next_results"` 393 | Query string `json:"query"` 394 | RefreshURL string `json:"refresh_url"` 395 | Count int `json:"count"` 396 | SinceID int `json:"since_id"` 397 | SinceIDStr int `json:"since_id_str,string"` 398 | } `json:"search_metadata"` 399 | } 400 | twitterStatus struct { 401 | Metadata struct { 402 | ResultType string `json:"result_type"` 403 | IsoLanguageCode string `json:"iso_language_code"` 404 | } `json:"metadata"` 405 | CreatedAt string `json:"created_at"` 406 | ID int64 `json:"id"` 407 | IDStr int64 `json:"id_str,string"` 408 | Text string `json:"text"` 409 | Source string `json:"source"` 410 | Truncated bool `json:"truncated"` 411 | InReplyToStatusID int64 `json:"in_reply_to_status_id"` 412 | InReplyToStatusIDStr int64 `json:"in_reply_to_status_id_str,string"` 413 | InReplyToUserID int64 `json:"in_reply_to_user_id"` 414 | InReplyToUserIDStr int64 `json:"in_reply_to_user_id_str,string"` 415 | InReplyToScreenName string `json:"in_reply_to_screen_name"` 416 | User twitterUser `json:"user,omitempty"` 417 | Geo any `json:"geo"` 418 | Coordinates any `json:"coordinates"` 419 | Place any `json:"place"` 420 | Contributors any `json:"contributors"` 421 | RetweeetedStatus *twitterStatus `json:"retweeted_status"` 422 | RetweetCount int `json:"retweet_count"` 423 | FavoriteCount int `json:"favorite_count"` 424 | Entities twitterEntities `json:"entities,omitempty"` 425 | Favorited bool `json:"favorited"` 426 | Retweeted bool `json:"retweeted"` 427 | PossiblySensitive bool `json:"possibly_sensitive"` 428 | Lang string `json:"lang"` 429 | } 430 | twitterUser struct { 431 | ID int64 `json:"id"` 432 | IDStr string `json:"id_str"` 433 | Name string `json:"name"` 434 | ScreenName string `json:"screen_name"` 435 | Location string `json:"location"` 436 | Description string `json:"description"` 437 | URL any `json:"url"` 438 | Entities twitterEntities `json:"entities"` 439 | Protected bool `json:"protected"` 440 | FollowersCount int `json:"followers_count"` 441 | FriendsCount int `json:"friends_count"` 442 | ListedCount int `json:"listed_count"` 443 | CreatedAt string `json:"created_at"` 444 | FavouritesCount int `json:"favourites_count"` 445 | UtcOffset int `json:"utc_offset"` 446 | TimeZone string `json:"time_zone"` 447 | GeoEnabled bool `json:"geo_enabled"` 448 | Verified bool `json:"verified"` 449 | StatusesCount int `json:"statuses_count"` 450 | Lang string `json:"lang"` 451 | ContributorsEnabled bool `json:"contributors_enabled"` 452 | IsTranslator bool `json:"is_translator"` 453 | IsTranslationEnabled bool `json:"is_translation_enabled"` 454 | ProfileBackgroundColor string `json:"profile_background_color"` 455 | ProfileBackgroundImageURL string `json:"profile_background_image_url"` 456 | ProfileBackgroundImageURLHTTPS string `json:"profile_background_image_url_https"` 457 | ProfileBackgroundTile bool `json:"profile_background_tile"` 458 | ProfileImageURL string `json:"profile_image_url"` 459 | ProfileImageURLHTTPS string `json:"profile_image_url_https"` 460 | ProfileBannerURL string `json:"profile_banner_url"` 461 | ProfileLinkColor string `json:"profile_link_color"` 462 | ProfileSidebarBorderColor string `json:"profile_sidebar_border_color"` 463 | ProfileSidebarFillColor string `json:"profile_sidebar_fill_color"` 464 | ProfileTextColor string `json:"profile_text_color"` 465 | ProfileUseBackgroundImage bool `json:"profile_use_background_image"` 466 | DefaultProfile bool `json:"default_profile"` 467 | DefaultProfileImage bool `json:"default_profile_image"` 468 | Following bool `json:"following"` 469 | FollowRequestSent bool `json:"follow_request_sent"` 470 | Notifications bool `json:"notifications"` 471 | } 472 | twitterEntities struct { 473 | Hashtags []any `json:"hashtags"` 474 | Symbols []any `json:"symbols"` 475 | URL *twitterURL `json:"url"` 476 | URLs []twitterURL `json:"urls"` 477 | UserMentions []struct { 478 | ScreenName string `json:"screen_name"` 479 | Name string `json:"name"` 480 | ID int64 `json:"id"` 481 | IDStr int64 `json:"id_str,string"` 482 | Indices []int `json:"indices"` 483 | } `json:"user_mentions"` 484 | Description struct { 485 | URLs []twitterURL `json:"urls"` 486 | } `json:"description"` 487 | Media []struct { 488 | ID int64 `json:"id"` 489 | IDStr string `json:"id_str"` 490 | Indices []int `json:"indices"` 491 | MediaURL string `json:"media_url"` 492 | MediaURLHTTPS string `json:"media_url_https"` 493 | URL string `json:"url"` 494 | DisplayURL string `json:"display_url"` 495 | ExpandedURL string `json:"expanded_url"` 496 | Type string `json:"type"` 497 | Sizes map[string]struct { 498 | W int `json:"w"` 499 | H int `json:"h"` 500 | Resize string `json:"resize"` 501 | } `json:"sizes"` 502 | SourceStatusID int64 `json:"source_status_id"` 503 | SourceStatusIDStr int64 `json:"source_status_id_str,string"` 504 | } `json:"media"` 505 | } 506 | twitterURL struct { 507 | URL string `json:"url"` 508 | URLs []twitterURL `json:"urls"` 509 | ExpandedURL string `json:"expanded_url"` 510 | DisplayURL string `json:"display_url"` 511 | Indices []int `json:"indices"` 512 | } 513 | ) 514 | --------------------------------------------------------------------------------