gojay

high performance JSON encoder/decoder with stream API for Golang
git clone git://git.lair.cx/gojay
Log | Files | Refs | README | LICENSE

README.md (25340B)


      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 
     14 GoJay is a performant JSON encoder/decoder for Golang (currently the most performant, [see benchmarks](#benchmark-results)).
     15 
     16 It has a simple API and doesn't use reflection. It relies on small interfaces to decode/encode structures and slices.
     17 
     18 Gojay also comes with powerful stream decoding features and an even faster [Unsafe](#unsafe-api) API.
     19 
     20 There 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 
     24 I 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 
     26 Also, 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 
     28 This 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
     33 go 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 
     43 Decoding is done through two different API similar to standard `encoding/json`:
     44 * [Unmarshal](#unmarshal-api)
     45 * [Decode](#decode-api)
     46 
     47 
     48 Example of basic stucture decoding with Unmarshal:
     49 ```go
     50 import "go.lair.cx/gojay"
     51 
     52 type user struct {
     53     id int
     54     name string
     55     email string
     56 }
     57 // implement gojay.UnmarshalerJSONObject
     58 func (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 }
     69 func (u *user) NKeys() int {
     70     return 3
     71 }
     72 
     73 func 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 
     83 with Decode:
     84 ```go
     85 func 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 
     97 Unmarshal API decodes a `[]byte` to a given pointer with a single function.
     98 
     99 Behind 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 
    101 If 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 
    103 Unmarshal API comes with three functions:
    104 * Unmarshal
    105 ```go
    106 func Unmarshal(data []byte, v interface{}) error
    107 ```
    108 
    109 * UnmarshalJSONObject
    110 ```go
    111 func UnmarshalJSONObject(data []byte, v gojay.UnmarshalerJSONObject) error
    112 ```
    113 
    114 * UnmarshalJSONArray
    115 ```go
    116 func UnmarshalJSONArray(data []byte, v gojay.UnmarshalerJSONArray) error
    117 ```
    118 
    119 
    120 ### Decode API
    121 
    122 Decode 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 
    126 You 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 
    128 After 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 
    130 Example getting a fresh an releasing:
    131 ```go
    132 str := ""
    133 dec := gojay.NewDecoder(strings.NewReader(`"test"`))
    134 defer dec.Release()
    135 if err := dec.Decode(&str); err != nil {
    136     log.Fatal(err)
    137 }
    138 ```
    139 Example borrowing a decoder and releasing:
    140 ```go
    141 str := ""
    142 dec := gojay.BorrowDecoder(strings.NewReader(`"test"`))
    143 defer dec.Release()
    144 if 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
    152 func (dec *gojay.Decoder) Decode(v interface{}) error
    153 ```
    154 * DecodeObject
    155 ```go
    156 func (dec *gojay.Decoder) DecodeObject(v gojay.UnmarshalerJSONObject) error
    157 ```
    158 * DecodeArray
    159 ```go
    160 func (dec *gojay.Decoder) DecodeArray(v gojay.UnmarshalerJSONArray) error
    161 ```
    162 * DecodeInt
    163 ```go
    164 func (dec *gojay.Decoder) DecodeInt(v *int) error
    165 ```
    166 * DecodeBool
    167 ```go
    168 func (dec *gojay.Decoder) DecodeBool(v *bool) error
    169 ```
    170 * DecodeString
    171 ```go
    172 func (dec *gojay.Decoder) DecodeString(v *string) error
    173 ```
    174 
    175 All 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 
    177 Example:
    178 ```go
    179 reader := strings.NewReader(`"John Doe"`)
    180 dec := NewDecoder(reader)
    181 
    182 var str string
    183 err := dec.DecodeString(&str)
    184 if err != nil {
    185     log.Fatal(err)
    186 }
    187 
    188 fmt.Println(str) // John Doe
    189 ```
    190 
    191 ### Structs and Maps
    192 #### UnmarshalerJSONObject Interface
    193 
    194 To unmarshal a JSON object to a structure, the structure must implement the `UnmarshalerJSONObject` interface:
    195 ```go
    196 type 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 
    205 Example of implementation for a struct:
    206 ```go
    207 type user struct {
    208     id int
    209     name string
    210     email string
    211 }
    212 // implement UnmarshalerJSONObject
    213 func (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 }
    224 func (u *user) NKeys() int {
    225     return 3
    226 }
    227 ```
    228 
    229 Example of implementation for a `map[string]string`:
    230 ```go
    231 // define our custom map type implementing UnmarshalerJSONObject
    232 type message map[string]string
    233 
    234 // Implementing Unmarshaler
    235 func (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
    246 func (m message) NKeys() int {
    247 	return 0
    248 }
    249 ```
    250 
    251 ### Arrays, Slices and Channels
    252 
    253 To unmarshal a JSON object to a slice an array or a channel, it must implement the UnmarshalerJSONArray interface:
    254 ```go
    255 type UnmarshalerJSONArray interface {
    256 	UnmarshalJSONArray(*gojay.Decoder) error
    257 }
    258 ```
    259 UnmarshalJSONArray 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 
    261 Example of implementation with a slice:
    262 ```go
    263 type testSlice []string
    264 // implement UnmarshalerJSONArray
    265 func (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 
    274 func 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 
    286 Example of implementation with a channel:
    287 ```go
    288 type testChannel chan string
    289 // implement UnmarshalerJSONArray
    290 func (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 
    299 func 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 
    314 Example of implementation with an array:
    315 ```go
    316 type testArray [3]string
    317 // implement UnmarshalerJSONArray
    318 func (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 
    327 func 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
    337 To decode other types (string, int, int32, int64, uint32, uint64, float, booleans), you don't need to implement any interface.
    338 
    339 Example of encoding strings:
    340 ```go
    341 func 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
    353 When 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 
    355 Non exhaustive list of methods available (to see all methods, check the godoc):
    356 ```go
    357 dec.Int
    358 dec.Int8
    359 dec.Int16
    360 dec.Int32
    361 dec.Int64
    362 dec.Uint8
    363 dec.Uint16
    364 dec.Uint32
    365 dec.Uint64
    366 dec.String
    367 dec.Time
    368 dec.Bool
    369 dec.SQLNullString
    370 dec.SQLNullInt64
    371 ```
    372 
    373 
    374 ## Encoding
    375 
    376 Encoding is done through two different API similar to standard `encoding/json`:
    377 * [Marshal](#marshal-api)
    378 * [Encode](#encode-api)
    379 
    380 Example of basic structure encoding with Marshal:
    381 ```go
    382 import "go.lair.cx/gojay"
    383 
    384 type user struct {
    385 	id    int
    386 	name  string
    387 	email string
    388 }
    389 
    390 // implement MarshalerJSONObject
    391 func (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 }
    396 func (u *user) IsNil() bool {
    397 	return u == nil
    398 }
    399 
    400 func 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 
    410 with Encode:
    411 ```go
    412 func 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 
    425 Marshal API encodes a value to a JSON `[]byte` with a single function.
    426 
    427 Behind 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 
    429 If 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 
    431 Marshal API comes with three functions:
    432 * Marshal
    433 ```go
    434 func Marshal(v interface{}) ([]byte, error)
    435 ```
    436 
    437 * MarshalJSONObject
    438 ```go
    439 func MarshalJSONObject(v gojay.MarshalerJSONObject) ([]byte, error)
    440 ```
    441 
    442 * MarshalJSONArray
    443 ```go
    444 func MarshalJSONArray(v gojay.MarshalerJSONArray) ([]byte, error)
    445 ```
    446 
    447 ### Encode API
    448 
    449 Encode 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 
    453 You 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 
    455 After 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 
    457 Example getting a fresh encoder an releasing:
    458 ```go
    459 str := "test"
    460 b := strings.Builder{}
    461 enc := gojay.NewEncoder(&b)
    462 defer enc.Release()
    463 if err := enc.Encode(str); err != nil {
    464     log.Fatal(err)
    465 }
    466 ```
    467 Example borrowing an encoder and releasing:
    468 ```go
    469 str := "test"
    470 b := strings.Builder{}
    471 enc := gojay.BorrowEncoder(b)
    472 defer enc.Release()
    473 if 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
    481 func (enc *gojay.Encoder) Encode(v interface{}) error
    482 ```
    483 * EncodeObject
    484 ```go
    485 func (enc *gojay.Encoder) EncodeObject(v gojay.MarshalerJSONObject) error
    486 ```
    487 * EncodeArray
    488 ```go
    489 func (enc *gojay.Encoder) EncodeArray(v gojay.MarshalerJSONArray) error
    490 ```
    491 * EncodeInt
    492 ```go
    493 func (enc *gojay.Encoder) EncodeInt(n int) error
    494 ```
    495 * EncodeInt64
    496 ```go
    497 func (enc *gojay.Encoder) EncodeInt64(n int64) error
    498 ```
    499 * EncodeFloat
    500 ```go
    501 func (enc *gojay.Encoder) EncodeFloat(n float64) error
    502 ```
    503 * EncodeBool
    504 ```go
    505 func (enc *gojay.Encoder) EncodeBool(v bool) error
    506 ```
    507 * EncodeString
    508 ```go
    509 func (enc *gojay.Encoder) EncodeString(s string) error
    510 ```
    511 
    512 ### Structs and Maps
    513 
    514 To encode a structure, the structure must implement the MarshalerJSONObject interface:
    515 ```go
    516 type 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 
    523 IsNil 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 
    525 Example of implementation for a struct:
    526 ```go
    527 type user struct {
    528 	id    int
    529 	name  string
    530 	email string
    531 }
    532 
    533 // implement MarshalerJSONObject
    534 func (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 }
    539 func (u *user) IsNil() bool {
    540 	return u == nil
    541 }
    542 ```
    543 
    544 Example of implementation for a `map[string]string`:
    545 ```go
    546 // define our custom map type implementing MarshalerJSONObject
    547 type message map[string]string
    548 
    549 // Implementing Marshaler
    550 func (m message) MarshalJSONObject(enc *gojay.Encoder) {
    551 	for k, v := range m {
    552 		enc.StringKey(k, v)
    553 	}
    554 }
    555 
    556 func (m message) IsNil() bool {
    557 	return m == nil
    558 }
    559 ```
    560 
    561 ### Arrays and Slices
    562 To encode an array or a slice, the slice/array must implement the MarshalerJSONArray interface:
    563 ```go
    564 type 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 
    573 Example of implementation:
    574 ```go
    575 type users []*user
    576 // implement MarshalerJSONArray
    577 func (u *users) MarshalJSONArray(enc *gojay.Encoder) {
    578 	for _, e := range u {
    579 		enc.Object(e)
    580 	}
    581 }
    582 func (u *users) IsNil() bool {
    583 	return len(u) == 0
    584 }
    585 ```
    586 
    587 ### Other types
    588 To encode other types (string, int, float, booleans), you don't need to implement any interface.
    589 
    590 Example of encoding strings:
    591 ```go
    592 func 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
    605 GoJay ships with a powerful stream decoder.
    606 
    607 It allows to read continuously from an io.Reader stream and do JIT decoding writing unmarshalled JSON to a channel to allow async consuming.
    608 
    609 When using the Stream API, the Decoder implements context.Context to provide graceful cancellation.
    610 
    611 To decode a stream of JSON, you must call `gojay.Stream.DecodeStream` and pass it a `UnmarshalerStream` implementation.
    612 
    613 ```go
    614 type UnmarshalerStream interface {
    615 	UnmarshalStream(*StreamDecoder) error
    616 }
    617 ```
    618 
    619 Example of implementation of stream reading from a WebSocket connection:
    620 ```go
    621 // implement UnmarshalerStream
    622 type ChannelStream chan *user
    623 
    624 func (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 
    633 func 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
    662 GoJay ships with a powerful stream encoder part of the Stream API.
    663 
    664 It 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 
    666 When using the Stream API, the Encoder implements context.Context to provide graceful cancellation.
    667 
    668 To encode a stream of data, you must call `EncodeStream` and pass it a `MarshalerStream` implementation.
    669 
    670 ```go
    671 type MarshalerStream interface {
    672 	MarshalStream(enc *gojay.StreamEncoder)
    673 }
    674 ```
    675 
    676 Example of implementation of stream writing to a WebSocket:
    677 ```go
    678 // Our structure which will be pushed to our stream
    679 type user struct {
    680 	id    int
    681 	name  string
    682 	email string
    683 }
    684 
    685 func (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 }
    690 func (u *user) IsNil() bool {
    691 	return u == nil
    692 }
    693 
    694 // Our MarshalerStream implementation
    695 type StreamChan chan *user
    696 
    697 func (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
    707 func 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 
    737 Unsafe 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 
    739 If you are not sure if your JSON is valid, don't use the Unsafe API.
    740 
    741 Also, 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 
    743 Access the `Unsafe` API this way:
    744 ```go
    745 gojay.Unsafe.Unmarshal(b, v)
    746 ```
    747 
    748 
    749 # Benchmarks
    750 
    751 Benchmarks encode and decode three different data based on size (small, medium, large).
    752 
    753 To run benchmark for decoder:
    754 ```bash
    755 cd $GOPATH/src/github.com/francoispqt/gojay/benchmarks/decoder && make bench
    756 ```
    757 
    758 To run benchmark for encoder:
    759 ```bash
    760 cd $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 
    852 Contributions are welcome :)
    853 
    854 If you encounter issues please report it in Github and/or send an email at [francois@parquet.ninja](mailto:francois@parquet.ninja)
    855