- Notifications
You must be signed in to change notification settings - Fork217
An incredibly fast, pure Elixir JSON library
License
devinus/poison
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Poison is a new JSON library for Elixir focusing on wicked-fastspeedwithout sacrificingsimplicity,completeness, orcorrectness.
Poison takes several approaches to be the fastest JSON library for Elixir.
Poison uses extensivesub binary matching, ahand-rolled parser usingseveral techniques that areknown to benefit BeamAsm for JIT compilation,IO list encoding andsingle-pass decoding.
Poison benchmarks sometimes puts Poison's performance close tojiffy
andusually faster than other Erlang/Elixir libraries.
Poison fully conforms toRFC 8259,ECMA 404, and fully passes theJSONTestSuite.
First, add Poison to yourmix.exs
dependencies:
defdepsdo[{:poison,"~> 6.0"}]end
Then, update your dependencies:
mix deps.get
Poison.encode!(%{"age"=>27,"name"=>"Devin Torres"})#=> "{\"name\":\"Devin Torres\",\"age\":27}"Poison.decode!(~s({"name": "Devin Torres", "age": 27}))#=> %{"age" => 27, "name" => "Devin Torres"}defmodulePersondo@derive[Poison.Encoder]defstruct[:name,:age]endPoison.encode!(%Person{name:"Devin Torres",age:27})#=> "{\"name\":\"Devin Torres\",\"age\":27}"Poison.decode!(~s({"name": "Devin Torres", "age": 27}),as:%Person{})#=> %Person{name: "Devin Torres", age: 27}Poison.decode!(~s({"people": [{"name": "Devin Torres", "age": 27}]}),as:%{"people"=>[%Person{}]})#=> %{"people" => [%Person{age: 27, name: "Devin Torres"}]}
Every component of Poison (encoder, decoder, and parser) are all usable ontheir own without buying into other functionality. For example, if you wereinterested purely in the speed of parsing JSON without a decoding step, youcould simply callPoison.Parser.parse
.
iex> Poison.Parser.parse!(~s({"name": "Devin Torres", "age": 27}), %{})%{"name" => "Devin Torres", "age" => 27}iex> Poison.Parser.parse!(~s({"name": "Devin Torres", "age": 27}), %{keys: :atoms!})%{name: "Devin Torres", age: 27}
Note thatkeys: :atoms!
reuses existing atoms, i.e. if:name
was notallocated before the call, you will encounter anargument error
message.
You can use thekeys: :atoms
variant to make sure all atoms are created asneeded. However, unless you absolutely know what you're doing, donot doit. Atoms are not garbage-collected, seeErlang Efficiency Guidefor more info:
Atoms are not garbage-collected. Once an atom is created, it will never beremoved. The emulator will terminate if the limit for the number of atoms(1048576 by default) is reached.
iex> Poison.Encoder.encode([1, 2, 3], %{}) |> IO.iodata_to_binary"[1,2,3]"
Anything implementing the Encoder protocol is expected to return anIO list to be embedded within any other Encoder's implementation andpassable to any IO subsystem without conversion.
defimplPoison.Encoder,for:Persondodefencode(%{name:name,age:age},options)doPoison.Encoder.BitString.encode("#{name} (#{age})",options)endend
For maximum performance, make sure you@derive [Poison.Encoder]
for anystruct you plan on encoding.
When deriving structs for encoding, it is possible to select or excludespecific attributes. This is achieved by derivingPoison.Encoder
with the:only
or:except
options set:
defmodulePersonOnlyNamedo@derive{Poison.Encoder,only:[:name]}defstruct[:name,:age]enddefmodulePersonWithoutNamedo@derive{Poison.Encoder,except:[:name]}defstruct[:name,:age]end
In case both:only
and:except
keys are defined, the:except
option isignored.
According toRFC 8259 keys in a JSON object should be unique. This isenforced and resolved in different ways in other libraries. In the Ruby JSONlibrary for example, the output generated from encoding a hash with a duplicatekey (say one is a string, the other an atom) will include both keys. Whenparsing JSON of this type, Chromium will override all previous values with thefinal one.
Poison will generate JSON with duplicate keys if you attempt to encode a mapwith atom and string keys whose encoded names would clash. If you'd like toensure that your generated JSON doesn't have this issue, you can pass thestrict_keys: true
option when encoding. This will force the encoding to fail.
Note: Validating keys can cause a small performance hit.
iex> Poison.encode!(%{:foo => "foo1", "foo" => "foo2"}, strict_keys: true)** (Poison.EncodeError) duplicate key found: :foo
MIX_ENV=bench mix run bench/run.exs
As of 2024-06-06:
- Amazon EC2 c6i.2xlarge instance running Ubuntu Server 22.04:https://gist.github.com/devinus/afb351ae45194a6b93b6db9bf2d4c163
Poison is released under thepublic-domain-equivalent0BSD license.
About
An incredibly fast, pure Elixir JSON library