{"id":16732863,"url":"https://github.com/nikita-volkov/jsonifier","last_synced_at":"2025-05-08T19:36:55.353Z","repository":{"id":45610732,"uuid":"303738671","full_name":"nikita-volkov/jsonifier","owner":"nikita-volkov","description":"Fast and simple JSON encoding toolkit","archived":false,"fork":false,"pushed_at":"2023-12-09T11:33:24.000Z","size":1412,"stargazers_count":82,"open_issues_count":1,"forks_count":1,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-17T18:11:59.667Z","etag":null,"topics":["bytestring","haskell","json","marshalling","serialization"],"latest_commit_sha":null,"homepage":"http://hackage.haskell.org/package/jsonifier","language":"Haskell","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/nikita-volkov.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":"2020-10-13T14:57:07.000Z","updated_at":"2024-12-12T08:09:22.000Z","dependencies_parsed_at":"2024-10-26T21:11:44.129Z","dependency_job_id":"ac4e9d05-ce65-4f77-9e73-82616c6e41da","html_url":"https://github.com/nikita-volkov/jsonifier","commit_stats":{"total_commits":174,"total_committers":2,"mean_commits":87.0,"dds":0.005747126436781658,"last_synced_commit":"93eafd14724762ab2191b94452750a4d908d3d25"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikita-volkov%2Fjsonifier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikita-volkov%2Fjsonifier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikita-volkov%2Fjsonifier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikita-volkov%2Fjsonifier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikita-volkov","download_url":"https://codeload.github.com/nikita-volkov/jsonifier/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253135567,"owners_count":21859666,"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":["bytestring","haskell","json","marshalling","serialization"],"created_at":"2024-10-12T23:47:04.482Z","updated_at":"2025-05-08T19:36:55.305Z","avatar_url":"https://github.com/nikita-volkov.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Summary\n\nMinimalistic library for encoding JSON directly to strict bytestring.\n\nThe library focuses on 2 aspects: **simplicity** and **performance**.\nThe API consists of just a few functions and\nachieves performance that gets up to **3 times** better than that of \"aeson\"\nin typical use-cases.\nIn cases where we deal with very large documents the performance difference\nbecomes less drastic.\n\n# Performance\n\n## Benchmarks\n\nFollowing are the benchmark results comparing the performance\nof encoding typical documents using this library and \"aeson\".\nEvery approach is measured on Twitter API data of sizes ranging from roughly 1kB to 60MB.\n\"aeson\" stands for \"aeson\" producing a strict bytestring,\n\"lazy-aeson\" - lazy bytestring,\n\"lazy-aeson-untrimmed-32k\" - lazy bytestring using an untrimmed builder strategy with allocation of 32k.\n\n```\n1kB/jsonifier                            mean 2.054 μs  ( +- 30.83 ns  )\n1kB/aeson                                mean 6.456 μs  ( +- 126.7 ns  )\n1kB/lazy-aeson                           mean 6.338 μs  ( +- 169.1 ns  )\n1kB/lazy-aeson-untrimmed-32k             mean 6.905 μs  ( +- 280.2 ns  )\n\n6kB/jsonifier                            mean 12.80 μs  ( +- 196.9 ns  )\n6kB/aeson                                mean 31.28 μs  ( +- 733.2 ns  )\n6kB/lazy-aeson                           mean 30.30 μs  ( +- 229.5 ns  )\n6kB/lazy-aeson-untrimmed-32k             mean 29.17 μs  ( +- 371.3 ns  )\n\n60kB/jsonifier                           mean 122.9 μs  ( +- 1.492 μs  )\n60kB/aeson                               mean 258.4 μs  ( +- 1.000 μs  )\n60kB/lazy-aeson                          mean 259.4 μs  ( +- 4.494 μs  )\n60kB/lazy-aeson-untrimmed-32k            mean 255.7 μs  ( +- 3.239 μs  )\n\n600kB/jsonifier                          mean 1.299 ms  ( +- 16.44 μs  )\n600kB/aeson                              mean 3.389 ms  ( +- 106.8 μs  )\n600kB/lazy-aeson                         mean 2.520 ms  ( +- 45.51 μs  )\n600kB/lazy-aeson-untrimmed-32k           mean 2.509 ms  ( +- 30.76 μs  )\n\n6MB/jsonifier                            mean 20.91 ms  ( +- 821.7 μs  )\n6MB/aeson                                mean 30.74 ms  ( +- 509.4 μs  )\n6MB/lazy-aeson                           mean 24.83 ms  ( +- 184.3 μs  )\n6MB/lazy-aeson-untrimmed-32k             mean 24.93 ms  ( +- 383.2 μs  )\n\n60MB/jsonifier                           mean 194.8 ms  ( +- 13.93 ms  )\n60MB/aeson                               mean 276.0 ms  ( +- 5.194 ms  )\n60MB/lazy-aeson                          mean 246.9 ms  ( +- 3.122 ms  )\n60MB/lazy-aeson-untrimmed-32k            mean 245.1 ms  ( +- 1.050 ms  )\n```\n\nThe benchmark suite is bundled with the package.\n\n## Reasoning\n\nSuch performance is achieved due to the approach taken to the process of building a bytestring. Unlike \"aeson\", this library doesn't use the builder distributed with the \"bytestring\" package, instead it uses a custom solution which produces a bytestring in two steps: first it counts how many bytes the rendering of data will occupy then it allocates a buffer of that exact size and renders directly into it. As the benchmarks show, at least for the purpose of rendering JSON this approach turns out to be faster than manipulations on temporary buffers which the builder from \"bytestring\" does.\n\nThis approach opens doors to optimizations otherwise inaccessible. E.g., we can efficiently count how many bytes a `Text` value encoded as JSON string literal will occupy, then render it into its final destination in one pass. We can efficiently count how many bytes a decimal encoding of an integer will occupy, and also render it in one pass despite the rendering of integers needing to be done in reverse direction and requiring a second pass of reversing the bytes in alternative solutions.\n\n*With all those observations some general concepts have emerged and have been extracted as the lower-level [\"ptr-poker\" package](https://github.com/nikita-volkov/ptr-poker), which focuses on the problem of populating pointers.*\n\n# Quality\n\nThe quality of the library is ensured with a test property in which a random JSON tree is generated, then rendered using \"jsonifier\", then parsed using \"aeson\" and compared to the original.\n\n# Demo\n\nFollowing is a complete program that shows how you can render\nJSON from your domain model.\n\n```haskell\n{-# LANGUAGE OverloadedStrings, RecordWildCards #-}\n\nimport qualified Jsonifier as J\nimport qualified Data.ByteString.Char8\n\n\n{-|\nOutputs the following:\n\n\u003e {\"name\":\"Metallica\",\"genres\":[{\"name\":\"Metal\"},{\"name\":\"Rock\"},{\"name\":\"Blues\"}]}\n-}\nmain =\n  Data.ByteString.Char8.putStrLn (J.toByteString (artistJson metallica))\n\nmetallica :: Artist\nmetallica =\n  Artist \"Metallica\" [Genre \"Metal\", Genre \"Rock\", Genre \"Blues\"]\n\n\n-- * Model\n-------------------------\n\ndata Artist =\n  Artist { artistName :: Text, artistGenres :: [Genre] }\n\ndata Genre =\n  Genre { genreName :: Text }\n\n\n-- * Encoders\n-------------------------\n\nartistJson :: Artist -\u003e J.Json\nartistJson Artist{..} =\n  J.object [\n    (\"name\", J.textString artistName),\n    (\"genres\", J.array (fmap genreJson artistGenres))\n    ]\n\ngenreJson :: Genre -\u003e J.Json\ngenreJson Genre{..} =\n  J.object [\n    (\"name\", J.textString genreName)\n    ]\n```\n\nA compilable version of this demo comes bundled with the package as the \\\"demo\\\" test-suite.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikita-volkov%2Fjsonifier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikita-volkov%2Fjsonifier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikita-volkov%2Fjsonifier/lists"}