1[![Build Status](https://travis-ci.org/francoispqt/gojay.svg?branch=master)](https://travis-ci.org/francoispqt/gojay)
2[![codecov](https://codecov.io/gh/francoispqt/gojay/branch/master/graph/badge.svg)](https://codecov.io/gh/francoispqt/gojay)
3[![Go Report Card](https://goreportcard.com/badge/github.com/francoispqt/gojay)](https://goreportcard.com/report/github.com/francoispqt/gojay)
4[![Go doc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square
5)](https://godoc.org/github.com/francoispqt/gojay)
6![MIT License](https://img.shields.io/badge/license-mit-blue.svg?style=flat-square)
7[![Sourcegraph](https://sourcegraph.com/github.com/francoispqt/gojay/-/badge.svg)](https://sourcegraph.com/github.com/francoispqt/gojay)
8![stability-stable](https://img.shields.io/badge/stability-stable-green.svg)
9
10# GoJay
11
12<img src="https://github.com/francoispqt/gojay/raw/master/gojay.png" width="200px">
13
14GoJay is a performant JSON encoder/decoder for Golang (currently the most performant, [see benchmarks](#benchmark-results)).
15
16It has a simple API and doesn't use reflection. It relies on small interfaces to decode/encode structures and slices.
17
18Gojay also comes with powerful stream decoding features and an even faster [Unsafe](#unsafe-api) API.
19
20There is also a [code generation tool](https://github.com/francoispqt/gojay/tree/master/gojay) to make usage easier and faster.
21
22# Why another JSON parser?
23
24I looked at other fast decoder/encoder and realised it was mostly hardly readable static code generation or a lot of reflection, poor streaming features, and not so fast in the end.
25
26Also, I wanted to build a decoder that could consume an io.Reader of line or comma delimited JSON, in a JIT way. To consume a flow of JSON objects from a TCP connection for example or from a standard output. Same way I wanted to build an encoder that could encode a flow of data to a io.Writer.
27
28This is how GoJay aims to be a very fast, JIT stream parser with 0 reflection, low allocation with a friendly API.
29
30# Get started
31
32```bash
33go get github.com/francoispqt/gojay
34```
35
36* [Encoder](#encoding)
37* [Decoder](#decoding)
38* [Stream API](#stream-api)
39* [Code Generation](https://github.com/francoispqt/gojay/tree/master/gojay)
40
41## Decoding
42
43Decoding is done through two different API similar to standard `encoding/json`:
44* [Unmarshal](#unmarshal-api)
45* [Decode](#decode-api)
46
47
48Example of basic stucture decoding with Unmarshal:
49```go
50import "github.com/francoispqt/gojay"
51
52type user struct {
53    id int
54    name string
55    email string
56}
57// implement gojay.UnmarshalerJSONObject
58func (u *user) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
59    switch key {
60    case "id":
61        return dec.Int(&u.id)
62    case "name":
63        return dec.String(&u.name)
64    case "email":
65        return dec.String(&u.email)
66    }
67    return nil
68}
69func (u *user) NKeys() int {
70    return 3
71}
72
73func main() {
74    u := &user{}
75    d := []byte(`{"id":1,"name":"gojay","email":"gojay@email.com"}`)
76    err := gojay.UnmarshalJSONObject(d, u)
77    if err != nil {
78        log.Fatal(err)
79    }
80}
81```
82
83with Decode:
84```go
85func main() {
86    u := &user{}
87    dec := gojay.NewDecoder(bytes.NewReader([]byte(`{"id":1,"name":"gojay","email":"gojay@email.com"}`)))
88    err := dec.DecodeObject(d, u)
89    if err != nil {
90        log.Fatal(err)
91    }
92}
93```
94
95### Unmarshal API
96
97Unmarshal API decodes a `[]byte` to a given pointer with a single function.
98
99Behind the doors, Unmarshal API borrows a `*gojay.Decoder` resets its settings and decodes the data to the given pointer and releases the `*gojay.Decoder` to the pool when it finishes, whether it encounters an error or not.
100
101If it cannot find the right Decoding strategy for the type of the given pointer, it returns an `InvalidUnmarshalError`. You can test the error returned by doing `if ok := err.(InvalidUnmarshalError); ok {}`.
102
103Unmarshal API comes with three functions:
104* Unmarshal
105```go
106func Unmarshal(data []byte, v interface{}) error
107```
108
109* UnmarshalJSONObject
110```go
111func UnmarshalJSONObject(data []byte, v gojay.UnmarshalerJSONObject) error
112```
113
114* UnmarshalJSONArray
115```go
116func UnmarshalJSONArray(data []byte, v gojay.UnmarshalerJSONArray) error
117```
118
119
120### Decode API
121
122Decode API decodes a `[]byte` to a given pointer by creating or borrowing a `*gojay.Decoder` with an `io.Reader` and calling `Decode` methods.
123
124__Getting a *gojay.Decoder or Borrowing__
125
126You can either get a fresh `*gojay.Decoder` calling `dec := gojay.NewDecoder(io.Reader)` or borrow one from the pool by calling `dec := gojay.BorrowDecoder(io.Reader)`.
127
128After using a decoder, you can release it by calling `dec.Release()`. Beware, if you reuse the decoder after releasing it, it will panic with an error of type `InvalidUsagePooledDecoderError`. If you want to fully benefit from the pooling, you must release your decoders after using.
129
130Example getting a fresh an releasing:
131```go
132str := ""
133dec := gojay.NewDecoder(strings.NewReader(`"test"`))
134defer dec.Release()
135if err := dec.Decode(&str); err != nil {
136    log.Fatal(err)
137}
138```
139Example borrowing a decoder and releasing:
140```go
141str := ""
142dec := gojay.BorrowDecoder(strings.NewReader(`"test"`))
143defer dec.Release()
144if err := dec.Decode(&str); err != nil {
145    log.Fatal(err)
146}
147```
148
149`*gojay.Decoder` has multiple methods to decode to specific types:
150* Decode
151```go
152func (dec *gojay.Decoder) Decode(v interface{}) error
153```
154* DecodeObject
155```go
156func (dec *gojay.Decoder) DecodeObject(v gojay.UnmarshalerJSONObject) error
157```
158* DecodeArray
159```go
160func (dec *gojay.Decoder) DecodeArray(v gojay.UnmarshalerJSONArray) error
161```
162* DecodeInt
163```go
164func (dec *gojay.Decoder) DecodeInt(v *int) error
165```
166* DecodeBool
167```go
168func (dec *gojay.Decoder) DecodeBool(v *bool) error
169```
170* DecodeString
171```go
172func (dec *gojay.Decoder) DecodeString(v *string) error
173```
174
175All DecodeXxx methods are used to decode top level JSON values. If you are decoding keys or items of a JSON object or array, don't use the Decode methods.
176
177Example:
178```go
179reader := strings.NewReader(`"John Doe"`)
180dec := NewDecoder(reader)
181
182var str string
183err := dec.DecodeString(&str)
184if err != nil {
185    log.Fatal(err)
186}
187
188fmt.Println(str) // John Doe
189```
190
191### Structs and Maps
192#### UnmarshalerJSONObject Interface
193
194To unmarshal a JSON object to a structure, the structure must implement the `UnmarshalerJSONObject` interface:
195```go
196type UnmarshalerJSONObject interface {
197	UnmarshalJSONObject(*gojay.Decoder, string) error
198	NKeys() int
199}
200```
201`UnmarshalJSONObject` method takes two arguments, the first one is a pointer to the Decoder (*gojay.Decoder) and the second one is the string value of the current key being parsed. If the JSON data is not an object, the UnmarshalJSONObject method will never be called.
202
203`NKeys` method must return the number of keys to Unmarshal in the JSON object or 0. If zero is returned, all keys will be parsed.
204
205Example of implementation for a struct:
206```go
207type user struct {
208    id int
209    name string
210    email string
211}
212// implement UnmarshalerJSONObject
213func (u *user) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
214    switch key {
215    case "id":
216        return dec.Int(&u.id)
217    case "name":
218        return dec.String(&u.name)
219    case "email":
220        return dec.String(&u.email)
221    }
222    return nil
223}
224func (u *user) NKeys() int {
225    return 3
226}
227```
228
229Example of implementation for a `map[string]string`:
230```go
231// define our custom map type implementing UnmarshalerJSONObject
232type message map[string]string
233
234// Implementing Unmarshaler
235func (m message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
236	str := ""
237	err := dec.String(&str)
238	if err != nil {
239		return err
240	}
241	m[k] = str
242	return nil
243}
244
245// we return 0, it tells the Decoder to decode all keys
246func (m message) NKeys() int {
247	return 0
248}
249```
250
251### Arrays, Slices and Channels
252
253To unmarshal a JSON object to a slice an array or a channel, it must implement the UnmarshalerJSONArray interface:
254```go
255type UnmarshalerJSONArray interface {
256	UnmarshalJSONArray(*gojay.Decoder) error
257}
258```
259UnmarshalJSONArray method takes one argument, a pointer to the Decoder (*gojay.Decoder). If the JSON data is not an array, the Unmarshal method will never be called.
260
261Example of implementation with a slice:
262```go
263type testSlice []string
264// implement UnmarshalerJSONArray
265func (t *testSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
266	str := ""
267	if err := dec.String(&str); err != nil {
268		return err
269	}
270	*t = append(*t, str)
271	return nil
272}
273
274func main() {
275	dec := gojay.BorrowDecoder(strings.NewReader(`["Tom", "Jim"]`))
276	var slice testSlice
277	err := dec.DecodeArray(&slice)
278	if err != nil {
279		log.Fatal(err)
280	}
281	fmt.Println(slice) // [Tom Jim]
282	dec.Release()
283}
284```
285
286Example of implementation with a channel:
287```go
288type testChannel chan string
289// implement UnmarshalerJSONArray
290func (c testChannel) UnmarshalJSONArray(dec *gojay.Decoder) error {
291	str := ""
292	if err := dec.String(&str); err != nil {
293		return err
294	}
295	c <- str
296	return nil
297}
298
299func main() {
300	dec := gojay.BorrowDecoder(strings.NewReader(`["Tom", "Jim"]`))
301	c := make(testChannel, 2)
302	err := dec.DecodeArray(c)
303	if err != nil {
304		log.Fatal(err)
305	}
306	for i := 0; i < 2; i++ {
307		fmt.Println(<-c)
308	}
309	close(c)
310	dec.Release()
311}
312```
313
314Example of implementation with an array:
315```go
316type testArray [3]string
317// implement UnmarshalerJSONArray
318func (a *testArray) UnmarshalJSONArray(dec *Decoder) error {
319	var str string
320	if err := dec.String(&str); err != nil {
321		return err
322	}
323	a[dec.Index()] = str
324	return nil
325}
326
327func main() {
328	dec := gojay.BorrowDecoder(strings.NewReader(`["Tom", "Jim", "Bob"]`))
329	var a testArray
330	err := dec.DecodeArray(&a)
331	fmt.Println(a) // [Tom Jim Bob]
332	dec.Release()
333}
334```
335
336### Other types
337To decode other types (string, int, int32, int64, uint32, uint64, float, booleans), you don't need to implement any interface.
338
339Example of encoding strings:
340```go
341func main() {
342    json := []byte(`"Jay"`)
343    var v string
344    err := gojay.Unmarshal(json, &v)
345    if err != nil {
346        log.Fatal(err)
347    }
348    fmt.Println(v) // Jay
349}
350```
351
352### Decode values methods
353When decoding a JSON object of a JSON array using `UnmarshalerJSONObject` or `UnmarshalerJSONArray` interface, the `gojay.Decoder` provides dozens of methods to Decode multiple types.
354
355Non exhaustive list of methods available (to see all methods, check the godoc):
356```go
357dec.Int
358dec.Int8
359dec.Int16
360dec.Int32
361dec.Int64
362dec.Uint8
363dec.Uint16
364dec.Uint32
365dec.Uint64
366dec.String
367dec.Time
368dec.Bool
369dec.SQLNullString
370dec.SQLNullInt64
371```
372
373
374## Encoding
375
376Encoding is done through two different API similar to standard `encoding/json`:
377* [Marshal](#marshal-api)
378* [Encode](#encode-api)
379
380Example of basic structure encoding with Marshal:
381```go
382import "github.com/francoispqt/gojay"
383
384type user struct {
385	id    int
386	name  string
387	email string
388}
389
390// implement MarshalerJSONObject
391func (u *user) MarshalJSONObject(enc *gojay.Encoder) {
392	enc.IntKey("id", u.id)
393	enc.StringKey("name", u.name)
394	enc.StringKey("email", u.email)
395}
396func (u *user) IsNil() bool {
397	return u == nil
398}
399
400func main() {
401	u := &user{1, "gojay", "gojay@email.com"}
402	b, err := gojay.MarshalJSONObject(u)
403	if err != nil {
404		log.Fatal(err)
405	}
406	fmt.Println(string(b)) // {"id":1,"name":"gojay","email":"gojay@email.com"}
407}
408```
409
410with Encode:
411```go
412func main() {
413	u := &user{1, "gojay", "gojay@email.com"}
414	b := strings.Builder{}
415	enc := gojay.NewEncoder(&b)
416	if err := enc.Encode(u); err != nil {
417		log.Fatal(err)
418	}
419	fmt.Println(b.String()) // {"id":1,"name":"gojay","email":"gojay@email.com"}
420}
421```
422
423### Marshal API
424
425Marshal API encodes a value to a JSON `[]byte` with a single function.
426
427Behind the doors, Marshal API borrows a `*gojay.Encoder` resets its settings and encodes the data to an internal byte buffer and releases the `*gojay.Encoder` to the pool when it finishes, whether it encounters an error or not.
428
429If it cannot find the right Encoding strategy for the type of the given value, it returns an `InvalidMarshalError`. You can test the error returned by doing `if ok := err.(InvalidMarshalError); ok {}`.
430
431Marshal API comes with three functions:
432* Marshal
433```go
434func Marshal(v interface{}) ([]byte, error)
435```
436
437* MarshalJSONObject
438```go
439func MarshalJSONObject(v gojay.MarshalerJSONObject) ([]byte, error)
440```
441
442* MarshalJSONArray
443```go
444func MarshalJSONArray(v gojay.MarshalerJSONArray) ([]byte, error)
445```
446
447### Encode API
448
449Encode API decodes a value to JSON by creating or borrowing a `*gojay.Encoder` sending it to an `io.Writer` and calling `Encode` methods.
450
451__Getting a *gojay.Encoder or Borrowing__
452
453You can either get a fresh `*gojay.Encoder` calling `enc := gojay.NewEncoder(io.Writer)` or borrow one from the pool by calling `enc := gojay.BorrowEncoder(io.Writer)`.
454
455After using an encoder, you can release it by calling `enc.Release()`. Beware, if you reuse the encoder after releasing it, it will panic with an error of type `InvalidUsagePooledEncoderError`. If you want to fully benefit from the pooling, you must release your encoders after using.
456
457Example getting a fresh encoder an releasing:
458```go
459str := "test"
460b := strings.Builder{}
461enc := gojay.NewEncoder(&b)
462defer enc.Release()
463if err := enc.Encode(str); err != nil {
464    log.Fatal(err)
465}
466```
467Example borrowing an encoder and releasing:
468```go
469str := "test"
470b := strings.Builder{}
471enc := gojay.BorrowEncoder(b)
472defer enc.Release()
473if err := enc.Encode(str); err != nil {
474    log.Fatal(err)
475}
476```
477
478`*gojay.Encoder` has multiple methods to encoder specific types to JSON:
479* Encode
480```go
481func (enc *gojay.Encoder) Encode(v interface{}) error
482```
483* EncodeObject
484```go
485func (enc *gojay.Encoder) EncodeObject(v gojay.MarshalerJSONObject) error
486```
487* EncodeArray
488```go
489func (enc *gojay.Encoder) EncodeArray(v gojay.MarshalerJSONArray) error
490```
491* EncodeInt
492```go
493func (enc *gojay.Encoder) EncodeInt(n int) error
494```
495* EncodeInt64
496```go
497func (enc *gojay.Encoder) EncodeInt64(n int64) error
498```
499* EncodeFloat
500```go
501func (enc *gojay.Encoder) EncodeFloat(n float64) error
502```
503* EncodeBool
504```go
505func (enc *gojay.Encoder) EncodeBool(v bool) error
506```
507* EncodeString
508```go
509func (enc *gojay.Encoder) EncodeString(s string) error
510```
511
512### Structs and Maps
513
514To encode a structure, the structure must implement the MarshalerJSONObject interface:
515```go
516type MarshalerJSONObject interface {
517	MarshalJSONObject(enc *gojay.Encoder)
518	IsNil() bool
519}
520```
521`MarshalJSONObject` method takes one argument, a pointer to the Encoder (*gojay.Encoder). The method must add all the keys in the JSON Object by calling Decoder's methods.
522
523IsNil method returns a boolean indicating if the interface underlying value is nil or not. It is used to safely ensure that the underlying value is not nil without using Reflection.
524
525Example of implementation for a struct:
526```go
527type user struct {
528	id    int
529	name  string
530	email string
531}
532
533// implement MarshalerJSONObject
534func (u *user) MarshalJSONObject(enc *gojay.Encoder) {
535	enc.IntKey("id", u.id)
536	enc.StringKey("name", u.name)
537	enc.StringKey("email", u.email)
538}
539func (u *user) IsNil() bool {
540	return u == nil
541}
542```
543
544Example of implementation for a `map[string]string`:
545```go
546// define our custom map type implementing MarshalerJSONObject
547type message map[string]string
548
549// Implementing Marshaler
550func (m message) MarshalJSONObject(enc *gojay.Encoder) {
551	for k, v := range m {
552		enc.StringKey(k, v)
553	}
554}
555
556func (m message) IsNil() bool {
557	return m == nil
558}
559```
560
561### Arrays and Slices
562To encode an array or a slice, the slice/array must implement the MarshalerJSONArray interface:
563```go
564type MarshalerJSONArray interface {
565	MarshalJSONArray(enc *gojay.Encoder)
566	IsNil() bool
567}
568```
569`MarshalJSONArray` method takes one argument, a pointer to the Encoder (*gojay.Encoder). The method must add all element in the JSON Array by calling Decoder's methods.
570
571`IsNil` method returns a boolean indicating if the interface underlying value is nil(empty) or not. It is used to safely ensure that the underlying value is not nil without using Reflection and also to in `OmitEmpty` feature.
572
573Example of implementation:
574```go
575type users []*user
576// implement MarshalerJSONArray
577func (u *users) MarshalJSONArray(enc *gojay.Encoder) {
578	for _, e := range u {
579		enc.Object(e)
580	}
581}
582func (u *users) IsNil() bool {
583	return len(u) == 0
584}
585```
586
587### Other types
588To encode other types (string, int, float, booleans), you don't need to implement any interface.
589
590Example of encoding strings:
591```go
592func main() {
593	name := "Jay"
594	b, err := gojay.Marshal(name)
595	if err != nil {
596		log.Fatal(err)
597	}
598	fmt.Println(string(b)) // "Jay"
599}
600```
601
602# Stream API
603
604### Stream Decoding
605GoJay ships with a powerful stream decoder.
606
607It allows to read continuously from an io.Reader stream and do JIT decoding writing unmarshalled JSON to a channel to allow async consuming.
608
609When using the Stream API, the Decoder implements context.Context to provide graceful cancellation.
610
611To decode a stream of JSON, you must call `gojay.Stream.DecodeStream` and pass it a `UnmarshalerStream` implementation.
612
613```go
614type UnmarshalerStream interface {
615	UnmarshalStream(*StreamDecoder) error
616}
617```
618
619Example of implementation of stream reading from a WebSocket connection:
620```go
621// implement UnmarshalerStream
622type ChannelStream chan *user
623
624func (c ChannelStream) UnmarshalStream(dec *gojay.StreamDecoder) error {
625	u := &user{}
626	if err := dec.Object(u); err != nil {
627		return err
628	}
629	c <- u
630	return nil
631}
632
633func main() {
634	// get our websocket connection
635	origin := "http://localhost/"
636	url := "ws://localhost:12345/ws"
637	ws, err := websocket.Dial(url, "", origin)
638	if err != nil {
639		log.Fatal(err)
640	}
641	// create our channel which will receive our objects
642	streamChan := ChannelStream(make(chan *user))
643	// borrow a decoder
644	dec := gojay.Stream.BorrowDecoder(ws)
645	// start decoding, it will block until a JSON message is decoded from the WebSocket
646	// or until Done channel is closed
647	go dec.DecodeStream(streamChan)
648	for {
649		select {
650		case v := <-streamChan:
651			// Got something from my websocket!
652			log.Println(v)
653		case <-dec.Done():
654			log.Println("finished reading from WebSocket")
655			os.Exit(0)
656		}
657	}
658}
659```
660
661### Stream Encoding
662GoJay ships with a powerful stream encoder part of the Stream API.
663
664It allows to write continuously to an io.Writer and do JIT encoding of data fed to a channel to allow async consuming. You can set multiple consumers on the channel to be as performant as possible. Consumers are non blocking and are scheduled individually in their own go routine.
665
666When using the Stream API, the Encoder implements context.Context to provide graceful cancellation.
667
668To encode a stream of data, you must call `EncodeStream` and pass it a `MarshalerStream` implementation.
669
670```go
671type MarshalerStream interface {
672	MarshalStream(enc *gojay.StreamEncoder)
673}
674```
675
676Example of implementation of stream writing to a WebSocket:
677```go
678// Our structure which will be pushed to our stream
679type user struct {
680	id    int
681	name  string
682	email string
683}
684
685func (u *user) MarshalJSONObject(enc *gojay.Encoder) {
686	enc.IntKey("id", u.id)
687	enc.StringKey("name", u.name)
688	enc.StringKey("email", u.email)
689}
690func (u *user) IsNil() bool {
691	return u == nil
692}
693
694// Our MarshalerStream implementation
695type StreamChan chan *user
696
697func (s StreamChan) MarshalStream(enc *gojay.StreamEncoder) {
698	select {
699	case <-enc.Done():
700		return
701	case o := <-s:
702		enc.Object(o)
703	}
704}
705
706// Our main function
707func main() {
708	// get our websocket connection
709	origin := "http://localhost/"
710	url := "ws://localhost:12345/ws"
711	ws, err := websocket.Dial(url, "", origin)
712	if err != nil {
713		log.Fatal(err)
714	}
715	// we borrow an encoder set stdout as the writer,
716	// set the number of consumer to 10
717	// and tell the encoder to separate each encoded element
718	// added to the channel by a new line character
719	enc := gojay.Stream.BorrowEncoder(ws).NConsumer(10).LineDelimited()
720	// instantiate our MarshalerStream
721	s := StreamChan(make(chan *user))
722	// start the stream encoder
723	// will block its goroutine until enc.Cancel(error) is called
724	// or until something is written to the channel
725	go enc.EncodeStream(s)
726	// write to our MarshalerStream
727	for i := 0; i < 1000; i++ {
728		s <- &user{i, "username", "user@email.com"}
729	}
730	// Wait
731	<-enc.Done()
732}
733```
734
735# Unsafe API
736
737Unsafe API has the same functions than the regular API, it only has `Unmarshal API` for now. It is unsafe because it makes assumptions on the quality of the given JSON.
738
739If you are not sure if your JSON is valid, don't use the Unsafe API.
740
741Also, the `Unsafe` API does not copy the buffer when using Unmarshal API, which, in case of string decoding, can lead to data corruption if a byte buffer is reused. Using the `Decode` API makes `Unsafe` API safer as the io.Reader relies on `copy` builtin method and `Decoder` will have its own internal buffer :)
742
743Access the `Unsafe` API this way:
744```go
745gojay.Unsafe.Unmarshal(b, v)
746```
747
748
749# Benchmarks
750
751Benchmarks encode and decode three different data based on size (small, medium, large).
752
753To run benchmark for decoder:
754```bash
755cd $GOPATH/src/github.com/francoispqt/gojay/benchmarks/decoder && make bench
756```
757
758To run benchmark for encoder:
759```bash
760cd $GOPATH/src/github.com/francoispqt/gojay/benchmarks/encoder && make bench
761```
762
763# Benchmark Results
764## Decode
765
766<img src="https://images2.imgbox.com/78/01/49OExcPh_o.png" width="500px">
767
768### Small Payload
769[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/decoder/decoder_bench_small_test.go)
770
771[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_small.go)
772
773|                 | ns/op     | bytes/op     | allocs/op |
774|-----------------|-----------|--------------|-----------|
775| Std Library     | 2547      | 496          | 4         |
776| JsonIter        | 2046      | 312          | 12        |
777| JsonParser      | 1408      | 0            | 0         |
778| EasyJson        | 929       | 240          | 2         |
779| **GoJay**       | **807**   | **256**      | **2**     |
780| **GoJay-unsafe**| **712**   | **112**      | **1**     |
781
782### Medium Payload
783[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/decoder/decoder_bench_medium_test.go)
784
785[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_medium.go)
786
787|                 | ns/op     | bytes/op | allocs/op |
788|-----------------|-----------|----------|-----------|
789| Std Library     | 30148     | 2152     | 496       |
790| JsonIter        | 16309     | 2976     | 80        |
791| JsonParser      | 7793      | 0        | 0         |
792| EasyJson        | 7957      | 232      | 6         |
793| **GoJay**       | **4984**  | **2448** | **8**     |
794| **GoJay-unsafe**| **4809**  | **144**  | **7**     |
795
796### Large Payload
797[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/decoder/decoder_bench_large_test.go)
798
799[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_large.go)
800
801|                 | ns/op     | bytes/op    | allocs/op |
802|-----------------|-----------|-------------|-----------|
803| JsonIter        | 210078    | 41712       | 1136      |
804| EasyJson        | 106626    | 160         | 2         |
805| JsonParser      | 66813     | 0           | 0         |
806| **GoJay**       | **52153** | **31241**   | **77**    |
807| **GoJay-unsafe**| **48277** | **2561**    | **76**    |
808
809## Encode
810
811<img src="https://images2.imgbox.com/e9/cc/pnM8c7Gf_o.png" width="500px">
812
813### Small Struct
814[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/encoder/encoder_bench_small_test.go)
815
816[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_small.go)
817
818|                | ns/op    | bytes/op     | allocs/op |
819|----------------|----------|--------------|-----------|
820| Std Library    | 1280     | 464          | 3         |
821| EasyJson       | 871      | 944          | 6         |
822| JsonIter       | 866      | 272          | 3         |
823| **GoJay**      | **543**  | **112**      | **1**     |
824| **GoJay-func** | **347**  | **0**        | **0**     |
825
826### Medium Struct
827[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/encoder/encoder_bench_medium_test.go)
828
829[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_medium.go)
830
831|             | ns/op    | bytes/op     | allocs/op |
832|-------------|----------|--------------|-----------|
833| Std Library | 5006     | 1496         | 25        |
834| JsonIter    | 2232     | 1544         | 20        |
835| EasyJson    | 1997     | 1544         | 19        |
836| **GoJay**   | **1522** | **312**      | **14**    |
837
838### Large Struct
839[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/encoder/encoder_bench_large_test.go)
840
841[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_large.go)
842
843|             | ns/op     | bytes/op     | allocs/op |
844|-------------|-----------|--------------|-----------|
845| Std Library | 66441     | 20576        | 332       |
846| JsonIter    | 35247     | 20255        | 328       |
847| EasyJson    | 32053     | 15474        | 327       |
848| **GoJay**   | **27847** | **9802**     | **318**   |
849
850# Contributing
851
852Contributions are welcome :)
853
854If you encounter issues please report it in Github and/or send an email at [francois@parquet.ninja](mailto:francois@parquet.ninja)
855
856