{"id":17251064,"url":"https://github.com/fumieval/mason","last_synced_at":"2025-07-19T22:04:11.834Z","repository":{"id":49245468,"uuid":"223562661","full_name":"fumieval/mason","owner":"fumieval","description":"fleet-footed ByteString builder","archived":false,"fork":false,"pushed_at":"2024-07-31T07:57:42.000Z","size":104,"stargazers_count":51,"open_issues_count":1,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-13T09:09:09.733Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fumieval.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2019-11-23T09:19:53.000Z","updated_at":"2025-05-13T14:36:06.000Z","dependencies_parsed_at":"2024-07-31T09:16:53.270Z","dependency_job_id":null,"html_url":"https://github.com/fumieval/mason","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/fumieval/mason","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fumieval%2Fmason","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fumieval%2Fmason/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fumieval%2Fmason/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fumieval%2Fmason/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fumieval","download_url":"https://codeload.github.com/fumieval/mason/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fumieval%2Fmason/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266026177,"owners_count":23866030,"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":[],"created_at":"2024-10-15T06:50:15.525Z","updated_at":"2025-07-19T22:04:11.784Z","avatar_url":"https://github.com/fumieval.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"mason: alacritous builder library\n====\n\n[![Build Status](https://travis-ci.com/fumieval/mason.svg?branch=master)](https://travis-ci.com/fumieval/mason)\n[![Hackage](https://img.shields.io/hackage/v/mason)](https://hackage.haskell.org/package/mason)\n\nmason is a builder \u0026 IO library.\n\n* __Fast__: much faster than bytestring's Builder.\n* __Extensible__: Builders can be consumed in a user-defined way.\n* __Hackable__: Low-level APIs are exposed. It's easy to plug in even pointer-level operations.\n\n`Mason.Builder` has API mostly compatible with `Data.ByteString.Builder` but there are some additions to the original API:\n\n* `toStrictByteString` produces a strict `ByteString` directly.\n* `hPutBuilderLen` writes a builder to a handle and returns the number of bytes.\n* `sendBuilder` sends the content of `Builder` over a socket.\n* `withPopper` turns a builder into http-client's[GivesPopper](http://hackage.haskell.org/package/http-client-0.7.2.1/docs/Network-HTTP-Client.html#t:GivesPopper)\n* `toStreamingBody` creates wai's [StreamingBody](http://hackage.haskell.org/package/wai-3.2.2.1/docs/Network-Wai.html#t:StreamingBody)\n\nUsage\n----\n\nReplace `Data.ByteString.Builder` with `Mason.Builder`. Note that if you have `Builder` in the type signature, you'll need `RankNTypes` extensions because of the design explained below. Alternatively, you can also import `Mason.Builder.Compat` which has an API almost compatible with `Data.ByteString.Builder`.\n\nPerformance\n----\n\nAs long as the code is optimised, mason's builder can be very fast (twice or more as bytestring). Make sure that functions returning `Builder`s are well inlined.\n\nSerialisation of JSON-like structure:\n\n```\nmason/hPutBuilder                        mean 274.7 μs  ( +- 49.40 μs  )\nfast-builder/hPutBuilder                 mean 399.9 μs  ( +- 76.05 μs  )\nbytestring/hPutBuilder                   mean 335.1 μs  ( +- 86.96 μs  )\nmason/toStrictByteString                 mean 106.6 μs  ( +- 6.680 μs  )\nfast-builder/toStrictByteString          mean 254.8 μs  ( +- 31.64 μs  )\nbytestring/toLazyByteString              mean 283.3 μs  ( +- 24.26 μs  )\nmason/toLazyByteString                   mean 127.2 μs  ( +- 25.86 μs  )\nfast-builder/toLazyByteString            mean 249.0 μs  ( +- 25.60 μs  )\nbytestring/toLazyByteString              mean 263.4 μs  ( +- 9.401 μs  )\n```\n\nIn the same benchmark application, the allocation footprint of mason is feathery.\n\n```\ntoStrictByteString\nmason           291,112    0\nfast-builder    991,016    0\nbytestring    1,158,584    0 (toStrict . toLazyByteString)\n\ntoLazyByteString\nCase          Allocated  GCs\nmason           228,936    0\nfast-builder    903,752    0\nbytestring    1,101,448    0\n```\n\n`doubleDec` employs Grisu3 which grants ~20x speedup over `show`-based implementation.\n\n```\nmason/double                             mean 116.2 ns  ( +- 6.654 ns  )\nfast-builder/double                      mean 2.183 μs  ( +- 85.80 ns  )\nbytestring/double                        mean 2.312 μs  ( +- 118.8 ns  )\n```\n\nYou can find more benchmarks below:\n\n* [bytes-builder-shootout](https://github.com/andrewthad/bytes-builder-shootout)\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand\u003c/summary\u003e\n\u003cpre\u003e\ntreeToHex-2000/small-bytearray-builder   mean 44.01 μs  ( +- 1.620 μs  )\ntreeToHex-2000/fast-builder              mean 34.40 μs  ( +- 390.1 ns  )\ntreeToHex-2000/bytestring                mean 58.76 μs  ( +- 3.843 μs  )\ntreeToHex-2000/mason                     mean 41.08 μs  ( +- 180.8 ns  )\ntreeToHex-9000/small-bytearray-builder   mean 191.8 μs  ( +- 1.835 μs  )\ntreeToHex-9000/bytestring                mean 284.8 μs  ( +- 1.156 μs  )\ntreeToHex-9000/mason                     mean 181.2 μs  ( +- 386.3 ns  )\nshort-text-tree-1000/small-bytearray-builder mean 26.54 μs  ( +- 34.08 ns  )\nshort-text-tree-1000/fast-builder        mean 37.51 μs  ( +- 99.85 ns  )\nshort-text-tree-1000/bytestring          mean 37.95 μs  ( +- 167.5 ns  )\nshort-text-tree-1000/mason               mean 26.87 μs  ( +- 312.4 ns  )\nbyte-tree-2000/small-bytearray-builder   mean 30.53 μs  ( +- 51.53 ns  )\nbyte-tree-2000/fast-builder              mean 26.91 μs  ( +- 592.2 ns  )\nbyte-tree-2000/bytestring                mean 54.40 μs  ( +- 1.743 μs  )\nbyte-tree-2000/mason                     mean 34.34 μs  ( +- 193.5 ns  )\n\u003c/pre\u003e\n\u003c/details\u003e\n\n* [haskell-perf/strict-bytestring-builder](https://github.com/haskell-perf/strict-bytestring-builders)\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand\u003c/summary\u003e\n\u003cpre\u003e\naveragedAppends-1/byteStringStrictBuilder mean 116.3 ns  ( +- 6.479 ns  )\naveragedAppends-1/byteStringTreeBuilder  mean 181.7 ns  ( +- 20.88 ns  )\naveragedAppends-1/fastBuilder            mean 181.5 ns  ( +- 7.219 ns  )\naveragedAppends-1/bufferBuilder          mean 728.5 ns  ( +- 9.114 ns  )\naveragedAppends-1/byteString             mean 358.7 ns  ( +- 4.663 ns  )\naveragedAppends-1/blazeBuilder           mean 356.0 ns  ( +- 7.604 ns  )\naveragedAppends-1/binary                 mean 635.0 ns  ( +- 7.936 ns  )\naveragedAppends-1/cereal                 mean 638.6 ns  ( +- 12.40 ns  )\naveragedAppends-1/mason                  mean 155.2 ns  ( +- 2.000 ns  )\naveragedAppends-100/byteStringStrictBuilder mean 7.290 μs  ( +- 99.74 ns  )\naveragedAppends-100/byteStringTreeBuilder mean 13.40 μs  ( +- 283.4 ns  )\naveragedAppends-100/fastBuilder          mean 13.07 μs  ( +- 418.2 ns  )\naveragedAppends-100/bufferBuilder        mean 19.57 μs  ( +- 5.644 μs  )\naveragedAppends-100/byteString           mean 17.31 μs  ( +- 1.609 μs  )\naveragedAppends-100/blazeBuilder         mean 19.15 μs  ( +- 6.533 μs  )\naveragedAppends-100/binary               mean 48.26 μs  ( +- 727.1 ns  )\naveragedAppends-100/cereal               mean 51.57 μs  ( +- 21.81 μs  )\naveragedAppends-100/mason                mean 12.07 μs  ( +- 233.8 ns  )\naveragedAppends-10000/byteStringStrictBuilder mean 1.038 ms  ( +- 18.63 μs  )\naveragedAppends-10000/byteStringTreeBuilder mean 1.989 ms  ( +- 70.63 μs  )\naveragedAppends-10000/fastBuilder        mean 1.611 ms  ( +- 42.24 μs  )\naveragedAppends-10000/bufferBuilder      mean 1.895 ms  ( +- 25.09 μs  )\naveragedAppends-10000/byteString         mean 2.248 ms  ( +- 40.99 μs  )\naveragedAppends-10000/blazeBuilder       mean 2.394 ms  ( +- 1.016 ms  )\naveragedAppends-10000/binary             mean 6.503 ms  ( +- 157.6 μs  )\naveragedAppends-10000/cereal             mean 6.458 ms  ( +- 221.6 μs  )\naveragedAppends-10000/mason              mean 1.738 ms  ( +- 25.89 μs  )\nregularConcat-100/byteStringStrictBuilder mean 1.606 μs  ( +- 32.93 ns  )\nregularConcat-100/byteStringTreeBuilder  mean 2.000 μs  ( +- 43.73 ns  )\nregularConcat-100/fastBuilder            mean 1.364 μs  ( +- 37.95 ns  )\nregularConcat-100/bufferBuilder          mean 2.204 μs  ( +- 48.40 ns  )\nregularConcat-100/byteString             mean 1.253 μs  ( +- 25.68 ns  )\nregularConcat-100/blazeBuilder           mean 1.317 μs  ( +- 24.05 ns  )\nregularConcat-100/binary                 mean 2.845 μs  ( +- 62.24 ns  )\nregularConcat-100/cereal                 mean 3.021 μs  ( +- 48.53 ns  )\nregularConcat-100/mason                  mean 1.405 μs  ( +- 35.11 ns  )\nregularConcat-10000/byteStringStrictBuilder mean 321.3 μs  ( +- 11.13 μs  )\nregularConcat-10000/byteStringTreeBuilder mean 349.1 μs  ( +- 4.359 μs  )\nregularConcat-10000/fastBuilder          mean 121.0 μs  ( +- 1.755 μs  )\nregularConcat-10000/bufferBuilder        mean 156.1 μs  ( +- 2.050 μs  )\nregularConcat-10000/byteString           mean 106.6 μs  ( +- 1.355 μs  )\nregularConcat-10000/blazeBuilder         mean 110.8 μs  ( +- 1.397 μs  )\nregularConcat-10000/binary               mean 308.1 μs  ( +- 5.346 μs  )\nregularConcat-10000/cereal               mean 352.0 μs  ( +- 6.142 μs  )\nregularConcat-10000/mason                mean 130.2 μs  ( +- 10.39 μs  )\n\u003c/pre\u003e\n\u003c/details\u003e\n\nArchitecture\n----\n\nMason's builder is a function that takes a purpose-dependent environment and a buffer. There is little intermediate structure involved; almost everything runs in one pass. This design is inspired by [fast-builder](http://hackage.haskell.org/package/fast-builder).\n\n```haskell\ntype Builder = forall s. Buildable s =\u003e BuilderFor s\n\nnewtype BuilderFor s = Builder { unBuilder :: s -\u003e Buffer -\u003e IO Buffer }\n\ndata Buffer = Buffer\n  { bEnd :: {-# UNPACK #-} !(Ptr Word8) -- ^ end of the buffer (next to the last byte)\n  , bCur :: {-# UNPACK #-} !(Ptr Word8) -- ^ current position\n  }\n\nclass Buildable s where\n  byteString :: B.ByteString -\u003e BuilderFor s\n  flush :: BuilderFor s\n  allocate :: Int -\u003e BuilderFor s\n```\n\nInstances of the `Buildable` class implement purpose-specific behaviour (e.g. exponentially allocate a buffer, flush to disk). This generic interface also allows creative uses of Builders such as on-the-fly compression.\n\n`Builder` has a smart constructor called `ensure`:\n\n```haskell\nensure :: Int -\u003e (Buffer -\u003e IO Buffer) -\u003e Builder\n```\n\n`ensure n f` secures at least `n` bytes in the buffer and passes the pointer to `f`. This gives rise to monoid homorphism; namely, `ensure m f \u003c\u003e ensure n g` will fuse into `ensure (m + n) (f \u003e=\u003e g)` so don't worry about the overhead of bound checking.\n\nCreating your own primitives\n----\n\nThe easiest way to create a new primitive is `withPtr`, a simplified version of `ensure`. This is quite convenient for calling foreign functions or anything low-level.\n\n```haskell\n-- | Construct a 'Builder' from a \"poke\" function.\nwithPtr :: Int -- ^ number of bytes to allocate (if needed)\n  -\u003e (Ptr Word8 -\u003e IO (Ptr Word8)) -- ^ return a next pointer after writing\n  -\u003e Builder\n\ngrisu v = withPtr 24 $ \\ptr -\u003e do\n  n \u003c- dtoa_grisu3 v ptr\n  return $ plusPtr ptr (fromIntegral n)\n\nforeign import ccall unsafe \"static dtoa_grisu3\"\n  dtoa_grisu3 :: Double -\u003e Ptr Word8 -\u003e IO CInt\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffumieval%2Fmason","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffumieval%2Fmason","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffumieval%2Fmason/lists"}