[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-5091":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":32,"trendingCount":16,"starSnapshotCount":16,"syncStatus":33,"lastSyncTime":34,"discoverSource":35},5091,"sonic","bytedance\u002Fsonic","bytedance","A blazingly fast JSON serializing & deserializing library","",null,"Go",9488,454,51,27,0,10,109,1,78.97,"Apache License 2.0",false,"main",true,[26,27,28,29],"high-performance","jit","json","simd","2026-06-12 04:00:24","# Sonic\n\nEnglish | [中文](README_ZH_CN.md)\n\nA blazingly fast JSON serializing &amp; deserializing library, accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data).\n\n## Requirement\n\n- Go: 1.18~1.26\n  - Notice: Go1.24.0 is not supported due to the [issue](https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fissues\u002F71672); please use a higher Go version or pass the build flag `-ldflags=\"-checklinkname=0\"`.\n- OS: Linux \u002F MacOS \u002F Windows\n- CPU: AMD64 \u002F (ARM64, need go1.20 above)\n\n## Features\n\n- Runtime object binding without code generation\n- Complete APIs for JSON value manipulation\n- Fast, fast, fast!\n\n## APIs\n\nsee [go.dev](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fbytedance\u002Fsonic)\n\n## Benchmarks\n\nFor **all sizes** of json and **all scenarios** of usage, **Sonic performs best**.\n\n- [Medium](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002Fdecoder\u002Ftestdata_test.go#L19) (13KB, 300+ key, 6 layers)\n\n```powershell\ngoversion: 1.17.1\ngoos: darwin\ngoarch: amd64\ncpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz\nBenchmarkEncoder_Generic_Sonic-16                      32393 ns\u002Fop         402.40 MB\u002Fs       11965 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Generic_Sonic_Fast-16                 21668 ns\u002Fop         601.57 MB\u002Fs       10940 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Generic_JsonIter-16                   42168 ns\u002Fop         309.12 MB\u002Fs       14345 B\u002Fop        115 allocs\u002Fop\nBenchmarkEncoder_Generic_GoJson-16                     65189 ns\u002Fop         199.96 MB\u002Fs       23261 B\u002Fop         16 allocs\u002Fop\nBenchmarkEncoder_Generic_StdLib-16                    106322 ns\u002Fop         122.60 MB\u002Fs       49136 B\u002Fop        789 allocs\u002Fop\nBenchmarkEncoder_Binding_Sonic-16                       6269 ns\u002Fop        2079.26 MB\u002Fs       14173 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Binding_Sonic_Fast-16                  5281 ns\u002Fop        2468.16 MB\u002Fs       12322 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Binding_JsonIter-16                   20056 ns\u002Fop         649.93 MB\u002Fs        9488 B\u002Fop          2 allocs\u002Fop\nBenchmarkEncoder_Binding_GoJson-16                      8311 ns\u002Fop        1568.32 MB\u002Fs        9481 B\u002Fop          1 allocs\u002Fop\nBenchmarkEncoder_Binding_StdLib-16                     16448 ns\u002Fop         792.52 MB\u002Fs        9479 B\u002Fop          1 allocs\u002Fop\nBenchmarkEncoder_Parallel_Generic_Sonic-16              6681 ns\u002Fop        1950.93 MB\u002Fs       12738 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Parallel_Generic_Sonic_Fast-16         4179 ns\u002Fop        3118.99 MB\u002Fs       10757 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Parallel_Generic_JsonIter-16           9861 ns\u002Fop        1321.84 MB\u002Fs       14362 B\u002Fop        115 allocs\u002Fop\nBenchmarkEncoder_Parallel_Generic_GoJson-16            18850 ns\u002Fop         691.52 MB\u002Fs       23278 B\u002Fop         16 allocs\u002Fop\nBenchmarkEncoder_Parallel_Generic_StdLib-16            45902 ns\u002Fop         283.97 MB\u002Fs       49174 B\u002Fop        789 allocs\u002Fop\nBenchmarkEncoder_Parallel_Binding_Sonic-16              1480 ns\u002Fop        8810.09 MB\u002Fs       13049 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Parallel_Binding_Sonic_Fast-16         1209 ns\u002Fop        10785.23 MB\u002Fs      11546 B\u002Fop          4 allocs\u002Fop\nBenchmarkEncoder_Parallel_Binding_JsonIter-16           6170 ns\u002Fop        2112.58 MB\u002Fs        9504 B\u002Fop          2 allocs\u002Fop\nBenchmarkEncoder_Parallel_Binding_GoJson-16             3321 ns\u002Fop        3925.52 MB\u002Fs        9496 B\u002Fop          1 allocs\u002Fop\nBenchmarkEncoder_Parallel_Binding_StdLib-16             3739 ns\u002Fop        3486.49 MB\u002Fs        9480 B\u002Fop          1 allocs\u002Fop\n\nBenchmarkDecoder_Generic_Sonic-16                      66812 ns\u002Fop         195.10 MB\u002Fs       57602 B\u002Fop        723 allocs\u002Fop\nBenchmarkDecoder_Generic_Sonic_Fast-16                 54523 ns\u002Fop         239.07 MB\u002Fs       49786 B\u002Fop        313 allocs\u002Fop\nBenchmarkDecoder_Generic_StdLib-16                    124260 ns\u002Fop         104.90 MB\u002Fs       50869 B\u002Fop        772 allocs\u002Fop\nBenchmarkDecoder_Generic_JsonIter-16                   91274 ns\u002Fop         142.81 MB\u002Fs       55782 B\u002Fop       1068 allocs\u002Fop\nBenchmarkDecoder_Generic_GoJson-16                     88569 ns\u002Fop         147.17 MB\u002Fs       66367 B\u002Fop        973 allocs\u002Fop\nBenchmarkDecoder_Binding_Sonic-16                      32557 ns\u002Fop         400.38 MB\u002Fs       28302 B\u002Fop        137 allocs\u002Fop\nBenchmarkDecoder_Binding_Sonic_Fast-16                 28649 ns\u002Fop         455.00 MB\u002Fs       24999 B\u002Fop         34 allocs\u002Fop\nBenchmarkDecoder_Binding_StdLib-16                    111437 ns\u002Fop         116.97 MB\u002Fs       10576 B\u002Fop        208 allocs\u002Fop\nBenchmarkDecoder_Binding_JsonIter-16                   35090 ns\u002Fop         371.48 MB\u002Fs       14673 B\u002Fop        385 allocs\u002Fop\nBenchmarkDecoder_Binding_GoJson-16                     28738 ns\u002Fop         453.59 MB\u002Fs       22039 B\u002Fop         49 allocs\u002Fop\nBenchmarkDecoder_Parallel_Generic_Sonic-16             12321 ns\u002Fop        1057.91 MB\u002Fs       57233 B\u002Fop        723 allocs\u002Fop\nBenchmarkDecoder_Parallel_Generic_Sonic_Fast-16        10644 ns\u002Fop        1224.64 MB\u002Fs       49362 B\u002Fop        313 allocs\u002Fop\nBenchmarkDecoder_Parallel_Generic_StdLib-16            57587 ns\u002Fop         226.35 MB\u002Fs       50874 B\u002Fop        772 allocs\u002Fop\nBenchmarkDecoder_Parallel_Generic_JsonIter-16          38666 ns\u002Fop         337.12 MB\u002Fs       55789 B\u002Fop       1068 allocs\u002Fop\nBenchmarkDecoder_Parallel_Generic_GoJson-16            30259 ns\u002Fop         430.79 MB\u002Fs       66370 B\u002Fop        974 allocs\u002Fop\nBenchmarkDecoder_Parallel_Binding_Sonic-16              5965 ns\u002Fop        2185.28 MB\u002Fs       27747 B\u002Fop        137 allocs\u002Fop\nBenchmarkDecoder_Parallel_Binding_Sonic_Fast-16         5170 ns\u002Fop        2521.31 MB\u002Fs       24715 B\u002Fop         34 allocs\u002Fop\nBenchmarkDecoder_Parallel_Binding_StdLib-16            27582 ns\u002Fop         472.58 MB\u002Fs       10576 B\u002Fop        208 allocs\u002Fop\nBenchmarkDecoder_Parallel_Binding_JsonIter-16          13571 ns\u002Fop         960.51 MB\u002Fs       14685 B\u002Fop        385 allocs\u002Fop\nBenchmarkDecoder_Parallel_Binding_GoJson-16            10031 ns\u002Fop        1299.51 MB\u002Fs       22111 B\u002Fop         49 allocs\u002Fop\n\nBenchmarkGetOne_Sonic-16                                3276 ns\u002Fop        3975.78 MB\u002Fs          24 B\u002Fop          1 allocs\u002Fop\nBenchmarkGetOne_Gjson-16                                9431 ns\u002Fop        1380.81 MB\u002Fs           0 B\u002Fop          0 allocs\u002Fop\nBenchmarkGetOne_Jsoniter-16                            51178 ns\u002Fop         254.46 MB\u002Fs       27936 B\u002Fop        647 allocs\u002Fop\nBenchmarkGetOne_Parallel_Sonic-16                      216.7 ns\u002Fop       60098.95 MB\u002Fs          24 B\u002Fop          1 allocs\u002Fop\nBenchmarkGetOne_Parallel_Gjson-16                       1076 ns\u002Fop        12098.62 MB\u002Fs          0 B\u002Fop          0 allocs\u002Fop\nBenchmarkGetOne_Parallel_Jsoniter-16                   17741 ns\u002Fop         734.06 MB\u002Fs       27945 B\u002Fop        647 allocs\u002Fop\nBenchmarkSetOne_Sonic-16                               9571 ns\u002Fop         1360.61 MB\u002Fs        1584 B\u002Fop         17 allocs\u002Fop\nBenchmarkSetOne_Sjson-16                               36456 ns\u002Fop         357.22 MB\u002Fs       52180 B\u002Fop          9 allocs\u002Fop\nBenchmarkSetOne_Jsoniter-16                            79475 ns\u002Fop         163.86 MB\u002Fs       45862 B\u002Fop        964 allocs\u002Fop\nBenchmarkSetOne_Parallel_Sonic-16                      850.9 ns\u002Fop       15305.31 MB\u002Fs        1584 B\u002Fop         17 allocs\u002Fop\nBenchmarkSetOne_Parallel_Sjson-16                      18194 ns\u002Fop         715.77 MB\u002Fs       52247 B\u002Fop          9 allocs\u002Fop\nBenchmarkSetOne_Parallel_Jsoniter-16                   33560 ns\u002Fop         388.05 MB\u002Fs       45892 B\u002Fop        964 allocs\u002Fop\nBenchmarkLoadNode\u002FLoadAll()-16                         11384 ns\u002Fop        1143.93 MB\u002Fs        6307 B\u002Fop         25 allocs\u002Fop\nBenchmarkLoadNode_Parallel\u002FLoadAll()-16                 5493 ns\u002Fop        2370.68 MB\u002Fs        7145 B\u002Fop         25 allocs\u002Fop\nBenchmarkLoadNode\u002FInterface()-16                       17722 ns\u002Fop         734.85 MB\u002Fs       13323 B\u002Fop         88 allocs\u002Fop\nBenchmarkLoadNode_Parallel\u002FInterface()-16              10330 ns\u002Fop        1260.70 MB\u002Fs       15178 B\u002Fop         88 allocs\u002Fop\n```\n\n- [Small](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002Ftestdata\u002Fsmall.go) (400B, 11 keys, 3 layers)\n![small benchmarks](.\u002Fdocs\u002Fimgs\u002Fbench-small.png)\n- [Large](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002Ftestdata\u002Ftwitter.json) (635KB, 10000+ key, 6 layers)\n![large benchmarks](.\u002Fdocs\u002Fimgs\u002Fbench-large.png)\n\nSee [bench.sh](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002Fscripts\u002Fbench.sh) for benchmark codes.\n\n## How it works\n\nSee [INTRODUCTION.md](.\u002Fdocs\u002FINTRODUCTION.md).\n\n## Usage\n\n### Marshal\u002FUnmarshal\n\nDefault behaviors are mostly consistent with `encoding\u002Fjson`, except HTML escaping form (see [Escape HTML](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002FREADME.md#escape-html)) and `SortKeys` feature (optional support see [Sort Keys](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002FREADME.md#sort-keys)) that is **NOT** in conformity to [RFC8259](https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc8259).\n\n ```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\n\nvar data YourSchema\n\u002F\u002F Marshal\noutput, err := sonic.Marshal(&data)\n\u002F\u002F Unmarshal\nerr := sonic.Unmarshal(output, &data)\n ```\n\n### Streaming IO\n\nSonic supports decoding json from `io.Reader` or encoding objects into `io.Writer`, aims at handling multiple values as well as reducing memory consumption.\n\n- encoder\n\n```go\nvar o1 = map[string]interface{}{\n    \"a\": \"b\",\n}\nvar o2 = 1\nvar w = bytes.NewBuffer(nil)\nvar enc = sonic.ConfigDefault.NewEncoder(w)\nenc.Encode(o1)\nenc.Encode(o2)\nfmt.Println(w.String())\n\u002F\u002F Output:\n\u002F\u002F {\"a\":\"b\"}\n\u002F\u002F 1\n```\n\n- decoder\n\n```go\nvar o =  map[string]interface{}{}\nvar r = strings.NewReader(`{\"a\":\"b\"}{\"1\":\"2\"}`)\nvar dec = sonic.ConfigDefault.NewDecoder(r)\ndec.Decode(&o)\ndec.Decode(&o)\nfmt.Printf(\"%+v\", o)\n\u002F\u002F Output:\n\u002F\u002F map[1:2 a:b]\n```\n\n### Use Number\u002FUse Int64\n\n ```go\nimport \"github.com\u002Fbytedance\u002Fsonic\u002Fdecoder\"\n\nvar input = `1`\nvar data interface{}\n\n\u002F\u002F default float64\ndc := decoder.NewDecoder(input)\ndc.Decode(&data) \u002F\u002F data == float64(1)\n\u002F\u002F use json.Number\ndc = decoder.NewDecoder(input)\ndc.UseNumber()\ndc.Decode(&data) \u002F\u002F data == json.Number(\"1\")\n\u002F\u002F use int64\ndc = decoder.NewDecoder(input)\ndc.UseInt64()\ndc.Decode(&data) \u002F\u002F data == int64(1)\n\nroot, err := sonic.GetFromString(input)\n\u002F\u002F Get json.Number\njn := root.Number()\njm := root.InterfaceUseNumber().(json.Number) \u002F\u002F jn == jm\n\u002F\u002F Get float64\nfn := root.Float64()\nfm := root.Interface().(float64) \u002F\u002F jn == jm\n ```\n\n### Sort Keys\n\nOn account of the performance loss from sorting (roughly 10%), sonic doesn't enable this feature by default. If your component depends on it to work (like [zstd](https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fzstd)), Use it like this:\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\nimport \"github.com\u002Fbytedance\u002Fsonic\u002Fencoder\"\n\n\u002F\u002F Binding map only\nm := map[string]interface{}{}\nv, err := encoder.Encode(m, encoder.SortMapKeys)\n\n\u002F\u002F Or ast.Node.SortKeys() before marshal\nvar root := sonic.Get(JSON)\nerr := root.SortKeys()\n```\n\n### Escape HTML\n\nOn account of the performance loss (roughly 15%), sonic doesn't enable this feature by default. You can use `encoder.EscapeHTML` option to open this feature (align with `encoding\u002Fjson.HTMLEscape`).\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\n\nv := map[string]string{\"&&\":\"\u003C>\"}\nret, err := Encode(v, EscapeHTML) \u002F\u002F ret == `{\"\\u0026\\u0026\":{\"X\":\"\\u003c\\u003e\"}}`\n```\n\n### Compact Format\n\nSonic encodes primitive objects (struct\u002Fmap...) as compact-format JSON by default, except marshaling `json.RawMessage` or `json.Marshaler`: sonic ensures validating their output JSON but **DO NOT** compacting them for performance concerns. We provide the option `encoder.CompactMarshaler` to add compacting process.\n\n### Print Error\n\nIf there invalid syntax in input JSON, sonic will return `decoder.SyntaxError`, which supports pretty-printing of error position\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\nimport \"github.com\u002Fbytedance\u002Fsonic\u002Fdecoder\"\n\nvar data interface{}\nerr := sonic.UnmarshalString(\"[[[}]]\", &data)\nif err != nil {\n    \u002F* One line by default *\u002F\n    println(e.Error()) \u002F\u002F \"Syntax error at index 3: invalid char\\n\\n\\t[[[}]]\\n\\t...^..\\n\"\n    \u002F* Pretty print *\u002F\n    if e, ok := err.(decoder.SyntaxError); ok {\n        \u002F*Syntax error at index 3: invalid char\n\n            [[[}]]\n            ...^..\n        *\u002F\n        print(e.Description())\n    } else if me, ok := err.(*decoder.MismatchTypeError); ok {\n        \u002F\u002F decoder.MismatchTypeError is new to Sonic v1.6.0\n        print(me.Description())\n    }\n}\n```\n\n#### Mismatched Types [Sonic v1.6.0]\n\nIf there a **mismatch-typed** value for a given key, sonic will report `decoder.MismatchTypeError` (if there are many, report the last one), but still skip wrong the value and keep decoding next JSON.\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\nimport \"github.com\u002Fbytedance\u002Fsonic\u002Fdecoder\"\n\nvar data = struct{\n    A int\n    B int\n}{}\nerr := UnmarshalString(`{\"A\":\"1\",\"B\":1}`, &data)\nprintln(err.Error())    \u002F\u002F Mismatch type int with value string \"at index 5: mismatched type with value\\n\\n\\t{\\\"A\\\":\\\"1\\\",\\\"B\\\":1}\\n\\t.....^.........\\n\"\nfmt.Printf(\"%+v\", data) \u002F\u002F {A:0 B:1}\n```\n\n### Ast.Node\n\nSonic\u002Fast.Node is a completely self-contained AST for JSON. It implements serialization and deserialization both and provides robust APIs for obtaining and modification of generic data.\n\n#### Get\u002FIndex\n\nSearch partial JSON by given paths, which must be non-negative integer or string, or nil\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\n\ninput := []byte(`{\"key1\":[{},{\"key2\":{\"key3\":[1,2,3]}}]}`)\n\n\u002F\u002F no path, returns entire json\nroot, err := sonic.Get(input)\nraw := root.Raw() \u002F\u002F == string(input)\n\n\u002F\u002F multiple paths\nroot, err := sonic.Get(input, \"key1\", 1, \"key2\")\nsub := root.Get(\"key3\").Index(2).Int64() \u002F\u002F == 3\n```\n\n**Tip**: since `Index()` uses offset to locate data, which is much faster than scanning like `Get()`, we suggest you use it as much as possible. And sonic also provides another API `IndexOrGet()` to underlying use offset as well as ensure the key is matched.\n\n#### SearchOption\n\n`Searcher` provides some options for user to meet different needs:\n\n```go\nopts := ast.SearchOption{ CopyReturn: true ... }\nval, err := sonic.GetWithOptions(JSON, opts, \"key\")\n```\n\n- CopyReturn\nIndicate the searcher to copy the result JSON string instead of refer from the input. This can help to reduce memory usage if you cache the results\n- ConcurentRead\nSince `ast.Node` use `Lazy-Load` design, it doesn't support Concurrently-Read by default. If you want to read it concurrently, please specify it.\n- ValidateJSON\nIndicate the searcher to validate the entire JSON. This option is enabled by default, which slow down the search speed a little.\n\n#### Set\u002FUnset\n\nModify the json content by Set()\u002FUnset()\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\n\n\u002F\u002F Set\nexist, err := root.Set(\"key4\", NewBool(true)) \u002F\u002F exist == false\nalias1 := root.Get(\"key4\")\nprintln(alias1.Valid()) \u002F\u002F true\nalias2 := root.Index(1)\nprintln(alias1 == alias2) \u002F\u002F true\n\n\u002F\u002F Unset\nexist, err := root.UnsetByIndex(1) \u002F\u002F exist == true\nprintln(root.Get(\"key4\").Check()) \u002F\u002F \"value not exist\"\n```\n\n#### Serialize\n\nTo encode `ast.Node` as json, use `MarshalJson()` or `json.Marshal()` (MUST pass the node's pointer)\n\n```go\nimport (\n    \"encoding\u002Fjson\"\n    \"github.com\u002Fbytedance\u002Fsonic\"\n)\n\nbuf, err := root.MarshalJson()\nprintln(string(buf))                \u002F\u002F {\"key1\":[{},{\"key2\":{\"key3\":[1,2,3]}}]}\nexp, err := json.Marshal(&root)     \u002F\u002F WARN: use pointer\nprintln(string(buf) == string(exp)) \u002F\u002F true\n```\n\n#### APIs\n\n- validation: `Check()`, `Error()`, `Valid()`, `Exist()`\n- searching: `Index()`, `Get()`, `IndexPair()`, `IndexOrGet()`, `GetByPath()`\n- go-type casting: `Int64()`, `Float64()`, `String()`, `Number()`, `Bool()`, `Map[UseNumber|UseNode]()`, `Array[UseNumber|UseNode]()`, `Interface[UseNumber|UseNode]()`\n- go-type packing: `NewRaw()`, `NewNumber()`, `NewNull()`, `NewBool()`, `NewString()`, `NewObject()`, `NewArray()`\n- iteration: `Values()`, `Properties()`, `ForEach()`, `SortKeys()`\n- modification: `Set()`, `SetByIndex()`, `Add()`\n\n### Ast.Visitor\n\nSonic provides an advanced API for fully parsing JSON into non-standard types (neither `struct` not `map[string]interface{}`) without using any intermediate representation (`ast.Node` or `interface{}`). For example, you might have the following types which are like `interface{}` but actually not `interface{}`:\n\n```go\ntype UserNode interface {}\n\n\u002F\u002F the following types implement the UserNode interface.\ntype (\n    UserNull    struct{}\n    UserBool    struct{ Value bool }\n    UserInt64   struct{ Value int64 }\n    UserFloat64 struct{ Value float64 }\n    UserString  struct{ Value string }\n    UserObject  struct{ Value map[string]UserNode }\n    UserArray   struct{ Value []UserNode }\n)\n```\n\nSonic provides the following API to return **the preorder traversal of a JSON AST**. The `ast.Visitor` is a SAX style interface which is used in some C++ JSON library. You should implement `ast.Visitor` by yourself and pass it to `ast.Preorder()` method. In your visitor you can make your custom types to represent JSON values. There may be an O(n) space container (such as stack) in your visitor to record the object \u002F array hierarchy.\n\n```go\nfunc Preorder(str string, visitor Visitor, opts *VisitorOptions) error\n\ntype Visitor interface {\n    OnNull() error\n    OnBool(v bool) error\n    OnString(v string) error\n    OnInt64(v int64, n json.Number) error\n    OnFloat64(v float64, n json.Number) error\n    OnObjectBegin(capacity int) error\n    OnObjectKey(key string) error\n    OnObjectEnd() error\n    OnArrayBegin(capacity int) error\n    OnArrayEnd() error\n}\n```\n\nSee [ast\u002Fvisitor.go](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002Fast\u002Fvisitor.go) for detailed usage. We also implement a demo visitor for `UserNode` in [ast\u002Fvisitor_test.go](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002Fast\u002Fvisitor_test.go).\n\n## Compatibility\n\nFor developers who want to use sonic to meet different scenarios, we provide some integrated configs as `sonic.API`\n\n- `ConfigDefault`: the sonic's default config (`EscapeHTML=false`,`SortKeys=false`...) to run sonic fast meanwhile ensure security.\n- `ConfigStd`: the std-compatible config (`EscapeHTML=true`,`SortKeys=true`...)\n- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic as fast as possible.\nSonic **DOES NOT** ensure to support all environments, due to the difficulty of developing high-performance codes. On non-sonic-supporting environment, the implementation will fall back to `encoding\u002Fjson`. Thus below configs will all equal to `ConfigStd`.\n\n## Tips\n\n### Pretouch\n\nSince Sonic uses [golang-asm](https:\u002F\u002Fgithub.com\u002Ftwitchyliquid64\u002Fgolang-asm) as a JIT assembler, which is NOT very suitable for runtime compiling, first-hit running of a huge schema may cause request-timeout or even process-OOM. For better stability, we advise **using `PretouchMany()` for huge-schema or lantency-sensitive applications** before `Marshal()\u002FUnmarshal()`.\n\n```go\nimport (\n    \"reflect\"\n    \"github.com\u002Fbytedance\u002Fsonic\"\n    \"github.com\u002Fbytedance\u002Fsonic\u002Foption\"\n)\n\nfunc init() {\n    var v1 HugeStruct1\n    var v2 HugeStruct2\n\n    \u002F\u002F For most large types (nesting depth \u003C= option.DefaultMaxInlineDepth)\n    sonic.PretouchMany([]reflect.Type{reflect.TypeOf(v1), reflect.TypeOf(v2)},\n        \u002F\u002F If the type is too deep nesting (nesting depth > option.DefaultMaxInlineDepth),\n        \u002F\u002F you can set more recursive loops in Pretouch for fully sufficient JIT.\n        option.WithCompileRecursiveDepth(loop),\n        \u002F\u002F For a large struct, try to set a smaller depth to reduce compiling time.\n        option.WithCompileMaxInlineDepth(depth),\n    )\n}\n```\n\n### Copy string\n\nWhen decoding **string values without any escaped characters**, sonic references them from the origin JSON buffer instead of mallocing a new buffer to copy. This helps a lot for CPU performance but may leave the whole JSON buffer in memory as long as the decoded objects are being used. In practice, we found the extra memory introduced by referring JSON buffer is usually 20% ~ 80% of decoded objects. Once an application holds these objects for a long time (for example, cache the decoded objects for reusing), its in-use memory on the server may go up. - `Config.CopyString`\u002F`decoder.CopyString()`: We provide the option for `Decode()` \u002F `Unmarshal()` users to choose not to reference the JSON buffer, which may cause a decline in CPU performance to some degree.\n\n- `GetFromStringNoCopy()`: For memory safety, `sonic.Get()` \u002F `sonic.GetFromString()` now copies return JSON. If users want to get json more quickly and not care about memory usage, you can use `GetFromStringNoCopy()` to return a JSON directly referenced from source.\n\n### Pass string or []byte?\n\nFor alignment to `encoding\u002Fjson`, we provide API to pass `[]byte` as an argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when the origin JSON is huge. Therefore, you can use `UnmarshalString()` and `GetFromString()` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte. We also provide API `MarshalString()` for convenient **nocopy-cast** of encoded JSON []byte, which is safe since sonic's output bytes is always duplicated and unique.\n\n### Accelerate `encoding.TextMarshaler`\n\nTo ensure data security, sonic.Encoder quotes and escapes string values from `encoding.TextMarshaler` interfaces by default, which may degrade performance much if most of your data is in form of them. We provide `encoder.NoQuoteTextMarshaler` to skip these operations, which means you **MUST** ensure their output string escaped and quoted following [RFC8259](https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc8259).\n\n### Better performance for generic data\n\nIn **fully-parsed** scenario, `Unmarshal()` performs better than `Get()`+`Node.Interface()`. But if you only have a part of the schema for specific json, you can combine `Get()` and `Unmarshal()` together:\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\n\nnode, err := sonic.GetFromString(_TwitterJson, \"statuses\", 3, \"user\")\nvar user User \u002F\u002F your partial schema...\nerr = sonic.UnmarshalString(node.Raw(), &user)\n```\n\nEven if you don't have any schema, use `ast.Node` as the container of generic values instead of `map` or `interface`:\n\n```go\nimport \"github.com\u002Fbytedance\u002Fsonic\"\n\nroot, err := sonic.GetFromString(_TwitterJson)\nuser := root.GetByPath(\"statuses\", 3, \"user\")  \u002F\u002F === root.Get(\"status\").Index(3).Get(\"user\")\nerr = user.Check()\n\n\u002F\u002F err = user.LoadAll() \u002F\u002F only call this when you want to use 'user' concurrently...\ngo someFunc(user)\n```\n\nWhy? Because `ast.Node` stores its children using `array`:\n\n- `Array`'s performance is **much better** than `Map` when Inserting (Deserialize) and Scanning (Serialize) data;\n- **Hashing** (`map[x]`) is not as efficient as **Indexing** (`array[x]`), which `ast.Node` can conduct on **both array and object**;\n- Using `Interface()`\u002F`Map()` means Sonic must parse all the underlying values, while `ast.Node` can parse them **on demand**.\n\n**CAUTION:** `ast.Node` **DOESN'T** ensure concurrent security directly, due to its **lazy-load** design. However, you can call `Node.Load()`\u002F`Node.LoadAll()` to achieve that, which may bring performance reduction while it still works faster than converting to `map` or `interface{}`\n\n### Ast.Node or Ast.Visitor?\n\nFor generic data, `ast.Node` should be enough for your needs in most cases.\n\nHowever, `ast.Node` is designed for partially processing JSON string. It has some special designs such as lazy-load which might not be suitable for directly parsing the whole JSON string like `Unmarshal()`. Although `ast.Node` is better then `map` or `interface{}`, it's also a kind of intermediate representation after all if your final types are customized and you have to convert the above types to your custom types after parsing.\n\nFor better performance, in previous case the `ast.Visitor` will be the better choice. It performs JSON decoding like `Unmarshal()` and you can directly use your final types to represents a JSON AST without any intermediate representations.\n\nBut `ast.Visitor` is not a very handy API. You might need to write a lot of code to implement your visitor and carefully maintain the tree hierarchy during decoding. Please read the comments in [ast\u002Fvisitor.go](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fblob\u002Fmain\u002Fast\u002Fvisitor.go) carefully if you decide to use this API.\n\n### Buffer Size\n\nSonic use memory pool in many places like `encoder.Encode`, `ast.Node.MarshalJSON` to improve performance, which may produce more memory usage (in-use) when server's load is high. See [issue 614](https:\u002F\u002Fgithub.com\u002Fbytedance\u002Fsonic\u002Fissues\u002F614). Therefore, we introduce some options to let user control the behavior of memory pool. See [option](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fbytedance\u002Fsonic@v1.11.9\u002Foption#pkg-variables) package.\n\n### Faster JSON Skip\n\nFor security, sonic use [FSM](native\u002Fskip_one.c) algorithm to  validate JSON when decoding raw JSON or encoding `json.Marshaler`, which is much slower (1~10x) than [SIMD-searching-pair](native\u002Fskip_one_fast.c) algorithm. If user has many redundant JSON value and DO NOT NEED to strictly validate JSON correctness, you can enable below options:\n\n- `Config.NoValidateSkipJSON`: for faster skipping JSON when decoding, such as unknown fields, json.Unmarshaler(json.RawMessage), mismatched values, and redundant array elements\n- `Config.NoValidateJSONMarshaler`: avoid validating JSON when encoding `json.Marshaler`\n- `SearchOption.ValidateJSON`: indicates if validate located JSON value when `Get`\n\n## JSON-Path Support (GJSON)\n\n[tidwall\u002Fgjson](https:\u002F\u002Fgithub.com\u002Ftidwall\u002Fgjson) has provided a comprehensive and popular JSON-Path API, and\n a lot of older codes heavily relies on it. Therefore, we provides a wrapper library, which combines gjson's API with sonic's SIMD algorithm to boost up the performance. See [cloudwego\u002Fgjson](https:\u002F\u002Fgithub.com\u002Fcloudwego\u002Fgjson).\n\n## Community\n\nSonic is a subproject of [CloudWeGo](https:\u002F\u002Fwww.cloudwego.io\u002F). We are committed to building a cloud native ecosystem.\n","Sonic 是一个高性能的 JSON 序列化和反序列化库，通过 JIT（即时编译）和 SIMD（单指令多数据流）技术加速。其核心功能包括运行时对象绑定无需代码生成、全面的 JSON 操作 API 以及极高的处理速度。适用于对性能有严格要求的应用场景，如大数据处理、实时数据分析等。Sonic 支持 Go 1.18 至 1.26 版本（注意 Go 1.24.0 不被支持），兼容 Linux、MacOS 和 Windows 操作系统及 AMD64 和 ARM64 架构的 CPU。基准测试显示，在各种大小的 JSON 数据和使用场景下，Sonic 的表现均优于其他主流 JSON 库。",2,"2026-06-11 03:02:30","top_language"]