{"id":18451860,"url":"https://github.com/go-faster/jx","last_synced_at":"2025-04-14T20:57:38.043Z","repository":{"id":36958668,"uuid":"422724362","full_name":"go-faster/jx","owner":"go-faster","description":"json encoding and decoding","archived":false,"fork":false,"pushed_at":"2024-11-27T05:15:55.000Z","size":2935,"stargazers_count":213,"open_issues_count":3,"forks_count":4,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-07T18:06:18.901Z","etag":null,"topics":["decoder","decoding","encoder","encoding","faster","go","golang","golang-library","iteration","json","rfc4627","rfc7159","streaming"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/go-faster.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-29T22:07:06.000Z","updated_at":"2025-04-07T07:38:03.000Z","dependencies_parsed_at":"2023-11-06T07:26:37.185Z","dependency_job_id":"26d9520e-30b0-4255-990f-475a725d2886","html_url":"https://github.com/go-faster/jx","commit_stats":{"total_commits":1259,"total_committers":60,"mean_commits":"20.983333333333334","dds":0.5949166004765687,"last_synced_commit":"6c6a4ab781b1bc14b0047c16e706cc76bfbdc919"},"previous_names":["ogen-go/jx"],"tags_count":77,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-faster%2Fjx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-faster%2Fjx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-faster%2Fjx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-faster%2Fjx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/go-faster","download_url":"https://codeload.github.com/go-faster/jx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248961186,"owners_count":21189991,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decoder","decoding","encoder","encoding","faster","go","golang","golang-library","iteration","json","rfc4627","rfc7159","streaming"],"created_at":"2024-11-06T07:29:42.667Z","updated_at":"2025-04-14T20:57:38.017Z","avatar_url":"https://github.com/go-faster.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# jx [![](https://img.shields.io/badge/go-pkg-00ADD8)](https://pkg.go.dev/github.com/go-faster/jx#section-documentation) [![](https://img.shields.io/codecov/c/github/go-faster/jx?label=cover)](https://codecov.io/gh/go-faster/jx) [![stable](https://img.shields.io/badge/-stable-brightgreen)](https://go-faster.org/docs/projects/status#stable)\n\nPackage jx implements encoding and decoding of json [[RFC 7159](https://www.rfc-editor.org/rfc/rfc7159.html)].\nLightweight fork of [jsoniter](https://github.com/json-iterator/go).\n\n```console\ngo get github.com/go-faster/jx\n```\n\n* [Usage and examples](#usage)\n* [Roadmap](#roadmap)\n* [Non-goals](#non-goals)\n\n## Features\n* Mostly zero-allocation and highly optimized\n* Directly encode and decode json values\n* No reflect or `interface{}`\n* Pools and direct buffer access for less (or none) allocations\n* Multi-pass decoding\n* Validation\n\nSee [usage](#Usage) for examples. Mostly suitable for fast low-level json manipulation\nwith high control, for dynamic parsing and encoding of unstructured data. Used in [ogen](https://github.com/ogen-go/ogen) project for\njson (un)marshaling code generation based on json and OpenAPI schemas.\n\nFor example, we have following OpenTelemetry log entry:\n\n```json\n{\n  \"Timestamp\": \"1586960586000000000\",\n  \"Attributes\": {\n    \"http.status_code\": 500,\n    \"http.url\": \"http://example.com\",\n    \"my.custom.application.tag\": \"hello\"\n  },\n  \"Resource\": {\n    \"service.name\": \"donut_shop\",\n    \"service.version\": \"2.0.0\",\n    \"k8s.pod.uid\": \"1138528c-c36e-11e9-a1a7-42010a800198\"\n  },\n  \"TraceId\": \"13e2a0921288b3ff80df0a0482d4fc46\",\n  \"SpanId\": \"43222c2d51a7abe3\",\n  \"SeverityText\": \"INFO\",\n  \"SeverityNumber\": 9,\n  \"Body\": \"20200415T072306-0700 INFO I like donuts\"\n}\n```\n\nFlexibility of `jx` enables highly efficient semantic-aware encoding and decoding,\ne.g. using `[16]byte` for `TraceId` with zero-allocation `hex` encoding in json:\n\n| Name     | Speed     | Allocations |\n|----------|-----------|-------------|\n| Decode   | 1279 MB/s | 0 allocs/op |\n| Validate | 1914 MB/s | 0 allocs/op |\n| Encode   | 1202 MB/s | 0 allocs/op |\n| Write    | 2055 MB/s | 0 allocs/op |\n\n`cpu: AMD Ryzen 9 7950X`\n\nSee [otel_test.go](./otel_test.go) for example.\n\n## Why\n\nMost of [jsoniter](https://github.com/json-iterator/go) issues are caused by necessity\nto be drop-in replacement for standard `encoding/json`. Removing such constrains greatly\nsimplified implementation and reduced scope, allowing to focus on json stream processing.\n\n* Commas are handled automatically while encoding\n* Raw json, Number and Base64 support\n* Reduced scope\n  * No reflection\n  * No `encoding/json` adapter\n  * 3.5x less code (8.5K to 2.4K SLOC)\n* Fuzzing, improved test coverage\n* Drastically refactored and simplified\n  * Explicit error returns\n  * No `Config` or `API`\n\n\n## Usage\n\n* [Decoding](#decode)\n* [Encoding](#encode)\n* [Writer](#writer)\n* [Raw message](#raw)\n* [Number](#number)\n* [Base64](#base64)\n* [Validation](#validate)\n* [Multi pass decoding](#capture)\n\n### Decode\n\nUse [jx.Decoder](https://pkg.go.dev/github.com/go-faster/jx#Decoder). Zero value is valid,\nbut constructors are available for convenience:\n  * [jx.Decode(reader io.Reader, bufSize int)](https://pkg.go.dev/github.com/go-faster/jx#Decode) for `io.Reader`\n  * [jx.DecodeBytes([]byte)](https://pkg.go.dev/github.com/go-faster/jx#Decode)  for byte slices\n  * [jx.DecodeStr(string)](https://pkg.go.dev/github.com/go-faster/jx#Decode) for strings\n\nTo reuse decoders and their buffers, use [jx.GetDecoder](https://pkg.go.dev/github.com/go-faster/jx#GetDecoder)\nand [jx.PutDecoder](https://pkg.go.dev/github.com/go-faster/jx#PutDecoder) alongside with reset functions:\n* [jx.Decoder.Reset(io.Reader)](https://pkg.go.dev/github.com/go-faster/jx#Decoder.Reset) to reset to new `io.Reader`\n* [jx.Decoder.ResetBytes([]byte)](https://pkg.go.dev/github.com/go-faster/jx#Decoder.ResetBytes) to decode another byte slice\n\nDecoder is reset on `PutDecoder`.\n\n```go\nd := jx.DecodeStr(`{\"values\":[4,8,15,16,23,42]}`)\n\n// Save all integers from \"values\" array to slice.\nvar values []int\n\n// Iterate over each object field.\nif err := d.Obj(func(d *jx.Decoder, key string) error {\n    switch key {\n    case \"values\":\n        // Iterate over each array element.\n        return d.Arr(func(d *jx.Decoder) error {\n            v, err := d.Int()\n            if err != nil {\n                return err\n            }\n            values = append(values, v)\n            return nil\n        })\n    default:\n        // Skip unknown fields if any.\n        return d.Skip()\n    }\n}); err != nil {\n    panic(err)\n}\n\nfmt.Println(values)\n// Output: [4 8 15 16 23 42]\n```\n\n### Encode\nUse [jx.Encoder](https://pkg.go.dev/github.com/go-faster/jx#Encoder). Zero value is valid, reuse with\n[jx.GetEncoder](https://pkg.go.dev/github.com/go-faster/jx#GetEncoder),\n[jx.PutEncoder](https://pkg.go.dev/github.com/go-faster/jx#PutEncoder) and\n[jx.Encoder.Reset()](https://pkg.go.dev/github.com/go-faster/jx#Encoder.Reset). Encoder is reset on `PutEncoder`.\n```go\nvar e jx.Encoder\ne.ObjStart()           // {\ne.FieldStart(\"values\") // \"values\":\ne.ArrStart()           // [\nfor _, v := range []int{4, 8, 15, 16, 23, 42} {\n    e.Int(v)\n}\ne.ArrEnd() // ]\ne.ObjEnd() // }\nfmt.Println(e)\nfmt.Println(\"Buffer len:\", len(e.Bytes()))\n// Output: {\"values\":[4,8,15,16,23,42]}\n// Buffer len: 28\n```\n\n### Writer\n\nUse [jx.Writer](https://pkg.go.dev/github.com/go-faster/jx#Writer) for low level json writing.\n\nNo automatic commas or indentation for lowest possible overhead, useful for code generated json encoding.\n\n### Raw\nUse [jx.Decoder.Raw](https://pkg.go.dev/github.com/go-faster/jx#Decoder.Raw) to read raw json values, similar to `json.RawMessage`.\n```go\nd := jx.DecodeStr(`{\"foo\": [1, 2, 3]}`)\n\nvar raw jx.Raw\nif err := d.Obj(func(d *jx.Decoder, key string) error {\n    v, err := d.Raw()\n    if err != nil {\n        return err\n    }\n    raw = v\n    return nil\n}); err != nil {\n    panic(err)\n}\n\nfmt.Println(raw.Type(), raw)\n// Output:\n// array [1, 2, 3]\n```\n\n### Number\n\nUse [jx.Decoder.Num](https://pkg.go.dev/github.com/go-faster/jx#Decoder.Num) to read numbers, similar to `json.Number`.\nAlso supports number strings, like `\"12345\"`, which is common compatible way to represent `uint64`.\n\n```go\nd := jx.DecodeStr(`{\"foo\": \"10531.0\"}`)\n\nvar n jx.Num\nif err := d.Obj(func(d *jx.Decoder, key string) error {\n    v, err := d.Num()\n    if err != nil {\n        return err\n    }\n    n = v\n    return nil\n}); err != nil {\n    panic(err)\n}\n\nfmt.Println(n)\nfmt.Println(\"positive:\", n.Positive())\n\n// Can decode floats with zero fractional part as integers:\nv, err := n.Int64()\nif err != nil {\n    panic(err)\n}\nfmt.Println(\"int64:\", v)\n// Output:\n// \"10531.0\"\n// positive: true\n// int64: 10531\n```\n\n### Base64\nUse [jx.Encoder.Base64](https://pkg.go.dev/github.com/go-faster/jx#Encoder.Base64) and\n[jx.Decoder.Base64](https://pkg.go.dev/github.com/go-faster/jx#Decoder.Base64) or\n[jx.Decoder.Base64Append](https://pkg.go.dev/github.com/go-faster/jx#Decoder.Base64Append).\n\nSame as encoding/json, base64.StdEncoding or [[RFC 4648](https://www.rfc-editor.org/rfc/rfc4648.html)].\n```go\nvar e jx.Encoder\ne.Base64([]byte(\"Hello\"))\nfmt.Println(e)\n\ndata, _ := jx.DecodeBytes(e.Bytes()).Base64()\nfmt.Printf(\"%s\", data)\n// Output:\n// \"SGVsbG8=\"\n// Hello\n```\n\n### Validate\n\nCheck that byte slice is valid json with [jx.Valid](https://pkg.go.dev/github.com/go-faster/jx#Valid):\n\n```go\nfmt.Println(jx.Valid([]byte(`{\"field\": \"value\"}`))) // true\nfmt.Println(jx.Valid([]byte(`\"Hello, world!\"`)))    // true\nfmt.Println(jx.Valid([]byte(`[\"foo\"}`)))            // false\n```\n\n### Capture\nThe [jx.Decoder.Capture](https://pkg.go.dev/github.com/go-faster/jx#Decoder.Capture) method allows to unread everything is read in callback.\nUseful for multi-pass parsing:\n```go\nd := jx.DecodeStr(`[\"foo\", \"bar\", \"baz\"]`)\nvar elems int\n// NB: Currently Capture does not support io.Reader, only buffers.\nif err := d.Capture(func(d *jx.Decoder) error {\n\t// Everything decoded in this callback will be rolled back.\n\treturn d.Arr(func(d *jx.Decoder) error {\n\t\telems++\n\t\treturn d.Skip()\n\t})\n}); err != nil {\n\tpanic(err)\n}\n// Decoder is rolled back to state before \"Capture\" call.\nfmt.Println(\"Read\", elems, \"elements on first pass\")\nfmt.Println(\"Next element is\", d.Next(), \"again\")\n\n// Output:\n// Read 3 elements on first pass\n// Next element is array again\n```\n\n### ObjBytes\n\nThe `Decoder.ObjBytes` method tries not to allocate memory for keys, reusing existing buffer.\n```go\nd := DecodeStr(`{\"id\":1,\"randomNumber\":10}`)\nd.ObjBytes(func(d *Decoder, key []byte) error {\n    switch string(key) {\n    case \"id\":\n    case \"randomNumber\":\n    }\n    return d.Skip()\n})\n```\n\n## Roadmap\n- [ ] Rework and export `Any`\n- [x] Support `Raw` for io.Reader\n- [x] Support `Capture` for io.Reader\n- [ ] Improve Num\n  - Better validation on decoding\n  - Support BigFloat and BigInt\n  - Support equivalence check, like `eq(1.0, 1) == true`\n- [ ] Add non-callback decoding of objects\n\n## Non-goals\n* Code generation for decoding or encoding\n* Replacement for `encoding/json`\n* Reflection or `interface{}` based encoding or decoding\n* Support for json path or similar\n\nThis package should be kept as simple as possible and be used as\nlow-level foundation for high-level projects like code generator.\n\n## License\nMIT, same as jsoniter\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-faster%2Fjx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgo-faster%2Fjx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-faster%2Fjx/lists"}