pax_global_header 0000666 0000000 0000000 00000000064 13653316651 0014523 g ustar 00root root 0000000 0000000 52 comment=6f16c3286d326c3ebe67ffa7f1be77eb187212cb
golang-github-francoispqt-gojay-1.2.13/ 0000775 0000000 0000000 00000000000 13653316651 0017774 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/.gitignore 0000664 0000000 0000000 00000000042 13653316651 0021760 0 ustar 00root root 0000000 0000000 vendor
*.out
*.log
*.test
.vscode
golang-github-francoispqt-gojay-1.2.13/.travis.yml 0000664 0000000 0000000 00000000514 13653316651 0022105 0 ustar 00root root 0000000 0000000 language: go
go:
- "1.10.x"
- "1.11.x"
- "1.12.x"
script:
- go get github.com/golang/dep/cmd/dep github.com/stretchr/testify
- dep ensure -v -vendor-only
- go test ./gojay/codegen/test/... -race
- go test -race -coverprofile=coverage.txt -covermode=atomic
after_success:
- bash <(curl -s https://codecov.io/bash)
golang-github-francoispqt-gojay-1.2.13/Gopkg.lock 0000664 0000000 0000000 00000010243 13653316651 0021715 0 ustar 00root root 0000000 0000000 # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:1a37f9f2ae10d161d9688fb6008ffa14e1631e5068cc3e9698008b9e8d40d575"
name = "cloud.google.com/go"
packages = ["compute/metadata"]
pruneopts = ""
revision = "457ea5c15ccf3b87db582c450e80101989da35f7"
version = "v0.40.0"
[[projects]]
digest = "1:968d8903d598e3fae738325d3410f33f07ea6a2b9ee5591e9c262ee37df6845a"
name = "github.com/go-errors/errors"
packages = ["."]
pruneopts = ""
revision = "a6af135bd4e28680facf08a3d206b454abc877a4"
version = "v1.0.1"
[[projects]]
digest = "1:529d738b7976c3848cae5cf3a8036440166835e389c1f617af701eeb12a0518d"
name = "github.com/golang/protobuf"
packages = ["proto"]
pruneopts = ""
revision = "b5d812f8a3706043e23a9cd5babf2e5423744d30"
version = "v1.3.1"
[[projects]]
branch = "master"
digest = "1:cae59d7b8243c671c9f544965522ba35c0fec48ee80adb9f1400cd2f33abbbec"
name = "github.com/mailru/easyjson"
packages = [
".",
"buffer",
"jlexer",
"jwriter",
]
pruneopts = ""
revision = "1ea4449da9834f4d333f1cc461c374aea217d249"
[[projects]]
digest = "1:1d7e1867c49a6dd9856598ef7c3123604ea3daabf5b83f303ff457bcbc410b1d"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = ""
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
version = "v0.8.1"
[[projects]]
digest = "1:8d4bbd8ab012efc77ab6b97286f2aff262bcdeac9803bb57d75cf7d0a5e6a877"
name = "github.com/viant/assertly"
packages = ["."]
pruneopts = ""
revision = "04f45e0aeb6f3455884877b047a97bcc95dc9493"
version = "v0.4.8"
[[projects]]
digest = "1:5913451bc2d274673c0716efe226a137625740cd9380641f4d8300ff4f2d82a0"
name = "github.com/viant/toolbox"
packages = [
".",
"cred",
"data",
"storage",
"url",
]
pruneopts = ""
revision = "1be8e4d172138324f40d55ea61a2aeab0c5ce864"
version = "v0.24.0"
[[projects]]
branch = "master"
digest = "1:9d150270ca2c3356f2224a0878daa1652e4d0b25b345f18b4f6e156cc4b8ec5e"
name = "golang.org/x/crypto"
packages = [
"blowfish",
"curve25519",
"ed25519",
"ed25519/internal/edwards25519",
"internal/chacha20",
"internal/subtle",
"poly1305",
"ssh",
]
pruneopts = ""
revision = "f99c8df09eb5bff426315721bfa5f16a99cad32c"
[[projects]]
branch = "master"
digest = "1:5a56f211e7c12a65c5585c629457a2fb91d8719844ee8fab92727ea8adb5721c"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"websocket",
]
pruneopts = ""
revision = "461777fb6f67e8cb9d70cda16573678d085a74cf"
[[projects]]
branch = "master"
digest = "1:01bdbbc604dcd5afb6f66a717f69ad45e9643c72d5bc11678d44ffa5c50f9e42"
name = "golang.org/x/oauth2"
packages = [
".",
"google",
"internal",
"jws",
"jwt",
]
pruneopts = ""
revision = "0f29369cfe4552d0e4bcddc57cc75f4d7e672a33"
[[projects]]
branch = "master"
digest = "1:8ddb956f67d4c176abbbc42b7514aaeaf9ea30daa24e27d2cf30ad82f9334a2c"
name = "golang.org/x/sys"
packages = ["cpu"]
pruneopts = ""
revision = "1e42afee0f762ed3d76e6dd942e4181855fd1849"
[[projects]]
digest = "1:47f391ee443f578f01168347818cb234ed819521e49e4d2c8dd2fb80d48ee41a"
name = "google.golang.org/appengine"
packages = [
".",
"internal",
"internal/app_identity",
"internal/base",
"internal/datastore",
"internal/log",
"internal/modules",
"internal/remote_api",
"internal/urlfetch",
"urlfetch",
]
pruneopts = ""
revision = "b2f4a3cf3c67576a2ee09e1fe62656a5086ce880"
version = "v1.6.1"
[[projects]]
digest = "1:cedccf16b71e86db87a24f8d4c70b0a855872eb967cb906a66b95de56aefbd0d"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = ""
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
version = "v2.2.2"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/go-errors/errors",
"github.com/mailru/easyjson",
"github.com/mailru/easyjson/jlexer",
"github.com/mailru/easyjson/jwriter",
"github.com/viant/assertly",
"github.com/viant/toolbox",
"github.com/viant/toolbox/url",
"golang.org/x/net/websocket",
]
solver-name = "gps-cdcl"
solver-version = 1
golang-github-francoispqt-gojay-1.2.13/Gopkg.toml 0000664 0000000 0000000 00000001301 13653316651 0021733 0 ustar 00root root 0000000 0000000 # Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
ignored = ["github.com/francoispqt/benchmarks*","github.com/stretchr/testify*","github.com/stretchr/testify","github.com/json-iterator/go","github.com/buger/jsonparser"]
golang-github-francoispqt-gojay-1.2.13/LICENSE 0000664 0000000 0000000 00000002045 13653316651 0021002 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2016 gojay
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. golang-github-francoispqt-gojay-1.2.13/Makefile 0000664 0000000 0000000 00000000275 13653316651 0021440 0 ustar 00root root 0000000 0000000 .PHONY: test
test:
go test -race -run=^Test -v
.PHONY: cover
cover:
go test -coverprofile=coverage.out -covermode=atomic
.PHONY: coverhtml
coverhtml:
go tool cover -html=coverage.out golang-github-francoispqt-gojay-1.2.13/README.md 0000664 0000000 0000000 00000061424 13653316651 0021262 0 ustar 00root root 0000000 0000000 [](https://travis-ci.org/francoispqt/gojay)
[](https://codecov.io/gh/francoispqt/gojay)
[](https://goreportcard.com/report/github.com/francoispqt/gojay)
[](https://godoc.org/github.com/francoispqt/gojay)

[](https://sourcegraph.com/github.com/francoispqt/gojay)

# GoJay
GoJay is a performant JSON encoder/decoder for Golang (currently the most performant, [see benchmarks](#benchmark-results)).
It has a simple API and doesn't use reflection. It relies on small interfaces to decode/encode structures and slices.
Gojay also comes with powerful stream decoding features and an even faster [Unsafe](#unsafe-api) API.
There is also a [code generation tool](https://github.com/francoispqt/gojay/tree/master/gojay) to make usage easier and faster.
# Why another JSON parser?
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.
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.
This is how GoJay aims to be a very fast, JIT stream parser with 0 reflection, low allocation with a friendly API.
# Get started
```bash
go get github.com/francoispqt/gojay
```
* [Encoder](#encoding)
* [Decoder](#decoding)
* [Stream API](#stream-api)
* [Code Generation](https://github.com/francoispqt/gojay/tree/master/gojay)
## Decoding
Decoding is done through two different API similar to standard `encoding/json`:
* [Unmarshal](#unmarshal-api)
* [Decode](#decode-api)
Example of basic stucture decoding with Unmarshal:
```go
import "github.com/francoispqt/gojay"
type user struct {
id int
name string
email string
}
// implement gojay.UnmarshalerJSONObject
func (u *user) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "id":
return dec.Int(&u.id)
case "name":
return dec.String(&u.name)
case "email":
return dec.String(&u.email)
}
return nil
}
func (u *user) NKeys() int {
return 3
}
func main() {
u := &user{}
d := []byte(`{"id":1,"name":"gojay","email":"gojay@email.com"}`)
err := gojay.UnmarshalJSONObject(d, u)
if err != nil {
log.Fatal(err)
}
}
```
with Decode:
```go
func main() {
u := &user{}
dec := gojay.NewDecoder(bytes.NewReader([]byte(`{"id":1,"name":"gojay","email":"gojay@email.com"}`)))
err := dec.DecodeObject(d, u)
if err != nil {
log.Fatal(err)
}
}
```
### Unmarshal API
Unmarshal API decodes a `[]byte` to a given pointer with a single function.
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.
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 {}`.
Unmarshal API comes with three functions:
* Unmarshal
```go
func Unmarshal(data []byte, v interface{}) error
```
* UnmarshalJSONObject
```go
func UnmarshalJSONObject(data []byte, v gojay.UnmarshalerJSONObject) error
```
* UnmarshalJSONArray
```go
func UnmarshalJSONArray(data []byte, v gojay.UnmarshalerJSONArray) error
```
### Decode API
Decode API decodes a `[]byte` to a given pointer by creating or borrowing a `*gojay.Decoder` with an `io.Reader` and calling `Decode` methods.
__Getting a *gojay.Decoder or Borrowing__
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)`.
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.
Example getting a fresh an releasing:
```go
str := ""
dec := gojay.NewDecoder(strings.NewReader(`"test"`))
defer dec.Release()
if err := dec.Decode(&str); err != nil {
log.Fatal(err)
}
```
Example borrowing a decoder and releasing:
```go
str := ""
dec := gojay.BorrowDecoder(strings.NewReader(`"test"`))
defer dec.Release()
if err := dec.Decode(&str); err != nil {
log.Fatal(err)
}
```
`*gojay.Decoder` has multiple methods to decode to specific types:
* Decode
```go
func (dec *gojay.Decoder) Decode(v interface{}) error
```
* DecodeObject
```go
func (dec *gojay.Decoder) DecodeObject(v gojay.UnmarshalerJSONObject) error
```
* DecodeArray
```go
func (dec *gojay.Decoder) DecodeArray(v gojay.UnmarshalerJSONArray) error
```
* DecodeInt
```go
func (dec *gojay.Decoder) DecodeInt(v *int) error
```
* DecodeBool
```go
func (dec *gojay.Decoder) DecodeBool(v *bool) error
```
* DecodeString
```go
func (dec *gojay.Decoder) DecodeString(v *string) error
```
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.
Example:
```go
reader := strings.NewReader(`"John Doe"`)
dec := NewDecoder(reader)
var str string
err := dec.DecodeString(&str)
if err != nil {
log.Fatal(err)
}
fmt.Println(str) // John Doe
```
### Structs and Maps
#### UnmarshalerJSONObject Interface
To unmarshal a JSON object to a structure, the structure must implement the `UnmarshalerJSONObject` interface:
```go
type UnmarshalerJSONObject interface {
UnmarshalJSONObject(*gojay.Decoder, string) error
NKeys() int
}
```
`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.
`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.
Example of implementation for a struct:
```go
type user struct {
id int
name string
email string
}
// implement UnmarshalerJSONObject
func (u *user) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "id":
return dec.Int(&u.id)
case "name":
return dec.String(&u.name)
case "email":
return dec.String(&u.email)
}
return nil
}
func (u *user) NKeys() int {
return 3
}
```
Example of implementation for a `map[string]string`:
```go
// define our custom map type implementing UnmarshalerJSONObject
type message map[string]string
// Implementing Unmarshaler
func (m message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
str := ""
err := dec.String(&str)
if err != nil {
return err
}
m[k] = str
return nil
}
// we return 0, it tells the Decoder to decode all keys
func (m message) NKeys() int {
return 0
}
```
### Arrays, Slices and Channels
To unmarshal a JSON object to a slice an array or a channel, it must implement the UnmarshalerJSONArray interface:
```go
type UnmarshalerJSONArray interface {
UnmarshalJSONArray(*gojay.Decoder) error
}
```
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.
Example of implementation with a slice:
```go
type testSlice []string
// implement UnmarshalerJSONArray
func (t *testSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
str := ""
if err := dec.String(&str); err != nil {
return err
}
*t = append(*t, str)
return nil
}
func main() {
dec := gojay.BorrowDecoder(strings.NewReader(`["Tom", "Jim"]`))
var slice testSlice
err := dec.DecodeArray(&slice)
if err != nil {
log.Fatal(err)
}
fmt.Println(slice) // [Tom Jim]
dec.Release()
}
```
Example of implementation with a channel:
```go
type testChannel chan string
// implement UnmarshalerJSONArray
func (c testChannel) UnmarshalJSONArray(dec *gojay.Decoder) error {
str := ""
if err := dec.String(&str); err != nil {
return err
}
c <- str
return nil
}
func main() {
dec := gojay.BorrowDecoder(strings.NewReader(`["Tom", "Jim"]`))
c := make(testChannel, 2)
err := dec.DecodeArray(c)
if err != nil {
log.Fatal(err)
}
for i := 0; i < 2; i++ {
fmt.Println(<-c)
}
close(c)
dec.Release()
}
```
Example of implementation with an array:
```go
type testArray [3]string
// implement UnmarshalerJSONArray
func (a *testArray) UnmarshalJSONArray(dec *Decoder) error {
var str string
if err := dec.String(&str); err != nil {
return err
}
a[dec.Index()] = str
return nil
}
func main() {
dec := gojay.BorrowDecoder(strings.NewReader(`["Tom", "Jim", "Bob"]`))
var a testArray
err := dec.DecodeArray(&a)
fmt.Println(a) // [Tom Jim Bob]
dec.Release()
}
```
### Other types
To decode other types (string, int, int32, int64, uint32, uint64, float, booleans), you don't need to implement any interface.
Example of encoding strings:
```go
func main() {
json := []byte(`"Jay"`)
var v string
err := gojay.Unmarshal(json, &v)
if err != nil {
log.Fatal(err)
}
fmt.Println(v) // Jay
}
```
### Decode values methods
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.
Non exhaustive list of methods available (to see all methods, check the godoc):
```go
dec.Int
dec.Int8
dec.Int16
dec.Int32
dec.Int64
dec.Uint8
dec.Uint16
dec.Uint32
dec.Uint64
dec.String
dec.Time
dec.Bool
dec.SQLNullString
dec.SQLNullInt64
```
## Encoding
Encoding is done through two different API similar to standard `encoding/json`:
* [Marshal](#marshal-api)
* [Encode](#encode-api)
Example of basic structure encoding with Marshal:
```go
import "github.com/francoispqt/gojay"
type user struct {
id int
name string
email string
}
// implement MarshalerJSONObject
func (u *user) MarshalJSONObject(enc *gojay.Encoder) {
enc.IntKey("id", u.id)
enc.StringKey("name", u.name)
enc.StringKey("email", u.email)
}
func (u *user) IsNil() bool {
return u == nil
}
func main() {
u := &user{1, "gojay", "gojay@email.com"}
b, err := gojay.MarshalJSONObject(u)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b)) // {"id":1,"name":"gojay","email":"gojay@email.com"}
}
```
with Encode:
```go
func main() {
u := &user{1, "gojay", "gojay@email.com"}
b := strings.Builder{}
enc := gojay.NewEncoder(&b)
if err := enc.Encode(u); err != nil {
log.Fatal(err)
}
fmt.Println(b.String()) // {"id":1,"name":"gojay","email":"gojay@email.com"}
}
```
### Marshal API
Marshal API encodes a value to a JSON `[]byte` with a single function.
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.
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 {}`.
Marshal API comes with three functions:
* Marshal
```go
func Marshal(v interface{}) ([]byte, error)
```
* MarshalJSONObject
```go
func MarshalJSONObject(v gojay.MarshalerJSONObject) ([]byte, error)
```
* MarshalJSONArray
```go
func MarshalJSONArray(v gojay.MarshalerJSONArray) ([]byte, error)
```
### Encode API
Encode API decodes a value to JSON by creating or borrowing a `*gojay.Encoder` sending it to an `io.Writer` and calling `Encode` methods.
__Getting a *gojay.Encoder or Borrowing__
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)`.
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.
Example getting a fresh encoder an releasing:
```go
str := "test"
b := strings.Builder{}
enc := gojay.NewEncoder(&b)
defer enc.Release()
if err := enc.Encode(str); err != nil {
log.Fatal(err)
}
```
Example borrowing an encoder and releasing:
```go
str := "test"
b := strings.Builder{}
enc := gojay.BorrowEncoder(b)
defer enc.Release()
if err := enc.Encode(str); err != nil {
log.Fatal(err)
}
```
`*gojay.Encoder` has multiple methods to encoder specific types to JSON:
* Encode
```go
func (enc *gojay.Encoder) Encode(v interface{}) error
```
* EncodeObject
```go
func (enc *gojay.Encoder) EncodeObject(v gojay.MarshalerJSONObject) error
```
* EncodeArray
```go
func (enc *gojay.Encoder) EncodeArray(v gojay.MarshalerJSONArray) error
```
* EncodeInt
```go
func (enc *gojay.Encoder) EncodeInt(n int) error
```
* EncodeInt64
```go
func (enc *gojay.Encoder) EncodeInt64(n int64) error
```
* EncodeFloat
```go
func (enc *gojay.Encoder) EncodeFloat(n float64) error
```
* EncodeBool
```go
func (enc *gojay.Encoder) EncodeBool(v bool) error
```
* EncodeString
```go
func (enc *gojay.Encoder) EncodeString(s string) error
```
### Structs and Maps
To encode a structure, the structure must implement the MarshalerJSONObject interface:
```go
type MarshalerJSONObject interface {
MarshalJSONObject(enc *gojay.Encoder)
IsNil() bool
}
```
`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.
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.
Example of implementation for a struct:
```go
type user struct {
id int
name string
email string
}
// implement MarshalerJSONObject
func (u *user) MarshalJSONObject(enc *gojay.Encoder) {
enc.IntKey("id", u.id)
enc.StringKey("name", u.name)
enc.StringKey("email", u.email)
}
func (u *user) IsNil() bool {
return u == nil
}
```
Example of implementation for a `map[string]string`:
```go
// define our custom map type implementing MarshalerJSONObject
type message map[string]string
// Implementing Marshaler
func (m message) MarshalJSONObject(enc *gojay.Encoder) {
for k, v := range m {
enc.StringKey(k, v)
}
}
func (m message) IsNil() bool {
return m == nil
}
```
### Arrays and Slices
To encode an array or a slice, the slice/array must implement the MarshalerJSONArray interface:
```go
type MarshalerJSONArray interface {
MarshalJSONArray(enc *gojay.Encoder)
IsNil() bool
}
```
`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.
`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.
Example of implementation:
```go
type users []*user
// implement MarshalerJSONArray
func (u *users) MarshalJSONArray(enc *gojay.Encoder) {
for _, e := range u {
enc.Object(e)
}
}
func (u *users) IsNil() bool {
return len(u) == 0
}
```
### Other types
To encode other types (string, int, float, booleans), you don't need to implement any interface.
Example of encoding strings:
```go
func main() {
name := "Jay"
b, err := gojay.Marshal(name)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b)) // "Jay"
}
```
# Stream API
### Stream Decoding
GoJay ships with a powerful stream decoder.
It allows to read continuously from an io.Reader stream and do JIT decoding writing unmarshalled JSON to a channel to allow async consuming.
When using the Stream API, the Decoder implements context.Context to provide graceful cancellation.
To decode a stream of JSON, you must call `gojay.Stream.DecodeStream` and pass it a `UnmarshalerStream` implementation.
```go
type UnmarshalerStream interface {
UnmarshalStream(*StreamDecoder) error
}
```
Example of implementation of stream reading from a WebSocket connection:
```go
// implement UnmarshalerStream
type ChannelStream chan *user
func (c ChannelStream) UnmarshalStream(dec *gojay.StreamDecoder) error {
u := &user{}
if err := dec.Object(u); err != nil {
return err
}
c <- u
return nil
}
func main() {
// get our websocket connection
origin := "http://localhost/"
url := "ws://localhost:12345/ws"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Fatal(err)
}
// create our channel which will receive our objects
streamChan := ChannelStream(make(chan *user))
// borrow a decoder
dec := gojay.Stream.BorrowDecoder(ws)
// start decoding, it will block until a JSON message is decoded from the WebSocket
// or until Done channel is closed
go dec.DecodeStream(streamChan)
for {
select {
case v := <-streamChan:
// Got something from my websocket!
log.Println(v)
case <-dec.Done():
log.Println("finished reading from WebSocket")
os.Exit(0)
}
}
}
```
### Stream Encoding
GoJay ships with a powerful stream encoder part of the Stream API.
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.
When using the Stream API, the Encoder implements context.Context to provide graceful cancellation.
To encode a stream of data, you must call `EncodeStream` and pass it a `MarshalerStream` implementation.
```go
type MarshalerStream interface {
MarshalStream(enc *gojay.StreamEncoder)
}
```
Example of implementation of stream writing to a WebSocket:
```go
// Our structure which will be pushed to our stream
type user struct {
id int
name string
email string
}
func (u *user) MarshalJSONObject(enc *gojay.Encoder) {
enc.IntKey("id", u.id)
enc.StringKey("name", u.name)
enc.StringKey("email", u.email)
}
func (u *user) IsNil() bool {
return u == nil
}
// Our MarshalerStream implementation
type StreamChan chan *user
func (s StreamChan) MarshalStream(enc *gojay.StreamEncoder) {
select {
case <-enc.Done():
return
case o := <-s:
enc.Object(o)
}
}
// Our main function
func main() {
// get our websocket connection
origin := "http://localhost/"
url := "ws://localhost:12345/ws"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Fatal(err)
}
// we borrow an encoder set stdout as the writer,
// set the number of consumer to 10
// and tell the encoder to separate each encoded element
// added to the channel by a new line character
enc := gojay.Stream.BorrowEncoder(ws).NConsumer(10).LineDelimited()
// instantiate our MarshalerStream
s := StreamChan(make(chan *user))
// start the stream encoder
// will block its goroutine until enc.Cancel(error) is called
// or until something is written to the channel
go enc.EncodeStream(s)
// write to our MarshalerStream
for i := 0; i < 1000; i++ {
s <- &user{i, "username", "user@email.com"}
}
// Wait
<-enc.Done()
}
```
# Unsafe API
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.
If you are not sure if your JSON is valid, don't use the Unsafe API.
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 :)
Access the `Unsafe` API this way:
```go
gojay.Unsafe.Unmarshal(b, v)
```
# Benchmarks
Benchmarks encode and decode three different data based on size (small, medium, large).
To run benchmark for decoder:
```bash
cd $GOPATH/src/github.com/francoispqt/gojay/benchmarks/decoder && make bench
```
To run benchmark for encoder:
```bash
cd $GOPATH/src/github.com/francoispqt/gojay/benchmarks/encoder && make bench
```
# Benchmark Results
## Decode
### Small Payload
[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/decoder/decoder_bench_small_test.go)
[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_small.go)
| | ns/op | bytes/op | allocs/op |
|-----------------|-----------|--------------|-----------|
| Std Library | 2547 | 496 | 4 |
| JsonIter | 2046 | 312 | 12 |
| JsonParser | 1408 | 0 | 0 |
| EasyJson | 929 | 240 | 2 |
| **GoJay** | **807** | **256** | **2** |
| **GoJay-unsafe**| **712** | **112** | **1** |
### Medium Payload
[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/decoder/decoder_bench_medium_test.go)
[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_medium.go)
| | ns/op | bytes/op | allocs/op |
|-----------------|-----------|----------|-----------|
| Std Library | 30148 | 2152 | 496 |
| JsonIter | 16309 | 2976 | 80 |
| JsonParser | 7793 | 0 | 0 |
| EasyJson | 7957 | 232 | 6 |
| **GoJay** | **4984** | **2448** | **8** |
| **GoJay-unsafe**| **4809** | **144** | **7** |
### Large Payload
[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/decoder/decoder_bench_large_test.go)
[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_large.go)
| | ns/op | bytes/op | allocs/op |
|-----------------|-----------|-------------|-----------|
| JsonIter | 210078 | 41712 | 1136 |
| EasyJson | 106626 | 160 | 2 |
| JsonParser | 66813 | 0 | 0 |
| **GoJay** | **52153** | **31241** | **77** |
| **GoJay-unsafe**| **48277** | **2561** | **76** |
## Encode
### Small Struct
[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/encoder/encoder_bench_small_test.go)
[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_small.go)
| | ns/op | bytes/op | allocs/op |
|----------------|----------|--------------|-----------|
| Std Library | 1280 | 464 | 3 |
| EasyJson | 871 | 944 | 6 |
| JsonIter | 866 | 272 | 3 |
| **GoJay** | **543** | **112** | **1** |
| **GoJay-func** | **347** | **0** | **0** |
### Medium Struct
[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/encoder/encoder_bench_medium_test.go)
[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_medium.go)
| | ns/op | bytes/op | allocs/op |
|-------------|----------|--------------|-----------|
| Std Library | 5006 | 1496 | 25 |
| JsonIter | 2232 | 1544 | 20 |
| EasyJson | 1997 | 1544 | 19 |
| **GoJay** | **1522** | **312** | **14** |
### Large Struct
[benchmark code is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/encoder/encoder_bench_large_test.go)
[benchmark data is here](https://github.com/francoispqt/gojay/blob/master/benchmarks/benchmarks_large.go)
| | ns/op | bytes/op | allocs/op |
|-------------|-----------|--------------|-----------|
| Std Library | 66441 | 20576 | 332 |
| JsonIter | 35247 | 20255 | 328 |
| EasyJson | 32053 | 15474 | 327 |
| **GoJay** | **27847** | **9802** | **318** |
# Contributing
Contributions are welcome :)
If you encounter issues please report it in Github and/or send an email at [francois@parquet.ninja](mailto:francois@parquet.ninja)
golang-github-francoispqt-gojay-1.2.13/benchmarks/ 0000775 0000000 0000000 00000000000 13653316651 0022111 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/benchmarks/benchmarks_large.go 0000664 0000000 0000000 00000075206 13653316651 0025741 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"strconv"
"github.com/francoispqt/gojay"
)
type DSUser struct {
Username string
}
func (m *DSUser) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "username":
return dec.AddString(&m.Username)
}
return nil
}
func (m *DSUser) NKeys() int {
return 1
}
func (m *DSUser) IsNil() bool {
return m == nil
}
func (m *DSUser) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddStringKey("username", m.Username)
}
type DSTopic struct {
Id int
Slug string
}
func (m *DSTopic) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "id":
return dec.AddInt(&m.Id)
case "slug":
return dec.AddString(&m.Slug)
}
return nil
}
func (m *DSTopic) NKeys() int {
return 2
}
func (m *DSTopic) IsNil() bool {
return m == nil
}
func (m *DSTopic) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddIntKey("id", m.Id)
enc.AddStringKey("slug", m.Slug)
}
type DSTopics []*DSTopic
func (t *DSTopics) UnmarshalJSONArray(dec *gojay.Decoder) error {
dsTopic := &DSTopic{}
*t = append(*t, dsTopic)
return dec.AddObject(dsTopic)
}
func (m *DSTopics) MarshalJSONArray(enc *gojay.Encoder) {
for _, e := range *m {
enc.AddObject(e)
}
}
func (m *DSTopics) IsNil() bool {
return m == nil
}
type DSTopicsList struct {
Topics DSTopics
MoreTopicsUrl string
}
func (m *DSTopicsList) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "topics":
m.Topics = DSTopics{}
return dec.AddArray(&m.Topics)
case "more_topics_url":
return dec.AddString(&m.MoreTopicsUrl)
}
return nil
}
func (m *DSTopicsList) NKeys() int {
return 2
}
func (m *DSTopicsList) IsNil() bool {
return m == nil
}
func (m *DSTopicsList) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddArrayKey("users", &m.Topics)
enc.AddStringKey("more_topics_url", m.MoreTopicsUrl)
}
type DSUsers []*DSUser
func (t *DSUsers) UnmarshalJSONArray(dec *gojay.Decoder) error {
dsUser := DSUser{}
*t = append(*t, &dsUser)
return dec.AddObject(&dsUser)
}
func (m *DSUsers) MarshalJSONArray(enc *gojay.Encoder) {
for _, e := range *m {
enc.AddObject(e)
}
}
func (m *DSUsers) IsNil() bool {
return m == nil
}
type LargePayload struct {
Users DSUsers
Topics *DSTopicsList
}
func (m *LargePayload) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "users":
return dec.AddArray(&m.Users)
case "topics":
m.Topics = &DSTopicsList{}
return dec.AddObject(m.Topics)
}
return nil
}
func (m *LargePayload) NKeys() int {
return 2
}
//easyjson:json
func (m *LargePayload) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddArrayKey("users", &m.Users)
enc.AddObjectKey("topics", m.Topics)
}
func (m *LargePayload) IsNil() bool {
return m == nil
}
var LargeFixture = []byte(`
{"users":[{"id":-1,"username":"system","avatar_template":"/user_avatar/discourse.metabase.com/system/{size}/6_1.png"},{"id":89,"username":"zergot","avatar_template":"https://avatars.discourse.org/v2/letter/z/0ea827/{size}.png"},{"id":1,"username":"sameer","avatar_template":"https://avatars.discourse.org/v2/letter/s/bbce88/{size}.png"},{"id":84,"username":"HenryMirror","avatar_template":"https://avatars.discourse.org/v2/letter/h/ecd19e/{size}.png"},{"id":73,"username":"fimp","avatar_template":"https://avatars.discourse.org/v2/letter/f/ee59a6/{size}.png"},{"id":14,"username":"agilliland","avatar_template":"/user_avatar/discourse.metabase.com/agilliland/{size}/26_1.png"},{"id":87,"username":"amir","avatar_template":"https://avatars.discourse.org/v2/letter/a/c37758/{size}.png"},{"id":82,"username":"waseem","avatar_template":"https://avatars.discourse.org/v2/letter/w/9dc877/{size}.png"},{"id":78,"username":"tovenaar","avatar_template":"https://avatars.discourse.org/v2/letter/t/9de0a6/{size}.png"},{"id":74,"username":"Ben","avatar_template":"https://avatars.discourse.org/v2/letter/b/df788c/{size}.png"},{"id":71,"username":"MarkLaFay","avatar_template":"https://avatars.discourse.org/v2/letter/m/3bc359/{size}.png"},{"id":72,"username":"camsaul","avatar_template":"/user_avatar/discourse.metabase.com/camsaul/{size}/70_1.png"},{"id":53,"username":"mhjb","avatar_template":"/user_avatar/discourse.metabase.com/mhjb/{size}/54_1.png"},{"id":58,"username":"jbwiv","avatar_template":"https://avatars.discourse.org/v2/letter/j/6bbea6/{size}.png"},{"id":70,"username":"Maggs","avatar_template":"https://avatars.discourse.org/v2/letter/m/bbce88/{size}.png"},{"id":69,"username":"andrefaria","avatar_template":"/user_avatar/discourse.metabase.com/andrefaria/{size}/65_1.png"},{"id":60,"username":"bencarter78","avatar_template":"/user_avatar/discourse.metabase.com/bencarter78/{size}/59_1.png"},{"id":55,"username":"vikram","avatar_template":"https://avatars.discourse.org/v2/letter/v/e47774/{size}.png"},{"id":68,"username":"edchan77","avatar_template":"/user_avatar/discourse.metabase.com/edchan77/{size}/66_1.png"},{"id":9,"username":"karthikd","avatar_template":"https://avatars.discourse.org/v2/letter/k/cab0a1/{size}.png"},{"id":23,"username":"arthurz","avatar_template":"/user_avatar/discourse.metabase.com/arthurz/{size}/32_1.png"},{"id":3,"username":"tom","avatar_template":"/user_avatar/discourse.metabase.com/tom/{size}/21_1.png"},{"id":50,"username":"LeoNogueira","avatar_template":"/user_avatar/discourse.metabase.com/leonogueira/{size}/52_1.png"},{"id":66,"username":"ss06vi","avatar_template":"https://avatars.discourse.org/v2/letter/s/3ab097/{size}.png"},{"id":34,"username":"mattcollins","avatar_template":"/user_avatar/discourse.metabase.com/mattcollins/{size}/41_1.png"},{"id":51,"username":"krmmalik","avatar_template":"/user_avatar/discourse.metabase.com/krmmalik/{size}/53_1.png"},{"id":46,"username":"odysseas","avatar_template":"https://avatars.discourse.org/v2/letter/o/5f8ce5/{size}.png"},{"id":5,"username":"jonthewayne","avatar_template":"/user_avatar/discourse.metabase.com/jonthewayne/{size}/18_1.png"},{"id":11,"username":"anandiyer","avatar_template":"/user_avatar/discourse.metabase.com/anandiyer/{size}/23_1.png"},{"id":25,"username":"alnorth","avatar_template":"/user_avatar/discourse.metabase.com/alnorth/{size}/34_1.png"},{"id":52,"username":"j_at_svg","avatar_template":"https://avatars.discourse.org/v2/letter/j/96bed5/{size}.png"},{"id":42,"username":"styts","avatar_template":"/user_avatar/discourse.metabase.com/styts/{size}/47_1.png"}],"topics":{"can_create_topic":false,"more_topics_url":"/c/uncategorized/l/latest?page=1","draft":null,"draft_key":"new_topic","draft_sequence":null,"per_page":30,"topics":[{"id":8,"title":"Welcome to Metabase's Discussion Forum","fancy_title":"Welcome to Metabase’s Discussion Forum","slug":"welcome-to-metabases-discussion-forum","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":"/images/welcome/discourse-edit-post-animated.gif","created_at":"2015-10-17T00:14:49.526Z","last_posted_at":"2015-10-17T00:14:49.557Z","bumped":true,"bumped_at":"2015-10-21T02:32:22.486Z","unseen":false,"pinned":true,"unpinned":null,"excerpt":"Welcome to Metabase's discussion forum. This is a place to get help on installation, setting up as well as sharing tips and tricks.","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":197,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"system","category_id":1,"pinned_globally":true,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":-1}]},{"id":169,"title":"Formatting Dates","fancy_title":"Formatting Dates","slug":"formatting-dates","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-01-14T06:30:45.311Z","last_posted_at":"2016-01-14T06:30:45.397Z","bumped":true,"bumped_at":"2016-01-14T06:30:45.397Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":11,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"zergot","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":89}]},{"id":168,"title":"Setting for google api key","fancy_title":"Setting for google api key","slug":"setting-for-google-api-key","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":null,"created_at":"2016-01-13T17:14:31.799Z","last_posted_at":"2016-01-14T06:24:03.421Z","bumped":true,"bumped_at":"2016-01-14T06:24:03.421Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":16,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"zergot","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":89}]},{"id":167,"title":"Cannot see non-US timezones on the admin","fancy_title":"Cannot see non-US timezones on the admin","slug":"cannot-see-non-us-timezones-on-the-admin","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-01-13T17:07:36.764Z","last_posted_at":"2016-01-13T17:07:36.831Z","bumped":true,"bumped_at":"2016-01-13T17:07:36.831Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":11,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"zergot","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":89}]},{"id":164,"title":"External (Metabase level) linkages in data schema","fancy_title":"External (Metabase level) linkages in data schema","slug":"external-metabase-level-linkages-in-data-schema","posts_count":4,"reply_count":1,"highest_post_number":4,"image_url":null,"created_at":"2016-01-11T13:51:02.286Z","last_posted_at":"2016-01-12T11:06:37.259Z","bumped":true,"bumped_at":"2016-01-12T11:06:37.259Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":32,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"zergot","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":89},{"extras":null,"description":"Frequent Poster","user_id":1}]},{"id":155,"title":"Query working on \"Questions\" but not in \"Pulses\"","fancy_title":"Query working on “Questions” but not in “Pulses”","slug":"query-working-on-questions-but-not-in-pulses","posts_count":3,"reply_count":0,"highest_post_number":3,"image_url":null,"created_at":"2016-01-01T14:06:10.083Z","last_posted_at":"2016-01-08T22:37:51.772Z","bumped":true,"bumped_at":"2016-01-08T22:37:51.772Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":72,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"agilliland","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":84},{"extras":null,"description":"Frequent Poster","user_id":73},{"extras":"latest","description":"Most Recent Poster","user_id":14}]},{"id":161,"title":"Pulses posted to Slack don't show question output","fancy_title":"Pulses posted to Slack don’t show question output","slug":"pulses-posted-to-slack-dont-show-question-output","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":"/uploads/default/original/1X/9d2806517bf3598b10be135b2c58923b47ba23e7.png","created_at":"2016-01-08T22:09:58.205Z","last_posted_at":"2016-01-08T22:28:44.685Z","bumped":true,"bumped_at":"2016-01-08T22:28:44.685Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":34,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":87},{"extras":"latest","description":"Most Recent Poster","user_id":1}]},{"id":152,"title":"Should we build Kafka connecter or Kafka plugin","fancy_title":"Should we build Kafka connecter or Kafka plugin","slug":"should-we-build-kafka-connecter-or-kafka-plugin","posts_count":4,"reply_count":1,"highest_post_number":4,"image_url":null,"created_at":"2015-12-28T20:37:23.501Z","last_posted_at":"2015-12-31T18:16:45.477Z","bumped":true,"bumped_at":"2015-12-31T18:16:45.477Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":84,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":82},{"extras":"latest","description":"Most Recent Poster, Frequent Poster","user_id":1}]},{"id":147,"title":"Change X and Y on graph","fancy_title":"Change X and Y on graph","slug":"change-x-and-y-on-graph","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2015-12-21T17:52:46.581Z","last_posted_at":"2015-12-21T17:52:46.684Z","bumped":true,"bumped_at":"2015-12-21T18:19:13.003Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":68,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"tovenaar","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":78}]},{"id":142,"title":"Issues sending mail via office365 relay","fancy_title":"Issues sending mail via office365 relay","slug":"issues-sending-mail-via-office365-relay","posts_count":5,"reply_count":2,"highest_post_number":5,"image_url":null,"created_at":"2015-12-16T10:38:47.315Z","last_posted_at":"2015-12-21T09:26:27.167Z","bumped":true,"bumped_at":"2015-12-21T09:26:27.167Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":122,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"Ben","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":74},{"extras":null,"description":"Frequent Poster","user_id":1}]},{"id":137,"title":"I see triplicates of my mongoDB collections","fancy_title":"I see triplicates of my mongoDB collections","slug":"i-see-triplicates-of-my-mongodb-collections","posts_count":3,"reply_count":0,"highest_post_number":3,"image_url":null,"created_at":"2015-12-14T13:33:03.426Z","last_posted_at":"2015-12-17T18:40:05.487Z","bumped":true,"bumped_at":"2015-12-17T18:40:05.487Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":97,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"MarkLaFay","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":71},{"extras":null,"description":"Frequent Poster","user_id":14}]},{"id":140,"title":"Google Analytics plugin","fancy_title":"Google Analytics plugin","slug":"google-analytics-plugin","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2015-12-15T13:00:55.644Z","last_posted_at":"2015-12-15T13:00:55.705Z","bumped":true,"bumped_at":"2015-12-15T13:00:55.705Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":105,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"fimp","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":73}]},{"id":138,"title":"With-mongo-connection failed: bad connection details:","fancy_title":"With-mongo-connection failed: bad connection details:","slug":"with-mongo-connection-failed-bad-connection-details","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2015-12-14T17:28:11.041Z","last_posted_at":"2015-12-14T17:28:11.111Z","bumped":true,"bumped_at":"2015-12-14T17:28:11.111Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":56,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"MarkLaFay","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":71}]},{"id":133,"title":"\"We couldn't understand your question.\" when I query mongoDB","fancy_title":"“We couldn’t understand your question.” when I query mongoDB","slug":"we-couldnt-understand-your-question-when-i-query-mongodb","posts_count":3,"reply_count":0,"highest_post_number":3,"image_url":null,"created_at":"2015-12-11T17:38:30.576Z","last_posted_at":"2015-12-14T13:31:26.395Z","bumped":true,"bumped_at":"2015-12-14T13:31:26.395Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":107,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"MarkLaFay","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":71},{"extras":null,"description":"Frequent Poster","user_id":72}]},{"id":129,"title":"My bar charts are all thin","fancy_title":"My bar charts are all thin","slug":"my-bar-charts-are-all-thin","posts_count":4,"reply_count":1,"highest_post_number":4,"image_url":"/uploads/default/original/1X/41bcf3b2a00dc7cfaff01cb3165d35d32a85bf1d.png","created_at":"2015-12-09T22:09:56.394Z","last_posted_at":"2015-12-11T19:00:45.289Z","bumped":true,"bumped_at":"2015-12-11T19:00:45.289Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":116,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"mhjb","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":53},{"extras":null,"description":"Frequent Poster","user_id":1}]},{"id":106,"title":"What is the expected return order of columns for graphing results when using raw SQL?","fancy_title":"What is the expected return order of columns for graphing results when using raw SQL?","slug":"what-is-the-expected-return-order-of-columns-for-graphing-results-when-using-raw-sql","posts_count":3,"reply_count":0,"highest_post_number":3,"image_url":null,"created_at":"2015-11-24T19:07:14.561Z","last_posted_at":"2015-12-11T17:04:14.149Z","bumped":true,"bumped_at":"2015-12-11T17:04:14.149Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":153,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"jbwiv","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":58},{"extras":null,"description":"Frequent Poster","user_id":14}]},{"id":131,"title":"Set site url from admin panel","fancy_title":"Set site url from admin panel","slug":"set-site-url-from-admin-panel","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":null,"created_at":"2015-12-10T06:22:46.042Z","last_posted_at":"2015-12-10T19:12:57.449Z","bumped":true,"bumped_at":"2015-12-10T19:12:57.449Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":77,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":70},{"extras":"latest","description":"Most Recent Poster","user_id":1}]},{"id":127,"title":"Internationalization (i18n)","fancy_title":"Internationalization (i18n)","slug":"internationalization-i18n","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":null,"created_at":"2015-12-08T16:55:37.397Z","last_posted_at":"2015-12-09T16:49:55.816Z","bumped":true,"bumped_at":"2015-12-09T16:49:55.816Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":85,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"agilliland","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":69},{"extras":"latest","description":"Most Recent Poster","user_id":14}]},{"id":109,"title":"Returning raw data with no filters always returns We couldn't understand your question","fancy_title":"Returning raw data with no filters always returns We couldn’t understand your question","slug":"returning-raw-data-with-no-filters-always-returns-we-couldnt-understand-your-question","posts_count":3,"reply_count":1,"highest_post_number":3,"image_url":null,"created_at":"2015-11-25T21:35:01.315Z","last_posted_at":"2015-12-09T10:26:12.255Z","bumped":true,"bumped_at":"2015-12-09T10:26:12.255Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":133,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"bencarter78","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":60},{"extras":null,"description":"Frequent Poster","user_id":14}]},{"id":103,"title":"Support for Cassandra?","fancy_title":"Support for Cassandra?","slug":"support-for-cassandra","posts_count":5,"reply_count":1,"highest_post_number":5,"image_url":null,"created_at":"2015-11-20T06:45:31.741Z","last_posted_at":"2015-12-09T03:18:51.274Z","bumped":true,"bumped_at":"2015-12-09T03:18:51.274Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":169,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"vikram","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":55},{"extras":null,"description":"Frequent Poster","user_id":1}]},{"id":128,"title":"Mongo query with Date breaks [solved: Mongo 3.0 required]","fancy_title":"Mongo query with Date breaks [solved: Mongo 3.0 required]","slug":"mongo-query-with-date-breaks-solved-mongo-3-0-required","posts_count":5,"reply_count":0,"highest_post_number":5,"image_url":null,"created_at":"2015-12-08T18:30:56.562Z","last_posted_at":"2015-12-08T21:03:02.421Z","bumped":true,"bumped_at":"2015-12-08T21:03:02.421Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":102,"like_count":1,"has_summary":false,"archetype":"regular","last_poster_username":"edchan77","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest","description":"Original Poster, Most Recent Poster","user_id":68},{"extras":null,"description":"Frequent Poster","user_id":1}]},{"id":23,"title":"Can this connect to MS SQL Server?","fancy_title":"Can this connect to MS SQL Server?","slug":"can-this-connect-to-ms-sql-server","posts_count":7,"reply_count":1,"highest_post_number":7,"image_url":null,"created_at":"2015-10-21T18:52:37.987Z","last_posted_at":"2015-12-07T17:41:51.609Z","bumped":true,"bumped_at":"2015-12-07T17:41:51.609Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":367,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":9},{"extras":null,"description":"Frequent Poster","user_id":23},{"extras":null,"description":"Frequent Poster","user_id":3},{"extras":null,"description":"Frequent Poster","user_id":50},{"extras":"latest","description":"Most Recent Poster","user_id":1}]},{"id":121,"title":"Cannot restart metabase in docker","fancy_title":"Cannot restart metabase in docker","slug":"cannot-restart-metabase-in-docker","posts_count":5,"reply_count":1,"highest_post_number":5,"image_url":null,"created_at":"2015-12-04T21:28:58.137Z","last_posted_at":"2015-12-04T23:02:00.488Z","bumped":true,"bumped_at":"2015-12-04T23:02:00.488Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":96,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":66},{"extras":"latest","description":"Most Recent Poster, Frequent Poster","user_id":1}]},{"id":85,"title":"Edit Max Rows Count","fancy_title":"Edit Max Rows Count","slug":"edit-max-rows-count","posts_count":4,"reply_count":2,"highest_post_number":4,"image_url":null,"created_at":"2015-11-11T23:46:52.917Z","last_posted_at":"2015-11-24T01:01:14.569Z","bumped":true,"bumped_at":"2015-11-24T01:01:14.569Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":169,"like_count":1,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":34},{"extras":"latest","description":"Most Recent Poster, Frequent Poster","user_id":1}]},{"id":96,"title":"Creating charts by querying more than one table at a time","fancy_title":"Creating charts by querying more than one table at a time","slug":"creating-charts-by-querying-more-than-one-table-at-a-time","posts_count":6,"reply_count":4,"highest_post_number":6,"image_url":null,"created_at":"2015-11-17T11:20:18.442Z","last_posted_at":"2015-11-21T02:12:25.995Z","bumped":true,"bumped_at":"2015-11-21T02:12:25.995Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":217,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":51},{"extras":"latest","description":"Most Recent Poster, Frequent Poster","user_id":1}]},{"id":90,"title":"Trying to add RDS postgresql as the database fails silently","fancy_title":"Trying to add RDS postgresql as the database fails silently","slug":"trying-to-add-rds-postgresql-as-the-database-fails-silently","posts_count":4,"reply_count":2,"highest_post_number":4,"image_url":null,"created_at":"2015-11-14T23:45:02.967Z","last_posted_at":"2015-11-21T01:08:45.915Z","bumped":true,"bumped_at":"2015-11-21T01:08:45.915Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":162,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":46},{"extras":"latest","description":"Most Recent Poster, Frequent Poster","user_id":1}]},{"id":17,"title":"Deploy to Heroku isn't working","fancy_title":"Deploy to Heroku isn’t working","slug":"deploy-to-heroku-isnt-working","posts_count":9,"reply_count":3,"highest_post_number":9,"image_url":null,"created_at":"2015-10-21T16:42:03.096Z","last_posted_at":"2015-11-20T18:34:14.044Z","bumped":true,"bumped_at":"2015-11-20T18:34:14.044Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":332,"like_count":2,"has_summary":false,"archetype":"regular","last_poster_username":"agilliland","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":5},{"extras":null,"description":"Frequent Poster","user_id":3},{"extras":null,"description":"Frequent Poster","user_id":11},{"extras":null,"description":"Frequent Poster","user_id":25},{"extras":"latest","description":"Most Recent Poster","user_id":14}]},{"id":100,"title":"Can I use DATEPART() in SQL queries?","fancy_title":"Can I use DATEPART() in SQL queries?","slug":"can-i-use-datepart-in-sql-queries","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":null,"created_at":"2015-11-17T23:15:58.033Z","last_posted_at":"2015-11-18T00:19:48.763Z","bumped":true,"bumped_at":"2015-11-18T00:19:48.763Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":112,"like_count":1,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":53},{"extras":"latest","description":"Most Recent Poster","user_id":1}]},{"id":98,"title":"Feature Request: LDAP Authentication","fancy_title":"Feature Request: LDAP Authentication","slug":"feature-request-ldap-authentication","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2015-11-17T17:22:44.484Z","last_posted_at":"2015-11-17T17:22:44.577Z","bumped":true,"bumped_at":"2015-11-17T17:22:44.577Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":97,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"j_at_svg","category_id":1,"pinned_globally":false,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user_id":52}]},{"id":87,"title":"Migrating from internal H2 to Postgres","fancy_title":"Migrating from internal H2 to Postgres","slug":"migrating-from-internal-h2-to-postgres","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":null,"created_at":"2015-11-12T14:36:06.745Z","last_posted_at":"2015-11-12T18:05:10.796Z","bumped":true,"bumped_at":"2015-11-12T18:05:10.796Z","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"views":111,"like_count":0,"has_summary":false,"archetype":"regular","last_poster_username":"sameer","category_id":1,"pinned_globally":false,"posters":[{"extras":null,"description":"Original Poster","user_id":42},{"extras":"latest","description":"Most Recent Poster","user_id":1}]}]}}
`)
func NewLargePayload() *LargePayload {
dsUsers := DSUsers{}
dsTopics := DSTopics{}
for i := 0; i < 100; i++ {
str := "test" + strconv.Itoa(i)
dsUsers = append(
dsUsers,
&DSUser{
Username: str,
},
)
dsTopics = append(
dsTopics,
&DSTopic{
Id: i,
Slug: str,
},
)
}
return &LargePayload{
Users: dsUsers,
Topics: &DSTopicsList{
Topics: dsTopics,
MoreTopicsUrl: "http://test.com",
},
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/benchmarks_large_easyjson.go 0000664 0000000 0000000 00000022147 13653316651 0027650 0 ustar 00root root 0000000 0000000 // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
package benchmarks
import (
json "encoding/json"
easyjson "github.com/mailru/easyjson"
jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter"
)
// suppress unused package warning
var (
_ *json.RawMessage
_ *jlexer.Lexer
_ *jwriter.Writer
_ easyjson.Marshaler
)
func easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks(in *jlexer.Lexer, out *LargePayload) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "Users":
if in.IsNull() {
in.Skip()
out.Users = nil
} else {
in.Delim('[')
if out.Users == nil {
if !in.IsDelim(']') {
out.Users = make(DSUsers, 0, 8)
} else {
out.Users = DSUsers{}
}
} else {
out.Users = (out.Users)[:0]
}
for !in.IsDelim(']') {
var v1 *DSUser
if in.IsNull() {
in.Skip()
v1 = nil
} else {
if v1 == nil {
v1 = new(DSUser)
}
(*v1).UnmarshalEasyJSON(in)
}
out.Users = append(out.Users, v1)
in.WantComma()
}
in.Delim(']')
}
case "Topics":
if in.IsNull() {
in.Skip()
out.Topics = nil
} else {
if out.Topics == nil {
out.Topics = new(DSTopicsList)
}
(*out.Topics).UnmarshalEasyJSON(in)
}
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks(out *jwriter.Writer, in LargePayload) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"Users\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Users == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null")
} else {
out.RawByte('[')
for v2, v3 := range in.Users {
if v2 > 0 {
out.RawByte(',')
}
if v3 == nil {
out.RawString("null")
} else {
(*v3).MarshalEasyJSON(out)
}
}
out.RawByte(']')
}
}
{
const prefix string = ",\"Topics\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Topics == nil {
out.RawString("null")
} else {
(*in.Topics).MarshalEasyJSON(out)
}
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v LargePayload) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v LargePayload) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *LargePayload) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *LargePayload) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks(l, v)
}
func easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks1(in *jlexer.Lexer, out *DSUser) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "Username":
out.Username = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks1(out *jwriter.Writer, in DSUser) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"Username\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Username))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v DSUser) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks1(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v DSUser) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks1(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *DSUser) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks1(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *DSUser) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks1(l, v)
}
func easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks2(in *jlexer.Lexer, out *DSTopicsList) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "Topics":
if in.IsNull() {
in.Skip()
out.Topics = nil
} else {
in.Delim('[')
if out.Topics == nil {
if !in.IsDelim(']') {
out.Topics = make(DSTopics, 0, 8)
} else {
out.Topics = DSTopics{}
}
} else {
out.Topics = (out.Topics)[:0]
}
for !in.IsDelim(']') {
var v4 *DSTopic
if in.IsNull() {
in.Skip()
v4 = nil
} else {
if v4 == nil {
v4 = new(DSTopic)
}
(*v4).UnmarshalEasyJSON(in)
}
out.Topics = append(out.Topics, v4)
in.WantComma()
}
in.Delim(']')
}
case "MoreTopicsUrl":
out.MoreTopicsUrl = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks2(out *jwriter.Writer, in DSTopicsList) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"Topics\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Topics == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null")
} else {
out.RawByte('[')
for v5, v6 := range in.Topics {
if v5 > 0 {
out.RawByte(',')
}
if v6 == nil {
out.RawString("null")
} else {
(*v6).MarshalEasyJSON(out)
}
}
out.RawByte(']')
}
}
{
const prefix string = ",\"MoreTopicsUrl\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.MoreTopicsUrl))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v DSTopicsList) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks2(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v DSTopicsList) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks2(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *DSTopicsList) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks2(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *DSTopicsList) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks2(l, v)
}
func easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks3(in *jlexer.Lexer, out *DSTopic) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "Id":
out.Id = int(in.Int())
case "Slug":
out.Slug = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks3(out *jwriter.Writer, in DSTopic) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"Id\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Int(int(in.Id))
}
{
const prefix string = ",\"Slug\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Slug))
}
out.RawByte('}')
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v DSTopic) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonCfe4e5f0EncodeGithubComFrancoispqtGojayBenchmarks3(w, v)
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *DSTopic) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonCfe4e5f0DecodeGithubComFrancoispqtGojayBenchmarks3(l, v)
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/benchmarks_medium.go 0000664 0000000 0000000 00000014102 13653316651 0026113 0 ustar 00root root 0000000 0000000 package benchmarks
import "github.com/francoispqt/gojay"
// Response from Clearbit API. Size: 2.4kb
var MediumFixture = []byte(`{
"person": {
"id": "d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
"name": {
"fullName": "Leonid Bugaev",
"givenName": "Leonid",
"familyName": "Bugaev"
},
"email": "leonsbox@gmail.com",
"gender": "male",
"location": "Saint Petersburg, Saint Petersburg, RU",
"geo": {
"city": "Saint Petersburg",
"state": "Saint Petersburg",
"country": "Russia",
"lat": 59.9342802,
"lng": 30.3350986
},
"bio": "Senior engineer at Granify.com",
"site": "http://flickfaver.com",
"avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
"employment": {
"name": "www.latera.ru",
"title": "Software Engineer",
"domain": "gmail.com"
},
"facebook": {
"handle": "leonid.bugaev"
},
"github": {
"handle": "buger",
"id": 14009,
"avatar": "https://avatars.githubusercontent.com/u/14009?v=3",
"company": "Granify",
"blog": "http://leonsbox.com",
"followers": 95,
"following": 10
},
"twitter": {
"handle": "flickfaver",
"id": 77004410,
"bio": null,
"followers": 2,
"following": 1,
"statuses": 5,
"favorites": 0,
"location": "",
"site": "http://flickfaver.com",
"avatar": null
},
"linkedin": {
"handle": "in/leonidbugaev"
},
"googleplus": {
"handle": null
},
"angellist": {
"handle": "leonid-bugaev",
"id": 61541,
"bio": "Senior engineer at Granify.com",
"blog": "http://buger.github.com",
"site": "http://buger.github.com",
"followers": 41,
"avatar": "https://d1qb2nb5cznatu.cloudfront.net/users/61541-medium_jpg?1405474390"
},
"klout": {
"handle": null,
"score": null
},
"foursquare": {
"handle": null
},
"aboutme": {
"handle": "leonid.bugaev",
"bio": null,
"avatar": null
},
"gravatar": {
"handle": "buger",
"urls": [
],
"avatar": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
"avatars": [
{
"url": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
"type": "thumbnail"
}
]
},
"fuzzy": false
},
"company": null
}`)
type CBAvatar struct {
Url string
}
func (m *CBAvatar) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "avatars":
return dec.AddString(&m.Url)
}
return nil
}
func (m *CBAvatar) NKeys() int {
return 1
}
func (m *CBAvatar) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddStringKey("url", m.Url)
}
func (m *CBAvatar) IsNil() bool {
return m == nil
}
type Avatars []*CBAvatar
func (t *Avatars) UnmarshalJSONArray(dec *gojay.Decoder) error {
avatar := CBAvatar{}
*t = append(*t, &avatar)
return dec.AddObject(&avatar)
}
func (m *Avatars) MarshalJSONArray(enc *gojay.Encoder) {
for _, e := range *m {
enc.AddObject(e)
}
}
func (m *Avatars) IsNil() bool {
return m == nil
}
type CBGravatar struct {
Avatars Avatars
}
func (m *CBGravatar) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "avatars":
return dec.AddArray(&m.Avatars)
}
return nil
}
func (m *CBGravatar) NKeys() int {
return 1
}
func (m *CBGravatar) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddArrayKey("avatars", &m.Avatars)
}
func (m *CBGravatar) IsNil() bool {
return m == nil
}
type CBGithub struct {
Followers int
}
func (m *CBGithub) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "followers":
return dec.AddInt(&m.Followers)
}
return nil
}
func (m *CBGithub) NKeys() int {
return 1
}
func (m *CBGithub) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddIntKey("followers", m.Followers)
}
func (m *CBGithub) IsNil() bool {
return m == nil
}
type CBName struct {
FullName string `json:"fullName"`
}
func (m *CBName) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "fullName":
return dec.AddString(&m.FullName)
}
return nil
}
func (m *CBName) NKeys() int {
return 1
}
func (m *CBName) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddStringKey("fullName", m.FullName)
}
func (m *CBName) IsNil() bool {
return m == nil
}
type CBPerson struct {
Name *CBName `json:"name"`
Github *CBGithub `json:"github"`
Gravatar *CBGravatar
}
func (m *CBPerson) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "name":
m.Name = &CBName{}
return dec.AddObject(m.Name)
case "github":
m.Github = &CBGithub{}
return dec.AddObject(m.Github)
case "gravatar":
m.Gravatar = &CBGravatar{}
return dec.AddObject(m.Gravatar)
}
return nil
}
func (m *CBPerson) NKeys() int {
return 3
}
func (m *CBPerson) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddObjectKey("name", m.Name)
enc.AddObjectKey("github", m.Github)
enc.AddObjectKey("gravatar", m.Gravatar)
}
func (m *CBPerson) IsNil() bool {
return m == nil
}
//easyjson:json
type MediumPayload struct {
Person *CBPerson `json:"person"`
Company string `json:"company"`
}
func (m *MediumPayload) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "person":
m.Person = &CBPerson{}
return dec.AddObject(m.Person)
case "company":
dec.AddString(&m.Company)
}
return nil
}
func (m *MediumPayload) NKeys() int {
return 2
}
func (m *MediumPayload) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddObjectKey("person", m.Person)
// enc.AddStringKey("company", m.Company)
}
func (m *MediumPayload) IsNil() bool {
return m == nil
}
func NewMediumPayload() *MediumPayload {
return &MediumPayload{
Company: "test",
Person: &CBPerson{
Name: &CBName{
FullName: "test",
},
Github: &CBGithub{
Followers: 100,
},
Gravatar: &CBGravatar{
Avatars: Avatars{
&CBAvatar{
Url: "http://test.com",
},
&CBAvatar{
Url: "http://test.com",
},
&CBAvatar{
Url: "http://test.com",
},
&CBAvatar{
Url: "http://test.com",
},
&CBAvatar{
Url: "http://test.com",
},
&CBAvatar{
Url: "http://test.com",
},
&CBAvatar{
Url: "http://test.com",
},
&CBAvatar{
Url: "http://test.com",
},
},
},
},
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/benchmarks_medium_easyjson.go 0000664 0000000 0000000 00000030354 13653316651 0030035 0 ustar 00root root 0000000 0000000 // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
package benchmarks
import (
json "encoding/json"
easyjson "github.com/mailru/easyjson"
jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter"
)
// suppress unused package warning
var (
_ *json.RawMessage
_ *jlexer.Lexer
_ *jwriter.Writer
_ easyjson.Marshaler
)
func easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks(in *jlexer.Lexer, out *MediumPayload) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "person":
if in.IsNull() {
in.Skip()
out.Person = nil
} else {
if out.Person == nil {
out.Person = new(CBPerson)
}
(*out.Person).UnmarshalEasyJSON(in)
}
case "company":
out.Company = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks(out *jwriter.Writer, in MediumPayload) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"person\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Person == nil {
out.RawString("null")
} else {
(*in.Person).MarshalEasyJSON(out)
}
}
{
const prefix string = ",\"company\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Company))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v MediumPayload) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v MediumPayload) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *MediumPayload) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *MediumPayload) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks(l, v)
}
func easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks1(in *jlexer.Lexer, out *CBPerson) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "name":
if in.IsNull() {
in.Skip()
out.Name = nil
} else {
if out.Name == nil {
out.Name = new(CBName)
}
(*out.Name).UnmarshalEasyJSON(in)
}
case "github":
if in.IsNull() {
in.Skip()
out.Github = nil
} else {
if out.Github == nil {
out.Github = new(CBGithub)
}
(*out.Github).UnmarshalEasyJSON(in)
}
case "Gravatar":
if in.IsNull() {
in.Skip()
out.Gravatar = nil
} else {
if out.Gravatar == nil {
out.Gravatar = new(CBGravatar)
}
(*out.Gravatar).UnmarshalEasyJSON(in)
}
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks1(out *jwriter.Writer, in CBPerson) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"name\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Name == nil {
out.RawString("null")
} else {
(*in.Name).MarshalEasyJSON(out)
}
}
{
const prefix string = ",\"github\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Github == nil {
out.RawString("null")
} else {
(*in.Github).MarshalEasyJSON(out)
}
}
{
const prefix string = ",\"Gravatar\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Gravatar == nil {
out.RawString("null")
} else {
(*in.Gravatar).MarshalEasyJSON(out)
}
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v CBPerson) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks1(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v CBPerson) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks1(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *CBPerson) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks1(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *CBPerson) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks1(l, v)
}
func easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks2(in *jlexer.Lexer, out *CBName) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "fullName":
out.FullName = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks2(out *jwriter.Writer, in CBName) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"fullName\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.FullName))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v CBName) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks2(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v CBName) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks2(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *CBName) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks2(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *CBName) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks2(l, v)
}
func easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks3(in *jlexer.Lexer, out *CBGravatar) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "Avatars":
if in.IsNull() {
in.Skip()
out.Avatars = nil
} else {
in.Delim('[')
if out.Avatars == nil {
if !in.IsDelim(']') {
out.Avatars = make(Avatars, 0, 8)
} else {
out.Avatars = Avatars{}
}
} else {
out.Avatars = (out.Avatars)[:0]
}
for !in.IsDelim(']') {
var v1 *CBAvatar
if in.IsNull() {
in.Skip()
v1 = nil
} else {
if v1 == nil {
v1 = new(CBAvatar)
}
(*v1).UnmarshalEasyJSON(in)
}
out.Avatars = append(out.Avatars, v1)
in.WantComma()
}
in.Delim(']')
}
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks3(out *jwriter.Writer, in CBGravatar) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"Avatars\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
if in.Avatars == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null")
} else {
out.RawByte('[')
for v2, v3 := range in.Avatars {
if v2 > 0 {
out.RawByte(',')
}
if v3 == nil {
out.RawString("null")
} else {
(*v3).MarshalEasyJSON(out)
}
}
out.RawByte(']')
}
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v CBGravatar) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks3(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v CBGravatar) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks3(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *CBGravatar) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks3(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *CBGravatar) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks3(l, v)
}
func easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks4(in *jlexer.Lexer, out *CBGithub) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "Followers":
out.Followers = int(in.Int())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks4(out *jwriter.Writer, in CBGithub) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"Followers\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Int(int(in.Followers))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v CBGithub) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks4(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v CBGithub) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks4(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *CBGithub) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks4(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *CBGithub) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks4(l, v)
}
func easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks5(in *jlexer.Lexer, out *CBAvatar) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "Url":
out.Url = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks5(out *jwriter.Writer, in CBAvatar) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"Url\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Url))
}
out.RawByte('}')
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v CBAvatar) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonB0500db0EncodeGithubComFrancoispqtGojayBenchmarks5(w, v)
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *CBAvatar) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonB0500db0DecodeGithubComFrancoispqtGojayBenchmarks5(l, v)
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/benchmarks_small.go 0000664 0000000 0000000 00000002770 13653316651 0025753 0 ustar 00root root 0000000 0000000 package benchmarks
import "github.com/francoispqt/gojay"
var SmallFixture = []byte(`{"st": 1,"sid": 486,"tt": "active","gr": 0,"uuid": "de305d54-75b4-431b-adb2-eb6b9e546014","ip": "127.0.0.1","ua": "user_agent","tz": -6,"v": 1}`)
//easyjson:json
type SmallPayload struct {
St int
Sid int
Tt string
Gr int
Uuid string
Ip string
Ua string
Tz int
V int
}
func (t *SmallPayload) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddIntKey("st", t.St)
enc.AddIntKey("sid", t.Sid)
enc.AddStringKey("tt", t.Tt)
enc.AddIntKey("gr", t.Gr)
enc.AddStringKey("uuid", t.Uuid)
enc.AddStringKey("ip", t.Ip)
enc.AddStringKey("ua", t.Ua)
enc.AddIntKey("tz", t.Tz)
enc.AddIntKey("v", t.V)
}
func (t *SmallPayload) IsNil() bool {
return t == nil
}
func (t *SmallPayload) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "st":
return dec.AddInt(&t.St)
case "sid":
return dec.AddInt(&t.Sid)
case "gr":
return dec.AddInt(&t.Gr)
case "tz":
return dec.AddInt(&t.Tz)
case "v":
return dec.AddInt(&t.V)
case "tt":
return dec.AddString(&t.Tt)
case "uuid":
return dec.AddString(&t.Uuid)
case "ip":
return dec.AddString(&t.Ip)
case "ua":
return dec.AddString(&t.Ua)
}
return nil
}
func (t *SmallPayload) NKeys() int {
return 9
}
func NewSmallPayload() *SmallPayload {
return &SmallPayload{
St: 1,
Sid: 2,
Tt: "TestString",
Gr: 4,
Uuid: "8f9a65eb-4807-4d57-b6e0-bda5d62f1429",
Ip: "127.0.0.1",
Ua: "Mozilla",
Tz: 8,
V: 6,
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/benchmarks_small_easyjson.go 0000664 0000000 0000000 00000007223 13653316651 0027664 0 ustar 00root root 0000000 0000000 // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
package benchmarks
import (
json "encoding/json"
easyjson "github.com/mailru/easyjson"
jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter"
)
// suppress unused package warning
var (
_ *json.RawMessage
_ *jlexer.Lexer
_ *jwriter.Writer
_ easyjson.Marshaler
)
func easyjson890029d8DecodeGithubComFrancoispqtGojayBenchmarks(in *jlexer.Lexer, out *SmallPayload) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "St":
out.St = int(in.Int())
case "Sid":
out.Sid = int(in.Int())
case "Tt":
out.Tt = string(in.String())
case "Gr":
out.Gr = int(in.Int())
case "Uuid":
out.Uuid = string(in.String())
case "Ip":
out.Ip = string(in.String())
case "Ua":
out.Ua = string(in.String())
case "Tz":
out.Tz = int(in.Int())
case "V":
out.V = int(in.Int())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjson890029d8EncodeGithubComFrancoispqtGojayBenchmarks(out *jwriter.Writer, in SmallPayload) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"St\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Int(int(in.St))
}
{
const prefix string = ",\"Sid\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Int(int(in.Sid))
}
{
const prefix string = ",\"Tt\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Tt))
}
{
const prefix string = ",\"Gr\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Int(int(in.Gr))
}
{
const prefix string = ",\"Uuid\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Uuid))
}
{
const prefix string = ",\"Ip\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Ip))
}
{
const prefix string = ",\"Ua\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Ua))
}
{
const prefix string = ",\"Tz\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Int(int(in.Tz))
}
{
const prefix string = ",\"V\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Int(int(in.V))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v SmallPayload) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjson890029d8EncodeGithubComFrancoispqtGojayBenchmarks(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v SmallPayload) MarshalEasyJSON(w *jwriter.Writer) {
easyjson890029d8EncodeGithubComFrancoispqtGojayBenchmarks(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *SmallPayload) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjson890029d8DecodeGithubComFrancoispqtGojayBenchmarks(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *SmallPayload) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjson890029d8DecodeGithubComFrancoispqtGojayBenchmarks(l, v)
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/ 0000775 0000000 0000000 00000000000 13653316651 0023516 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/.gitignore 0000664 0000000 0000000 00000000010 13653316651 0025475 0 ustar 00root root 0000000 0000000 vendor/* golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/Makefile 0000664 0000000 0000000 00000002114 13653316651 0025154 0 ustar 00root root 0000000 0000000 .PHONY: test
test:
go test -run=^Test -v
.PHONY: bench
bench:
go test -benchmem -run=^$ github.com/francoispqt/gojay/benchmarks/decoder -bench ^Benchmark
.PHONY: benchtrace
benchtrace:
go test -c & GODEBUG=allocfreetrace=1 ./decoder.test -test.run=none -test.bench=^Benchmark -test.benchtime=10ms 2>trace.log
.PHONY: benchcpu
benchcpu:
go test -benchmem -run=^$ github.com/francoispqt/gojay/benchmarks/decoder -bench ^Benchmark -cpuprofile cpu.out
.PHONY: testtrace
testtrace:
go test -benchmem -run=^$ github.com/francoispqt/gojay/benchmarks/decoder -bench ^Benchmark -trace trace.out
.PHONY: benchgojay
benchgojay:
go test -benchmem -run=^BenchmarkGoJay -bench=^BenchmarkGoJay -benchtime=30ms
.PHONY: benchgojaycpu
benchgojaycpu:
go test -benchmem -run=^BenchmarkGoJay -bench=^BenchmarkGoJay -benchtime=30ms -cpuprofile cpu.out
.PHONY: benchjsoniter
benchjsoniter:
go test -benchmem -run=^BenchmarkJsonIter -bench=^BenchmarkJsonIter -benchtime=30ms
.PHONY: benchjsonparser
benchjsonparser:
go test -benchmem -run=^BenchmarkJsonParser -bench=^BenchmarkJsonParser -benchtime=30ms golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder.go 0000664 0000000 0000000 00000000023 13653316651 0025445 0 ustar 00root root 0000000 0000000 package benchmarks
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder_bench_float_test.go 0000664 0000000 0000000 00000001077 13653316651 0031042 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"encoding/json"
"testing"
"github.com/francoispqt/gojay"
)
var bigf = []byte(`0.00058273999999999999`)
// BenchmarkBigFloatEncodingJSON decodes a big float with the standard package
func BenchmarkBigFloatEncodingJSON(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
var f float64
var _ = json.Unmarshal(bigf, &f)
}
}
// BenchmarkBigFloatGojay decodes a big float with gojay
func BenchmarkBigFloatGojay(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
var f float64
var _ = gojay.Unmarshal(bigf, &f)
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder_bench_large_test.go 0000664 0000000 0000000 00000003023 13653316651 0031020 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"testing"
"github.com/buger/jsonparser"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
jsoniter "github.com/json-iterator/go"
"github.com/mailru/easyjson"
)
func BenchmarkJsonParserDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
jsonparser.ArrayEach(benchmarks.LargeFixture, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
jsonparser.Get(value, "username")
nothing()
}, "users")
jsonparser.ArrayEach(benchmarks.LargeFixture, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
jsonparser.GetInt(value, "id")
jsonparser.Get(value, "slug")
nothing()
}, "topics", "topics")
}
}
func BenchmarkJsonIterDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.LargePayload{}
jsoniter.Unmarshal(benchmarks.LargeFixture, &result)
}
}
func BenchmarkEasyJsonDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.LargePayload{}
easyjson.Unmarshal(benchmarks.LargeFixture, &result)
}
}
func BenchmarkGoJayDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.LargePayload{}
gojay.UnmarshalJSONObject(benchmarks.LargeFixture, &result)
}
}
func BenchmarkGoJayUnsafeDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.LargePayload{}
gojay.Unsafe.UnmarshalJSONObject(benchmarks.LargeFixture, &result)
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder_bench_medium_test.go 0000664 0000000 0000000 00000003537 13653316651 0031220 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"encoding/json"
"testing"
"github.com/buger/jsonparser"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
jsoniter "github.com/json-iterator/go"
"github.com/mailru/easyjson"
)
func BenchmarkJsonIterDecodeObjMedium(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
result := benchmarks.MediumPayload{}
jsoniter.Unmarshal(benchmarks.MediumFixture, &result)
}
}
/*
github.com/buger/jsonparser
*/
func BenchmarkJSONParserDecodeObjMedium(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
jsonparser.Get(benchmarks.MediumFixture, "person", "name", "fullName")
jsonparser.GetInt(benchmarks.MediumFixture, "person", "github", "followers")
jsonparser.Get(benchmarks.MediumFixture, "company")
jsonparser.ArrayEach(benchmarks.MediumFixture, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
jsonparser.Get(value, "url")
nothing()
}, "person", "gravatar", "avatars")
}
}
func BenchmarkEncodingJsonStructMedium(b *testing.B) {
for i := 0; i < b.N; i++ {
var data = benchmarks.MediumPayload{}
json.Unmarshal(benchmarks.MediumFixture, &data)
}
}
func BenchmarkEasyJsonDecodeObjMedium(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.MediumPayload{}
easyjson.Unmarshal(benchmarks.MediumFixture, &result)
}
}
func BenchmarkGoJayDecodeObjMedium(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.MediumPayload{}
err := gojay.UnmarshalJSONObject(benchmarks.MediumFixture, &result)
if err != nil {
b.Error(err)
}
}
}
func BenchmarkGoJayUnsafeDecodeObjMedium(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.MediumPayload{}
err := gojay.Unsafe.UnmarshalJSONObject(benchmarks.MediumFixture, &result)
if err != nil {
b.Error(err)
}
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder_bench_small_test.go 0000664 0000000 0000000 00000003322 13653316651 0031040 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"encoding/json"
_ "fmt"
"testing"
"github.com/buger/jsonparser"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
jsoniter "github.com/json-iterator/go"
"github.com/mailru/easyjson"
)
func BenchmarkJSONDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
result := benchmarks.SmallPayload{}
json.Unmarshal(benchmarks.SmallFixture, &result)
}
}
func nothing(_ ...interface{}) {}
func BenchmarkJSONParserSmall(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
jsonparser.GetInt(benchmarks.SmallFixture, "tz")
jsonparser.GetInt(benchmarks.SmallFixture, "v")
jsonparser.GetInt(benchmarks.SmallFixture, "sid")
jsonparser.GetInt(benchmarks.SmallFixture, "st")
jsonparser.GetInt(benchmarks.SmallFixture, "gr")
jsonparser.Get(benchmarks.SmallFixture, "uuid")
jsonparser.Get(benchmarks.SmallFixture, "ua")
nothing()
}
}
func BenchmarkJsonIterDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
result := benchmarks.SmallPayload{}
jsoniter.Unmarshal(benchmarks.SmallFixture, &result)
}
}
func BenchmarkEasyJsonDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.SmallPayload{}
easyjson.Unmarshal(benchmarks.SmallFixture, &result)
}
}
func BenchmarkGoJayDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
result := benchmarks.SmallPayload{}
gojay.UnmarshalJSONObject(benchmarks.SmallFixture, &result)
}
}
func BenchmarkGoJayUnsafeDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.SmallPayload{}
gojay.Unsafe.UnmarshalJSONObject(benchmarks.SmallFixture, &result)
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder_large_test.go 0000664 0000000 0000000 00000001257 13653316651 0027670 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"testing"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
"github.com/stretchr/testify/assert"
)
func TestGoJayDecodeObjLarge(t *testing.T) {
result := benchmarks.LargePayload{}
err := gojay.UnmarshalJSONObject(benchmarks.LargeFixture, &result)
assert.Nil(t, err, "err should be nil")
assert.Len(t, result.Users, 32, "Len of users should be 32")
for _, u := range result.Users {
assert.True(t, len(u.Username) > 0, "User should have username")
}
assert.Len(t, result.Topics.Topics, 30, "Len of topics should be 30")
for _, top := range result.Topics.Topics {
assert.True(t, top.Id > 0, "Topic should have Id")
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder_medium_test.go 0000664 0000000 0000000 00000001230 13653316651 0030045 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"testing"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
"github.com/stretchr/testify/assert"
)
func TestGoJayDecodeObjMedium(t *testing.T) {
result := benchmarks.MediumPayload{}
err := gojay.Unmarshal(benchmarks.MediumFixture, &result)
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "Leonid Bugaev", result.Person.Name.FullName, "result.Person.Name.FullName should be Leonid Bugaev")
assert.Equal(t, 95, result.Person.Github.Followers, "result.Person.Github.Followers should be 95")
assert.Len(t, result.Person.Gravatar.Avatars, 1, "result.Person.Gravatar.Avatars should have 1 item")
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/decoder/decoder_small_test.go 0000664 0000000 0000000 00000001742 13653316651 0027705 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"testing"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
"github.com/stretchr/testify/assert"
)
func TestGoJayDecodeObjSmall(t *testing.T) {
result := benchmarks.SmallPayload{}
err := gojay.Unmarshal(benchmarks.SmallFixture, &result)
assert.Nil(t, err, "err should be nil")
assert.Equal(t, result.St, 1, "result.St should be 1")
assert.Equal(t, result.Sid, 486, "result.Sid should be 486")
assert.Equal(t, result.Tt, "active", "result.Sid should be 'active'")
assert.Equal(t, result.Gr, 0, "result.Gr should be 0")
assert.Equal(
t,
result.Uuid,
"de305d54-75b4-431b-adb2-eb6b9e546014",
"result.Gr should be 'de305d54-75b4-431b-adb2-eb6b9e546014'",
)
assert.Equal(t, result.Ip, "127.0.0.1", "result.Ip should be '127.0.0.1'")
assert.Equal(t, result.Ua, "user_agent", "result.Ua should be 'user_agent'")
assert.Equal(t, result.Tz, -6, "result.Tz should be 6")
assert.Equal(t, result.V, 1, "result.V should be 1")
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/ 0000775 0000000 0000000 00000000000 13653316651 0023530 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/.gitignore 0000664 0000000 0000000 00000000010 13653316651 0025507 0 ustar 00root root 0000000 0000000 vendor/* golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/Makefile 0000664 0000000 0000000 00000002041 13653316651 0025165 0 ustar 00root root 0000000 0000000 .PHONY: bench
bench:
go test -benchmem -run=^$ github.com/francoispqt/gojay/benchmarks/encoder -bench ^Benchmark
.PHONY: benchtrace
benchtrace:
go test -c & GODEBUG=allocfreetrace=1 ./encoder.test -test.run=none -test.bench=^Benchmark -test.benchtime=10ms 2>trace.log
.PHONY: benchcpu
benchcpu:
go test -benchmem -run=^$ github.com/francoispqt/gojay/benchmarks/encoder -bench ^Benchmark -cpuprofile cpu.out
.PHONY: testtrace
testtrace:
go test -benchmem -run=^$ github.com/francoispqt/gojay/benchmarks/encoder -bench ^Benchmark -trace trace.out
.PHONY: benchgojay
benchgojay:
go test -benchmem -run=^BenchmarkGoJay -bench=^BenchmarkGoJay -benchtime=30ms
.PHONY: benchgojaycpu
benchgojaycpu:
go test -benchmem -run=^BenchmarkGoJay -bench=^BenchmarkGoJay -benchtime=30ms -cpuprofile cpu.out
.PHONY: benchjsoniter
benchjsoniter:
go test -benchmem -run=^BenchmarkJsonIter -bench=^BenchmarkJsonIter -benchtime=30ms
.PHONY: benchjsonparser
benchjsonparser:
go test -benchmem -run=^BenchmarkJsonParser -bench=^BenchmarkJsonParser -benchtime=30ms golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/encoder_bench_large_test.go 0000664 0000000 0000000 00000002373 13653316651 0031053 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"encoding/json"
"log"
"testing"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
jsoniter "github.com/json-iterator/go"
"github.com/mailru/easyjson"
)
func BenchmarkEncodingJsonEncodeLargeStruct(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(benchmarks.NewLargePayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkJsonIterEncodeLargeStruct(b *testing.B) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(benchmarks.NewLargePayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkEasyJsonEncodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := easyjson.Marshal(benchmarks.NewLargePayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkGoJayEncodeLargeStruct(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := gojay.MarshalJSONObject(benchmarks.NewLargePayload()); err != nil {
b.Fatal(err)
}
}
}
func TestGoJayEncodeLargeStruct(t *testing.T) {
if output, err := gojay.MarshalJSONObject(benchmarks.NewLargePayload()); err != nil {
t.Fatal(err)
} else {
log.Print(string(output))
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/encoder_bench_medium_test.go 0000664 0000000 0000000 00000002406 13653316651 0031236 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"encoding/json"
"log"
"testing"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
jsoniter "github.com/json-iterator/go"
"github.com/mailru/easyjson"
)
func BenchmarkEncodingJsonEncodeMediumStruct(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(benchmarks.NewMediumPayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkJsonIterEncodeMediumStruct(b *testing.B) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(benchmarks.NewMediumPayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkEasyJsonEncodeObjMedium(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := easyjson.Marshal(benchmarks.NewMediumPayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkGoJayEncodeMediumStruct(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := gojay.MarshalJSONObject(benchmarks.NewMediumPayload()); err != nil {
b.Fatal(err)
}
}
}
func TestGoJayEncodeMediumStruct(t *testing.T) {
if output, err := gojay.MarshalJSONObject(benchmarks.NewMediumPayload()); err != nil {
t.Fatal(err)
} else {
log.Print(string(output))
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/encoder_bench_small_test.go 0000664 0000000 0000000 00000003350 13653316651 0031065 0 ustar 00root root 0000000 0000000 package benchmarks
import (
"encoding/json"
"log"
"testing"
"github.com/francoispqt/gojay"
"github.com/francoispqt/gojay/benchmarks"
jsoniter "github.com/json-iterator/go"
"github.com/mailru/easyjson"
)
func BenchmarkEncodingJsonEncodeSmallStruct(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(benchmarks.NewSmallPayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkEasyJsonEncodeObjSmall(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := easyjson.Marshal(benchmarks.NewSmallPayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkJsonIterEncodeSmallStruct(b *testing.B) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(benchmarks.NewSmallPayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkGoJayEncodeSmallStruct(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := gojay.MarshalJSONObject(benchmarks.NewSmallPayload()); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkGoJayEncodeSmallFunc(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := gojay.MarshalJSONObject(gojay.EncodeObjectFunc(func(enc *gojay.Encoder) {
enc.AddIntKey("st", 1)
enc.AddIntKey("sid", 1)
enc.AddStringKey("tt", "test")
enc.AddIntKey("gr", 1)
enc.AddStringKey("uuid", "test")
enc.AddStringKey("ip", "test")
enc.AddStringKey("ua", "test")
enc.AddIntKey("tz", 1)
enc.AddIntKey("v", 1)
})); err != nil {
b.Fatal(err)
}
}
}
func TestGoJayEncodeSmallStruct(t *testing.T) {
if output, err := gojay.MarshalJSONObject(benchmarks.NewSmallPayload()); err != nil {
t.Fatal(err)
} else {
log.Print(output)
}
}
golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/encoder_large_test.go 0000664 0000000 0000000 00000000023 13653316651 0027702 0 ustar 00root root 0000000 0000000 package benchmarks
golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/encoder_medium_test.go 0000664 0000000 0000000 00000000023 13653316651 0030070 0 ustar 00root root 0000000 0000000 package benchmarks
golang-github-francoispqt-gojay-1.2.13/benchmarks/encoder/encoder_small_test.go 0000664 0000000 0000000 00000000023 13653316651 0027720 0 ustar 00root root 0000000 0000000 package benchmarks
golang-github-francoispqt-gojay-1.2.13/decode.go 0000664 0000000 0000000 00000023610 13653316651 0021550 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"io"
)
// UnmarshalJSONArray parses the JSON-encoded data and stores the result in the value pointed to by v.
//
// v must implement UnmarshalerJSONArray.
//
// If a JSON value is not appropriate for a given target type, or if a JSON number
// overflows the target type, UnmarshalJSONArray skips that field and completes the unmarshaling as best it can.
func UnmarshalJSONArray(data []byte, v UnmarshalerJSONArray) error {
dec := borrowDecoder(nil, 0)
defer dec.Release()
dec.data = make([]byte, len(data))
copy(dec.data, data)
dec.length = len(data)
_, err := dec.decodeArray(v)
if err != nil {
return err
}
if dec.err != nil {
return dec.err
}
return nil
}
// UnmarshalJSONObject parses the JSON-encoded data and stores the result in the value pointed to by v.
//
// v must implement UnmarshalerJSONObject.
//
// If a JSON value is not appropriate for a given target type, or if a JSON number
// overflows the target type, UnmarshalJSONObject skips that field and completes the unmarshaling as best it can.
func UnmarshalJSONObject(data []byte, v UnmarshalerJSONObject) error {
dec := borrowDecoder(nil, 0)
defer dec.Release()
dec.data = make([]byte, len(data))
copy(dec.data, data)
dec.length = len(data)
_, err := dec.decodeObject(v)
if err != nil {
return err
}
if dec.err != nil {
return dec.err
}
return nil
}
// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.
// If v is nil, not an implementation of UnmarshalerJSONObject or UnmarshalerJSONArray or not one of the following types:
// *string, **string, *int, **int, *int8, **int8, *int16, **int16, *int32, **int32, *int64, **int64, *uint8, **uint8, *uint16, **uint16,
// *uint32, **uint32, *uint64, **uint64, *float64, **float64, *float32, **float32, *bool, **bool
// Unmarshal returns an InvalidUnmarshalError.
//
//
// If a JSON value is not appropriate for a given target type, or if a JSON number
// overflows the target type, Unmarshal skips that field and completes the unmarshaling as best it can.
// If no more serious errors are encountered, Unmarshal returns an UnmarshalTypeError describing the earliest such error.
// In any case, it's not guaranteed that all the remaining fields following the problematic one will be unmarshaled into the target object.
func Unmarshal(data []byte, v interface{}) error {
var err error
var dec *Decoder
switch vt := v.(type) {
case *string:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeString(vt)
case **string:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeStringNull(vt)
case *int:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt(vt)
case **int:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeIntNull(vt)
case *int8:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt8(vt)
case **int8:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt8Null(vt)
case *int16:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt16(vt)
case **int16:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt16Null(vt)
case *int32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt32(vt)
case **int32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt32Null(vt)
case *int64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt64(vt)
case **int64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt64Null(vt)
case *uint8:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint8(vt)
case **uint8:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint8Null(vt)
case *uint16:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint16(vt)
case **uint16:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint16Null(vt)
case *uint32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint32(vt)
case **uint32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint32Null(vt)
case *uint64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint64(vt)
case **uint64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint64Null(vt)
case *float64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeFloat64(vt)
case **float64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeFloat64Null(vt)
case *float32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeFloat32(vt)
case **float32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeFloat32Null(vt)
case *bool:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeBool(vt)
case **bool:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeBoolNull(vt)
case UnmarshalerJSONObject:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = make([]byte, len(data))
copy(dec.data, data)
_, err = dec.decodeObject(vt)
case UnmarshalerJSONArray:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = make([]byte, len(data))
copy(dec.data, data)
_, err = dec.decodeArray(vt)
case *interface{}:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = make([]byte, len(data))
copy(dec.data, data)
err = dec.decodeInterface(vt)
default:
return InvalidUnmarshalError(fmt.Sprintf(invalidUnmarshalErrorMsg, vt))
}
defer dec.Release()
if err != nil {
return err
}
return dec.err
}
// UnmarshalerJSONObject is the interface to implement to decode a JSON Object.
type UnmarshalerJSONObject interface {
UnmarshalJSONObject(*Decoder, string) error
NKeys() int
}
// UnmarshalerJSONArray is the interface to implement to decode a JSON Array.
type UnmarshalerJSONArray interface {
UnmarshalJSONArray(*Decoder) error
}
// A Decoder reads and decodes JSON values from an input stream.
type Decoder struct {
r io.Reader
data []byte
err error
isPooled byte
called byte
child byte
cursor int
length int
keysDone int
arrayIndex int
}
// Decode reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
// The differences between Decode and Unmarshal are:
// - Decode reads from an io.Reader in the Decoder, whereas Unmarshal reads from a []byte
// - Decode leaves to the user the option of borrowing and releasing a Decoder, whereas Unmarshal internally always borrows a Decoder and releases it when the unmarshaling is completed
func (dec *Decoder) Decode(v interface{}) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
var err error
switch vt := v.(type) {
case *string:
err = dec.decodeString(vt)
case **string:
err = dec.decodeStringNull(vt)
case *int:
err = dec.decodeInt(vt)
case **int:
err = dec.decodeIntNull(vt)
case *int8:
err = dec.decodeInt8(vt)
case **int8:
err = dec.decodeInt8Null(vt)
case *int16:
err = dec.decodeInt16(vt)
case **int16:
err = dec.decodeInt16Null(vt)
case *int32:
err = dec.decodeInt32(vt)
case **int32:
err = dec.decodeInt32Null(vt)
case *int64:
err = dec.decodeInt64(vt)
case **int64:
err = dec.decodeInt64Null(vt)
case *uint8:
err = dec.decodeUint8(vt)
case **uint8:
err = dec.decodeUint8Null(vt)
case *uint16:
err = dec.decodeUint16(vt)
case **uint16:
err = dec.decodeUint16Null(vt)
case *uint32:
err = dec.decodeUint32(vt)
case **uint32:
err = dec.decodeUint32Null(vt)
case *uint64:
err = dec.decodeUint64(vt)
case **uint64:
err = dec.decodeUint64Null(vt)
case *float64:
err = dec.decodeFloat64(vt)
case **float64:
err = dec.decodeFloat64Null(vt)
case *float32:
err = dec.decodeFloat32(vt)
case **float32:
err = dec.decodeFloat32Null(vt)
case *bool:
err = dec.decodeBool(vt)
case **bool:
err = dec.decodeBoolNull(vt)
case UnmarshalerJSONObject:
_, err = dec.decodeObject(vt)
case UnmarshalerJSONArray:
_, err = dec.decodeArray(vt)
case *EmbeddedJSON:
err = dec.decodeEmbeddedJSON(vt)
case *interface{}:
err = dec.decodeInterface(vt)
default:
return InvalidUnmarshalError(fmt.Sprintf(invalidUnmarshalErrorMsg, vt))
}
if err != nil {
return err
}
return dec.err
}
// Non exported
func isDigit(b byte) bool {
switch b {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return true
default:
return false
}
}
func (dec *Decoder) read() bool {
if dec.r != nil {
// if we reach the end, double the buffer to ensure there's always more space
if len(dec.data) == dec.length {
nLen := dec.length * 2
if nLen == 0 {
nLen = 512
}
Buf := make([]byte, nLen, nLen)
copy(Buf, dec.data)
dec.data = Buf
}
var n int
var err error
for n == 0 {
n, err = dec.r.Read(dec.data[dec.length:])
if err != nil {
if err != io.EOF {
dec.err = err
return false
}
if n == 0 {
return false
}
dec.length = dec.length + n
return true
}
}
dec.length = dec.length + n
return true
}
return false
}
func (dec *Decoder) nextChar() byte {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
}
d := dec.data[dec.cursor]
return d
}
return 0
}
golang-github-francoispqt-gojay-1.2.13/decode_array.go 0000664 0000000 0000000 00000015052 13653316651 0022747 0 ustar 00root root 0000000 0000000 package gojay
import "reflect"
// DecodeArray reads the next JSON-encoded value from the decoder's input (io.Reader)
// and stores it in the value pointed to by v.
//
// v must implement UnmarshalerJSONArray.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeArray(v UnmarshalerJSONArray) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
_, err := dec.decodeArray(v)
return err
}
func (dec *Decoder) decodeArray(arr UnmarshalerJSONArray) (int, error) {
// remember last array index in case of nested arrays
lastArrayIndex := dec.arrayIndex
dec.arrayIndex = 0
defer func() {
dec.arrayIndex = lastArrayIndex
}()
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
case '[':
dec.cursor = dec.cursor + 1
// array is open, char is not space start readings
for dec.nextChar() != 0 {
// closing array
if dec.data[dec.cursor] == ']' {
dec.cursor = dec.cursor + 1
return dec.cursor, nil
}
// calling unmarshall function for each element of the slice
err := arr.UnmarshalJSONArray(dec)
if err != nil {
return 0, err
}
dec.arrayIndex++
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
case 'n':
// is null
dec.cursor++
err := dec.assertNull()
if err != nil {
return 0, err
}
return dec.cursor, nil
case '{', '"', 'f', 't', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
// can't unmarshall to struct
// we skip array and set Error
dec.err = dec.makeInvalidUnmarshalErr(arr)
err := dec.skipData()
if err != nil {
return 0, err
}
return dec.cursor, nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeArrayNull(v interface{}) (int, error) {
// remember last array index in case of nested arrays
lastArrayIndex := dec.arrayIndex
dec.arrayIndex = 0
defer func() {
dec.arrayIndex = lastArrayIndex
}()
vv := reflect.ValueOf(v)
vvt := vv.Type()
if vvt.Kind() != reflect.Ptr || vvt.Elem().Kind() != reflect.Ptr {
dec.err = ErrUnmarshalPtrExpected
return 0, dec.err
}
// not an array not an error, but do not know what to do
// do not check syntax
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
case '[':
dec.cursor = dec.cursor + 1
// create our new type
elt := vv.Elem()
n := reflect.New(elt.Type().Elem())
var arr UnmarshalerJSONArray
var ok bool
if arr, ok = n.Interface().(UnmarshalerJSONArray); !ok {
dec.err = dec.makeInvalidUnmarshalErr((UnmarshalerJSONArray)(nil))
return 0, dec.err
}
// array is open, char is not space start readings
for dec.nextChar() != 0 {
// closing array
if dec.data[dec.cursor] == ']' {
elt.Set(n)
dec.cursor = dec.cursor + 1
return dec.cursor, nil
}
// calling unmarshall function for each element of the slice
err := arr.UnmarshalJSONArray(dec)
if err != nil {
return 0, err
}
dec.arrayIndex++
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
case 'n':
// is null
dec.cursor++
err := dec.assertNull()
if err != nil {
return 0, err
}
return dec.cursor, nil
case '{', '"', 'f', 't', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
// can't unmarshall to struct
// we skip array and set Error
dec.err = dec.makeInvalidUnmarshalErr((UnmarshalerJSONArray)(nil))
err := dec.skipData()
if err != nil {
return 0, err
}
return dec.cursor, nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) skipArray() (int, error) {
var arraysOpen = 1
var arraysClosed = 0
// var stringOpen byte = 0
for j := dec.cursor; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case ']':
arraysClosed++
// everything is closed return
if arraysOpen == arraysClosed {
// add char to object data
return j + 1, nil
}
case '[':
arraysOpen++
case '"':
j++
var isInEscapeSeq bool
var isFirstQuote = true
for ; j < dec.length || dec.read(); j++ {
if dec.data[j] != '"' {
continue
}
if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) {
break
} else {
isInEscapeSeq = false
}
if isFirstQuote {
isFirstQuote = false
}
// loop backward and count how many anti slash found
// to see if string is effectively escaped
ct := 0
for i := j - 1; i > 0; i-- {
if dec.data[i] != '\\' {
break
}
ct++
}
// is pair number of slashes, quote is not escaped
if ct&1 == 0 {
break
}
isInEscapeSeq = true
}
default:
continue
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// DecodeArrayFunc is a func type implementing UnmarshalerJSONArray.
// Use it to cast a `func(*Decoder) error` to Unmarshal an array on the fly.
type DecodeArrayFunc func(*Decoder) error
// UnmarshalJSONArray implements UnmarshalerJSONArray.
func (f DecodeArrayFunc) UnmarshalJSONArray(dec *Decoder) error {
return f(dec)
}
// IsNil implements UnmarshalerJSONArray.
func (f DecodeArrayFunc) IsNil() bool {
return f == nil
}
// Add Values functions
// AddArray decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
func (dec *Decoder) AddArray(v UnmarshalerJSONArray) error {
return dec.Array(v)
}
// AddArrayNull decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
func (dec *Decoder) AddArrayNull(v interface{}) error {
return dec.ArrayNull(v)
}
// Array decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
func (dec *Decoder) Array(v UnmarshalerJSONArray) error {
newCursor, err := dec.decodeArray(v)
if err != nil {
return err
}
dec.cursor = newCursor
dec.called |= 1
return nil
}
// ArrayNull decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
// v should be a pointer to an UnmarshalerJSONArray,
// if `null` value is encountered in JSON, it will leave the value v untouched,
// else it will create a new instance of the UnmarshalerJSONArray behind v.
func (dec *Decoder) ArrayNull(v interface{}) error {
newCursor, err := dec.decodeArrayNull(v)
if err != nil {
return err
}
dec.cursor = newCursor
dec.called |= 1
return nil
}
// Index returns the index of an array being decoded.
func (dec *Decoder) Index() int {
return dec.arrayIndex
}
golang-github-francoispqt-gojay-1.2.13/decode_array_test.go 0000664 0000000 0000000 00000046410 13653316651 0024010 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
type testSliceInts []int
func (t *testSliceInts) UnmarshalJSONArray(dec *Decoder) error {
i := 0
if err := dec.AddInt(&i); err != nil {
return err
}
*t = append(*t, i)
return nil
}
func TestSliceInts(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testSliceInts
err bool
errType interface{}
}{
{
name: "basic-test",
json: "[1,2,3,43567788543,45777655,432,0]",
expectedResult: testSliceInts{1, 2, 3, 43567788543, 45777655, 432, 0},
},
{
name: "basic-test",
json: "[1,2,3,43567788543,null,432,0]",
expectedResult: testSliceInts{1, 2, 3, 43567788543, 0, 432, 0},
},
{
name: "empty",
json: "[]",
expectedResult: testSliceInts{},
},
{
name: "invalid-json",
json: "[",
expectedResult: testSliceInts{},
err: true,
},
{
name: "floats",
json: "[1,2,3,43567788543,457.7765,432,0,0.45]",
expectedResult: testSliceInts{1, 2, 3, 43567788543, 457, 432, 0, 0},
},
{
name: "invalid-type",
json: `[1,2,3,43567788543,457.7765,432,0,"test"]`,
expectedResult: testSliceInts{1, 2, 3, 43567788543, 457, 432, 0, 0},
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `[1,2,3",43567788543,457.7765,432,0,"test"]`,
expectedResult: testSliceInts{1, 2, 3, 43567788543, 457, 432, 0, 0},
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
s := make(testSliceInts, 0)
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
continue
}
for k, v := range testCase.expectedResult {
assert.Equal(t, v, s[k], "value at given index should be the same as expected results")
}
}
}
type testSliceStrings []string
func (t *testSliceStrings) UnmarshalJSONArray(dec *Decoder) error {
str := ""
if err := dec.AddString(&str); err != nil {
return err
}
*t = append(*t, str)
return nil
}
func TestSliceStrings(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testSliceStrings
err bool
errType interface{}
}{
{
name: "basic-test",
json: `["hello world", "hey" , "foo","bar"]`,
expectedResult: testSliceStrings{"hello world", "hey", "foo", "bar"},
},
{
name: "basic-test",
json: `["hello world", "hey" , "foo","bar \n escape"]`,
expectedResult: testSliceStrings{"hello world", "hey", "foo", "bar \n escape"},
},
{
name: "basic-test",
json: `["hello world", "hey" , null,"bar \n escape"]`,
expectedResult: testSliceStrings{"hello world", "hey", "", "bar \n escape"},
},
{
name: "invalid-type",
json: `["foo",1,2,3,"test"]`,
expectedResult: testSliceStrings{},
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `["hello world]`,
expectedResult: testSliceStrings{},
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := make(testSliceStrings, 0)
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
for k, v := range testCase.expectedResult {
assert.Equal(t, v, s[k], "value at given index should be the same as expected results")
}
})
}
}
type testSliceBools []bool
func (t *testSliceBools) UnmarshalJSONArray(dec *Decoder) error {
b := false
if err := dec.AddBool(&b); err != nil {
return err
}
*t = append(*t, b)
return nil
}
func TestSliceBools(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testSliceBools
err bool
errType interface{}
}{
{
name: "basic-test",
json: `[true, false, false, true, true, false]`,
expectedResult: testSliceBools{true, false, false, true, true, false},
},
{
name: "basic-test2",
json: `[true, false, false, true, null,null,true,false]`,
expectedResult: testSliceBools{true, false, false, true, false, false, true, false},
},
{
name: "invalid-type",
json: `["foo",1,2,3,"test"]`,
expectedResult: testSliceBools{},
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `["hello world]`,
expectedResult: testSliceBools{},
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := make(testSliceBools, 0)
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
for k, v := range testCase.expectedResult {
assert.Equal(t, v, s[k], "value at given index should be the same as expected results")
}
})
}
}
type testSliceSlicesSlices []testSliceInts
func (t *testSliceSlicesSlices) UnmarshalJSONArray(dec *Decoder) error {
sl := make(testSliceInts, 0)
if err := dec.AddArray(&sl); err != nil {
return err
}
*t = append(*t, sl)
return nil
}
func TestSliceSlices(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testSliceSlicesSlices
err bool
errType interface{}
}{
{
name: "basic-test",
json: `[[1,2],[1,2],[1,2]]`,
expectedResult: testSliceSlicesSlices{testSliceInts{1, 2}, testSliceInts{1, 2}, testSliceInts{1, 2}},
},
{
name: "basic-test",
json: `[[1,2],null,[1,2]]`,
expectedResult: testSliceSlicesSlices{testSliceInts{1, 2}, testSliceInts{}, testSliceInts{1, 2}},
},
{
name: "invalid-type",
json: `["foo",1,2,3,"test"]`,
expectedResult: testSliceSlicesSlices{},
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `["hello world]`,
expectedResult: testSliceSlicesSlices{},
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := make(testSliceSlicesSlices, 0)
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
for k, v := range testCase.expectedResult {
assert.Equal(t, v, s[k], "value at given index should be the same as expected results")
}
})
}
}
type testSliceObjects []*testObject
func (t *testSliceObjects) UnmarshalJSONArray(dec *Decoder) error {
obj := &testObject{}
*t = append(*t, obj)
return dec.AddObject(obj)
}
func TestSliceObjects(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testSliceObjects
err bool
errType interface{}
}{
{
name: "basic-test",
json: `[{"testStr":"foo bar","testInt":123},{"testStr":"foo bar","testInt":123}]`,
expectedResult: testSliceObjects{
&testObject{
testStr: "foo bar",
testInt: 123,
},
&testObject{
testStr: "foo bar",
testInt: 123,
},
},
},
{
name: "basic-test",
json: `[{"testStr":"foo bar","testInt":123},null,{"testStr":"foo bar","testInt":123}]`,
expectedResult: testSliceObjects{
&testObject{
testStr: "foo bar",
testInt: 123,
},
&testObject{},
&testObject{
testStr: "foo bar",
testInt: 123,
},
},
},
{
name: "invalid-type",
json: `["foo",1,2,3,"test"]`,
expectedResult: testSliceObjects{},
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `["hello world]`,
expectedResult: testSliceObjects{},
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := make(testSliceObjects, 0)
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
for k, v := range testCase.expectedResult {
assert.Equal(t, *v, *s[k], "value at given index should be the same as expected results")
}
})
}
}
type ArrayNull []string
func (a *ArrayNull) UnmarshalJSONArray(dec *Decoder) error {
var str string
if err := dec.String(&str); err != nil {
return err
}
*a = append(*a, str)
return nil
}
type ObjectArrayNull struct {
SubArray *ArrayNull
}
func (o *ObjectArrayNull) UnmarshalJSONObject(dec *Decoder, k string) error {
switch k {
case "subarray":
return dec.ArrayNull(&o.SubArray)
}
return nil
}
func (o *ObjectArrayNull) NKeys() int {
return 1
}
func TestDecodeArrayNullPtr(t *testing.T) {
t.Run("sub obj should not be nil", func(t *testing.T) {
var o = &ObjectArrayNull{}
var err = UnmarshalJSONObject([]byte(`{"subarray": ["test"]}`), o)
assert.Nil(t, err)
assert.NotNil(t, o.SubArray)
assert.Len(t, *o.SubArray, 1)
})
t.Run("sub array should be nil", func(t *testing.T) {
var o = &ObjectArrayNull{}
var err = UnmarshalJSONObject([]byte(`{"subarray": null}`), o)
assert.Nil(t, err)
assert.Nil(t, o.SubArray)
})
t.Run("sub array err, not closing arr", func(t *testing.T) {
var o = &ObjectArrayNull{}
var err = UnmarshalJSONObject([]byte(`{"subarray": [ `), o)
assert.NotNil(t, err)
})
t.Run("sub array err, invalid string", func(t *testing.T) {
var o = &ObjectArrayNull{}
var err = UnmarshalJSONObject([]byte(`{"subarray":[",]}`), o)
assert.NotNil(t, err)
})
t.Run("sub array err, invalid null", func(t *testing.T) {
var o = &ObjectArrayNull{}
var err = UnmarshalJSONObject([]byte(`{"subarray":nll}`), o)
assert.NotNil(t, err)
})
t.Run("sub array err, empty", func(t *testing.T) {
var o = &ObjectArrayNull{}
var err = UnmarshalJSONObject([]byte(`{"subarray":`), o)
assert.NotNil(t, err)
})
}
type testChannelArray chan *TestObj
func (c *testChannelArray) UnmarshalJSONArray(dec *Decoder) error {
obj := &TestObj{}
if err := dec.AddObject(obj); err != nil {
return err
}
*c <- obj
return nil
}
func TestDecoderSliceNull(t *testing.T) {
json := []byte(`null`)
v := &testSliceStrings{}
err := Unmarshal(json, v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, len(*v), 0, "v must be of len 0")
}
func TestDecodeSliceInvalidType(t *testing.T) {
result := testSliceObjects{}
err := UnmarshalJSONArray([]byte(`{}`), &result)
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUnmarshalError(""), err, "err should be of type InvalidUnmarshalError")
assert.Equal(t, "Cannot unmarshal JSON to type '*gojay.testSliceObjects'", err.Error(), "err should not be nil")
}
func TestDecoderChannelOfObjectsBasic(t *testing.T) {
json := []byte(`[
{
"test": 245,
"test2": -246,
"test3": "string"
},
{
"test": 247,
"test2": 248,
"test3": "string"
},
{
"test": 777,
"test2": 456,
"test3": "string"
}
]`)
testChan := testChannelArray(make(chan *TestObj, 3))
err := UnmarshalJSONArray(json, &testChan)
assert.Nil(t, err, "Err must be nil")
ct := 0
l := len(testChan)
for range testChan {
ct++
if ct == l {
break
}
}
assert.Equal(t, ct, 3)
}
func TestDecoderSliceInvalidJSON(t *testing.T) {
json := []byte(`hello`)
testArr := testSliceInts{}
err := UnmarshalJSONArray(json, &testArr)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}
func TestDecoderSliceDecoderAPI(t *testing.T) {
json := `["string","string1"]`
testArr := testSliceStrings{}
dec := NewDecoder(strings.NewReader(json))
err := dec.DecodeArray(&testArr)
assert.Nil(t, err, "Err must be nil")
assert.Len(t, testArr, 2, "testArr should be of len 2")
assert.Equal(t, "string", testArr[0], "testArr[0] should be 'string'")
assert.Equal(t, "string1", testArr[1], "testArr[1] should be 'string1'")
}
func TestDecoderSliceDecoderAPIError(t *testing.T) {
testArr := testSliceInts{}
dec := NewDecoder(strings.NewReader(`hello`))
err := dec.DecodeArray(&testArr)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}
func TestUnmarshalJSONArrays(t *testing.T) {
testCases := []struct {
name string
v UnmarshalerJSONArray
d []byte
expectations func(err error, v interface{}, t *testing.T)
}{
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 1, "len of vt must be 1")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"},{"test":"test2"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 2, "len of vt must be 2")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
assert.Equal(t, "test2", vt[1].test, "vt[1].test must be equal to 'test2'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`invalid json`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(*testing.T) {
err := UnmarshalJSONArray(testCase.d, testCase.v)
testCase.expectations(err, testCase.v, t)
})
}
}
func TestSkipArray(t *testing.T) {
testCases := []struct {
name string
json string
expectations func(*testing.T, int, error)
}{
{
name: "basic",
json: `"testbasic"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"testbasic"]`), i)
assert.Nil(t, err)
},
},
{
name: "complex escape string",
json: `"test \\\\\" escape"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"test \\\\\" escape"]`), i)
assert.Nil(t, err)
},
},
{
name: "complex escape slash",
json: `"test \\\\\\"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"test \\\\\\"]`), i)
assert.Nil(t, err)
},
},
{
json: `"test \n"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"test \n"]`), i)
assert.Nil(t, err)
},
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
dec := NewDecoder(strings.NewReader(test.json))
i, err := dec.skipArray()
test.expectations(t, i, err)
})
}
}
func TestDecodeArrayEmpty(t *testing.T) {
v := new(testDecodeSlice)
dec := NewDecoder(strings.NewReader(""))
err := dec.Decode(v)
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
}
func TestDecodeArraySkipError(t *testing.T) {
v := new(testDecodeSlice)
dec := NewDecoder(strings.NewReader("34fef"))
err := dec.Decode(v)
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
}
func TestDecodeArrayNullError(t *testing.T) {
v := new(testDecodeSlice)
dec := NewDecoder(strings.NewReader("nall"))
err := dec.Decode(v)
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
}
func TestDecoderArrayFunc(t *testing.T) {
var f DecodeArrayFunc
assert.True(t, f.IsNil())
}
type testArrayStrings [3]string
func (a *testArrayStrings) UnmarshalJSONArray(dec *Decoder) error {
var str string
if err := dec.String(&str); err != nil {
return err
}
a[dec.Index()] = str
return nil
}
func TestArrayStrings(t *testing.T) {
data := []byte(`["a", "b", "c"]`)
arr := testArrayStrings{}
err := Unmarshal(data, &arr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "a", arr[0], "arr[0] must be equal to 'a'")
assert.Equal(t, "b", arr[1], "arr[1] must be equal to 'b'")
assert.Equal(t, "c", arr[2], "arr[2] must be equal to 'c'")
}
type testSliceArraysStrings struct {
arrays []testArrayStrings
t *testing.T
}
func (s *testSliceArraysStrings) UnmarshalJSONArray(dec *Decoder) error {
var a testArrayStrings
assert.Equal(s.t, len(s.arrays), dec.Index(), "decoded array index must be equal to current slice len")
if err := dec.AddArray(&a); err != nil {
return err
}
assert.Equal(s.t, len(s.arrays), dec.Index(), "decoded array index must be equal to current slice len")
s.arrays = append(s.arrays, a)
return nil
}
func TestIndex(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult []testArrayStrings
}{
{
name: "basic-test",
json: `[["a","b","c"],["1","2","3"],["x","y","z"]]`,
expectedResult: []testArrayStrings{{"a", "b", "c"}, {"1", "2", "3"}, {"x", "y", "z"}},
},
{
name: "basic-test-null",
json: `[["a","b","c"],null,["x","y","z"]]`,
expectedResult: []testArrayStrings{{"a", "b", "c"}, {"", "", ""}, {"x", "y", "z"}},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := make([]testArrayStrings, 0)
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
a := testSliceArraysStrings{arrays: s, t: t}
err := dec.Decode(&a)
assert.Nil(t, err, "err should be nil")
assert.Zero(t, dec.Index(), "Index() must return zero after decoding")
for k, v := range testCase.expectedResult {
assert.Equal(t, v, a.arrays[k], "value at given index should be the same as expected results")
}
})
}
}
golang-github-francoispqt-gojay-1.2.13/decode_bool.go 0000664 0000000 0000000 00000012533 13653316651 0022565 0 ustar 00root root 0000000 0000000 package gojay
// DecodeBool reads the next JSON-encoded value from the decoder's input (io.Reader)
// and stores it in the boolean pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeBool(v *bool) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeBool(v)
}
func (dec *Decoder) decodeBool(v *bool) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
case 't':
dec.cursor++
err := dec.assertTrue()
if err != nil {
return err
}
*v = true
return nil
case 'f':
dec.cursor++
err := dec.assertFalse()
if err != nil {
return err
}
*v = false
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
*v = false
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return nil
}
func (dec *Decoder) decodeBoolNull(v **bool) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
case 't':
dec.cursor++
err := dec.assertTrue()
if err != nil {
return err
}
if *v == nil {
*v = new(bool)
}
**v = true
return nil
case 'f':
dec.cursor++
err := dec.assertFalse()
if err != nil {
return err
}
if *v == nil {
*v = new(bool)
}
**v = false
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return nil
}
func (dec *Decoder) assertTrue() error {
i := 0
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch i {
case 0:
if dec.data[dec.cursor] != 'r' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 1:
if dec.data[dec.cursor] != 'u' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 2:
if dec.data[dec.cursor] != 'e' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 3:
switch dec.data[dec.cursor] {
case ' ', '\b', '\t', '\n', ',', ']', '}':
// dec.cursor--
return nil
default:
return dec.raiseInvalidJSONErr(dec.cursor)
}
}
i++
}
if i == 3 {
return nil
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) assertNull() error {
i := 0
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch i {
case 0:
if dec.data[dec.cursor] != 'u' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 1:
if dec.data[dec.cursor] != 'l' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 2:
if dec.data[dec.cursor] != 'l' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 3:
switch dec.data[dec.cursor] {
case ' ', '\t', '\n', ',', ']', '}':
// dec.cursor--
return nil
default:
return dec.raiseInvalidJSONErr(dec.cursor)
}
}
i++
}
if i == 3 {
return nil
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) assertFalse() error {
i := 0
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch i {
case 0:
if dec.data[dec.cursor] != 'a' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 1:
if dec.data[dec.cursor] != 'l' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 2:
if dec.data[dec.cursor] != 's' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 3:
if dec.data[dec.cursor] != 'e' {
return dec.raiseInvalidJSONErr(dec.cursor)
}
case 4:
switch dec.data[dec.cursor] {
case ' ', '\t', '\n', ',', ']', '}':
// dec.cursor--
return nil
default:
return dec.raiseInvalidJSONErr(dec.cursor)
}
}
i++
}
if i == 4 {
return nil
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
// Add Values functions
// AddBool decodes the JSON value within an object or an array to a *bool.
// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned.
// If next key is null, bool will be false.
func (dec *Decoder) AddBool(v *bool) error {
return dec.Bool(v)
}
// AddBoolNull decodes the JSON value within an object or an array to a *bool.
// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned.
// If next key is null, bool will be false.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddBoolNull(v **bool) error {
return dec.BoolNull(v)
}
// Bool decodes the JSON value within an object or an array to a *bool.
// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned.
// If next key is null, bool will be false.
func (dec *Decoder) Bool(v *bool) error {
err := dec.decodeBool(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// BoolNull decodes the JSON value within an object or an array to a *bool.
// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned.
// If next key is null, bool will be false.
func (dec *Decoder) BoolNull(v **bool) error {
err := dec.decodeBoolNull(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_bool_test.go 0000664 0000000 0000000 00000036052 13653316651 0023626 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecoderBool(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult bool
expectations func(t *testing.T, v bool, err error)
}{
{
name: "true-basic",
json: "true",
expectations: func(t *testing.T, v bool, err error) {
assert.Nil(t, err, "err should be nil")
assert.True(t, v, "result should be true")
},
},
{
name: "false-basic",
json: "false",
expectations: func(t *testing.T, v bool, err error) {
assert.Nil(t, err, "err should be nil")
assert.False(t, v, "result should be false")
},
},
{
name: "null-basic",
json: "null",
expectations: func(t *testing.T, v bool, err error) {
assert.Nil(t, err, "err should be nil")
assert.False(t, v, "result should be false")
},
},
{
name: "true-error",
json: "taue",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "true-error2",
json: "trae",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "true-error3",
json: "trua",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "true-error4",
json: "truea",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "true-error5",
json: "t",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "true-error6",
json: "a",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "false-error",
json: "fulse",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "false-error2",
json: "fause",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "false-error3",
json: "falze",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "false-error4",
json: "falso",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "false-error5",
json: "falsea",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "false-error6",
json: "f",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "false-error7",
json: "a",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-error",
json: "nall",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-error2",
json: "nual",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-error3",
json: "nula",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-error4",
json: "nulle",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-error5",
json: "n",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-error6",
json: "a",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-skip",
json: "{}",
expectations: func(t *testing.T, v bool, err error) {
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUnmarshalError(""), err, "err should be of type InvalidUnmarshalError")
assert.False(t, v, "result should be false")
},
},
{
name: "null-skip",
json: "",
expectations: func(t *testing.T, v bool, err error) {
assert.Nil(t, err, "err should not be nil")
assert.False(t, v, "result should be false")
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v bool
err := Unmarshal(json, &v)
testCase.expectations(t, v, err)
})
}
}
func TestDecoderBoolNull(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult bool
expectations func(t *testing.T, v *bool, err error)
}{
{
name: "true-basic",
json: "true",
expectations: func(t *testing.T, v *bool, err error) {
assert.Nil(t, err, "err should be nil")
assert.True(t, *v, "result should be true")
},
},
{
name: "false-basic",
json: "false",
expectations: func(t *testing.T, v *bool, err error) {
assert.Nil(t, err, "err should be nil")
assert.False(t, *v, "result should be false")
},
},
{
name: "null-basic",
json: "null",
expectations: func(t *testing.T, v *bool, err error) {
assert.Nil(t, err, "err should be nil")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "true-error",
json: "taue",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be false")
},
},
{
name: "true-error2",
json: "trae",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "true-error3",
json: "trua",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "true-error4",
json: "truea",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "true-error5",
json: "t",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "true-error6",
json: "a",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "false-error",
json: "fulse",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "false-error2",
json: "fause",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "false-error3",
json: "falze",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "false-error4",
json: "falso",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "false-error5",
json: "falsea",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "false-error6",
json: "f",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "false-error7",
json: "a",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-error",
json: "nall",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-error2",
json: "nual",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-error3",
json: "nula",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-error4",
json: "nulle",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-error5",
json: "n",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-error6",
json: "a",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-skip",
json: "{}",
expectations: func(t *testing.T, v *bool, err error) {
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUnmarshalError(""), err, "err should be of type InvalidUnmarshalError")
assert.Nil(t, v, "result should be nil")
},
},
{
name: "null-skip",
json: "",
expectations: func(t *testing.T, v *bool, err error) {
assert.Nil(t, err, "err should not be nil")
assert.Nil(t, v, "result should be nil")
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var v = struct {
b *bool
}{}
err := Unmarshal([]byte(testCase.json), &v.b)
testCase.expectations(t, v.b, err)
})
}
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(bool)
var dec = NewDecoder(strings.NewReader(`folse`))
err := dec.BoolNull(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderBoolDecoderAPI(t *testing.T) {
var v bool
dec := BorrowDecoder(strings.NewReader("true"))
defer dec.Release()
err := dec.DecodeBool(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, true, v, "v must be equal to true")
}
func TestDecoderBoolPoolError(t *testing.T) {
v := true
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeBool(&v)
assert.True(t, false, "should not be called as decoder should have panicked")
}
golang-github-francoispqt-gojay-1.2.13/decode_embedded_json.go 0000664 0000000 0000000 00000004167 13653316651 0024420 0 ustar 00root root 0000000 0000000 package gojay
// EmbeddedJSON is a raw encoded JSON value.
// It can be used to delay JSON decoding or precompute a JSON encoding.
type EmbeddedJSON []byte
func (dec *Decoder) decodeEmbeddedJSON(ej *EmbeddedJSON) error {
var err error
if ej == nil {
return InvalidUnmarshalError("Invalid nil pointer given")
}
var beginOfEmbeddedJSON int
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
// is null
case 'n':
beginOfEmbeddedJSON = dec.cursor
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
case 't':
beginOfEmbeddedJSON = dec.cursor
dec.cursor++
err := dec.assertTrue()
if err != nil {
return err
}
// is false
case 'f':
beginOfEmbeddedJSON = dec.cursor
dec.cursor++
err := dec.assertFalse()
if err != nil {
return err
}
// is an object
case '{':
beginOfEmbeddedJSON = dec.cursor
dec.cursor = dec.cursor + 1
dec.cursor, err = dec.skipObject()
// is string
case '"':
beginOfEmbeddedJSON = dec.cursor
dec.cursor = dec.cursor + 1
err = dec.skipString() // why no new dec.cursor in result?
// is array
case '[':
beginOfEmbeddedJSON = dec.cursor
dec.cursor = dec.cursor + 1
dec.cursor, err = dec.skipArray()
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
beginOfEmbeddedJSON = dec.cursor
dec.cursor, err = dec.skipNumber()
}
break
}
if err == nil {
if dec.cursor-1 >= beginOfEmbeddedJSON {
*ej = append(*ej, dec.data[beginOfEmbeddedJSON:dec.cursor]...)
}
dec.called |= 1
}
return err
}
// AddEmbeddedJSON adds an EmbeddedsJSON to the value pointed by v.
// It can be used to delay JSON decoding or precompute a JSON encoding.
func (dec *Decoder) AddEmbeddedJSON(v *EmbeddedJSON) error {
return dec.EmbeddedJSON(v)
}
// EmbeddedJSON adds an EmbeddedsJSON to the value pointed by v.
// It can be used to delay JSON decoding or precompute a JSON encoding.
func (dec *Decoder) EmbeddedJSON(v *EmbeddedJSON) error {
err := dec.decodeEmbeddedJSON(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_embedded_json_test.go 0000664 0000000 0000000 00000012616 13653316651 0025455 0 ustar 00root root 0000000 0000000 package gojay
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
type Request struct {
id string
method string
params EmbeddedJSON
more int
}
func (r *Request) UnmarshalJSONObject(dec *Decoder, key string) error {
switch key {
case "id":
return dec.AddString(&r.id)
case "method":
return dec.AddString(&r.method)
case "params":
return dec.AddEmbeddedJSON(&r.params)
case "more":
dec.AddInt(&r.more)
}
return nil
}
func (r *Request) NKeys() int {
return 4
}
func TestDecodeEmbeddedJSONUnmarshalAPI(t *testing.T) {
testCases := []struct {
name string
json []byte
expectedEmbedded string
err bool
}{
{
name: "decode-basic-string",
json: []byte(`{"id":"someid","method":"getmydata","params":"raw data", "more":123}`),
expectedEmbedded: `"raw data"`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params":12345, "more":123}`),
expectedEmbedded: `12345`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params":true, "more":123}`),
expectedEmbedded: `true`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params": false, "more":123}`),
expectedEmbedded: `false`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params":null, "more":123}`),
expectedEmbedded: `null`,
},
{
name: "decode-basic-object",
json: []byte(`{"id":"someid","method":"getmydata","params":{"example":"of raw data"}, "more":123}`),
expectedEmbedded: `{"example":"of raw data"}`,
},
{
name: "decode-basic-object",
json: []byte(`{"id":"someid","method":"getmydata","params":[1,2,3], "more":123}`),
expectedEmbedded: `[1,2,3]`,
},
{
name: "decode-null-err",
json: []byte(`{"id":"someid","method":"getmydata","params":nil, "more":123}`),
expectedEmbedded: ``,
err: true,
},
{
name: "decode-bool-false-err",
json: []byte(`{"id":"someid","method":"getmydata","params":faulse, "more":123}`),
expectedEmbedded: ``,
err: true,
},
{
name: "decode-bool-true-err",
json: []byte(`{"id":"someid","method":"getmydata","params":trou, "more":123}`),
expectedEmbedded: ``,
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
req := &Request{}
err := Unmarshal(testCase.json, req)
t.Log(req)
t.Log(string(req.params))
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
} else {
assert.Nil(t, err, "err should be nil")
}
assert.Equal(t, testCase.expectedEmbedded, string(req.params), "r.params should be equal to expectedEmbeddedResult")
})
}
}
func TestDecodeEmbeddedJSONDecodeAPI(t *testing.T) {
testCases := []struct {
name string
json []byte
expectedEmbedded string
}{
{
name: "decode-basic-string",
json: []byte(`{"id":"someid","method":"getmydata","params":"raw data", "more":123}`),
expectedEmbedded: `"raw data"`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params":12345, "more":123}`),
expectedEmbedded: `12345`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params":true, "more":123}`),
expectedEmbedded: `true`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params": false, "more":123}`),
expectedEmbedded: `false`,
},
{
name: "decode-basic-int",
json: []byte(`{"id":"someid","method":"getmydata","params":null, "more":123}`),
expectedEmbedded: `null`,
},
{
name: "decode-basic-object",
json: []byte(`{"id":"someid","method":"getmydata","params":{"example":"of raw data"}, "more":123}`),
expectedEmbedded: `{"example":"of raw data"}`,
},
{
name: "decode-basic-object",
json: []byte(`{"id":"someid","method":"getmydata","params":[1,2,3], "more":123}`),
expectedEmbedded: `[1,2,3]`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
ej := EmbeddedJSON([]byte{})
dec := BorrowDecoder(bytes.NewReader(testCase.json))
err := dec.Decode(&ej)
assert.Nil(t, err, "err should be nil")
assert.Equal(t, string(testCase.json), string(ej), "r.params should be equal to expectedEmbeddedResult")
})
}
}
func TestDecodeEmbeededJSONNil(t *testing.T) {
dec := BorrowDecoder(strings.NewReader(`"bar"`))
var ej *EmbeddedJSON
err := dec.decodeEmbeddedJSON(ej)
assert.NotNil(t, err, `err should not be nil a nil pointer is given`)
assert.IsType(t, InvalidUnmarshalError(""), err, `err should not be of type InvalidUnmarshalError`)
}
func TestDecodeEmbeededJSONNil2(t *testing.T) {
dec := BorrowDecoder(strings.NewReader(`"bar"`))
var ej *EmbeddedJSON
err := dec.AddEmbeddedJSON(ej)
assert.NotNil(t, err, `err should not be nil a nil pointer is given`)
assert.IsType(t, InvalidUnmarshalError(""), err, `err should not be of type InvalidUnmarshalError`)
}
golang-github-francoispqt-gojay-1.2.13/decode_example_test.go 0000664 0000000 0000000 00000005032 13653316651 0024320 0 ustar 00root root 0000000 0000000 package gojay_test
import (
"fmt"
"log"
"strings"
"github.com/francoispqt/gojay"
)
func ExampleUnmarshal_string() {
data := []byte(`"gojay"`)
var str string
err := gojay.Unmarshal(data, &str)
if err != nil {
log.Fatal(err)
}
fmt.Println(str) // true
}
func ExampleUnmarshal_bool() {
data := []byte(`true`)
var b bool
err := gojay.Unmarshal(data, &b)
if err != nil {
log.Fatal(err)
}
fmt.Println(b) // true
}
func ExampleUnmarshal_invalidType() {
data := []byte(`"gojay"`)
someStruct := struct{}{}
err := gojay.Unmarshal(data, &someStruct)
fmt.Println(err) // "Cannot unmarshal JSON to type '*struct{}'"
}
func ExampleDecoder_Decode_string() {
var str string
dec := gojay.BorrowDecoder(strings.NewReader(`"gojay"`))
err := dec.Decode(&str)
dec.Release()
if err != nil {
log.Fatal(err)
}
fmt.Println(str) // "gojay"
}
func ExampleDecodeObjectFunc() {
reader := strings.NewReader(`{
"name": "John Doe",
"email": "john.doe@email.com"
}`)
dec := gojay.NewDecoder(reader)
user := struct {
name string
email string
}{}
dec.DecodeObject(gojay.DecodeObjectFunc(func(dec *gojay.Decoder, k string) error {
switch k {
case "name":
return dec.String(&user.name)
case "email":
return dec.String(&user.email)
}
return nil
}))
fmt.Printf("User\nname: %s\nemail: %s", user.name, user.email)
// Output:
// User
// name: John Doe
// email: john.doe@email.com
}
func ExampleDecodeArrayFunc() {
reader := strings.NewReader(`[
"foo",
"bar"
]`)
dec := gojay.NewDecoder(reader)
strSlice := make([]string, 0)
err := dec.DecodeArray(gojay.DecodeArrayFunc(func(dec *gojay.Decoder) error {
var str string
if err := dec.AddString(&str); err != nil {
return err
}
strSlice = append(strSlice, str)
return nil
}))
if err != nil {
log.Fatal(err)
}
fmt.Print(strSlice)
// Output:
// [foo bar]
}
func ExampleNewDecoder() {
reader := strings.NewReader(`"gojay"`)
dec := gojay.NewDecoder(reader)
var str string
err := dec.DecodeString(&str)
if err != nil {
log.Fatal(err)
}
fmt.Println(str)
// Output:
// gojay
}
func ExampleBorrowDecoder() {
reader := strings.NewReader(`"gojay"`)
dec := gojay.BorrowDecoder(reader)
defer dec.Release()
var str string
err := dec.DecodeString(&str)
if err != nil {
log.Fatal(err)
}
fmt.Println(str)
// Output:
// gojay
}
func ExampleDecoder_DecodeBool() {
reader := strings.NewReader(`true`)
dec := gojay.NewDecoder(reader)
var b bool
err := dec.DecodeBool(&b)
if err != nil {
log.Fatal(err)
}
fmt.Println(b)
// Output:
// true
}
golang-github-francoispqt-gojay-1.2.13/decode_interface.go 0000664 0000000 0000000 00000005535 13653316651 0023576 0 ustar 00root root 0000000 0000000 package gojay
// TODO @afiune for now we are using the standard json unmarshaling but in
// the future it would be great to implement one here inside this repo
import "encoding/json"
// DecodeInterface reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by i.
//
// i must be an interface poiter
func (dec *Decoder) DecodeInterface(i *interface{}) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
err := dec.decodeInterface(i)
return err
}
func (dec *Decoder) decodeInterface(i *interface{}) error {
start, end, err := dec.getObject()
if err != nil {
dec.cursor = start
return err
}
// if start & end are equal the object is a null, don't unmarshal
if start == end {
return nil
}
object := dec.data[start:end]
if err = json.Unmarshal(object, i); err != nil {
return err
}
dec.cursor = end
return nil
}
// @afiune Maybe return the type as well?
func (dec *Decoder) getObject() (start int, end int, err error) {
// start cursor
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
// is null
case 'n':
dec.cursor++
err = dec.assertNull()
if err != nil {
return
}
// Set start & end to the same cursor to indicate the object
// is a null and should not be unmarshal
start = dec.cursor
end = dec.cursor
return
case 't':
start = dec.cursor
dec.cursor++
err = dec.assertTrue()
if err != nil {
return
}
end = dec.cursor
dec.cursor++
return
// is false
case 'f':
start = dec.cursor
dec.cursor++
err = dec.assertFalse()
if err != nil {
return
}
end = dec.cursor
dec.cursor++
return
// is an object
case '{':
start = dec.cursor
dec.cursor++
end, err = dec.skipObject()
dec.cursor = end
return
// is string
case '"':
start = dec.cursor
dec.cursor++
start, end, err = dec.getString()
start--
dec.cursor = end
return
// is array
case '[':
start = dec.cursor
dec.cursor++
end, err = dec.skipArray()
dec.cursor = end
return
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
start = dec.cursor
end, err = dec.skipNumber()
dec.cursor = end
return
default:
err = dec.raiseInvalidJSONErr(dec.cursor)
return
}
}
err = dec.raiseInvalidJSONErr(dec.cursor)
return
}
// Add Values functions
// AddInterface decodes the JSON value within an object or an array to a interface{}.
func (dec *Decoder) AddInterface(v *interface{}) error {
return dec.Interface(v)
}
// Interface decodes the JSON value within an object or an array to an interface{}.
func (dec *Decoder) Interface(value *interface{}) error {
err := dec.decodeInterface(value)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_interface_test.go 0000664 0000000 0000000 00000031614 13653316651 0024632 0 ustar 00root root 0000000 0000000 package gojay
import (
"encoding/json"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeInterfaceBasic(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult interface{}
err bool
errType interface{}
skipCheckResult bool
}{
{
name: "array",
json: `[1,2,3]`,
expectedResult: []interface{}([]interface{}{float64(1), float64(2), float64(3)}),
err: false,
},
{
name: "object",
json: `{"testStr": "hello world!"}`,
expectedResult: map[string]interface{}(map[string]interface{}{"testStr": "hello world!"}),
err: false,
},
{
name: "string",
json: `"hola amigos!"`,
expectedResult: interface{}("hola amigos!"),
err: false,
},
{
name: "bool-true",
json: `true`,
expectedResult: interface{}(true),
err: false,
},
{
name: "bool-false",
json: `false`,
expectedResult: interface{}(false),
err: false,
},
{
name: "null",
json: `null`,
expectedResult: interface{}(nil),
err: false,
},
{
name: "number",
json: `1234`,
expectedResult: interface{}(float64(1234)),
err: false,
},
{
name: "array-error",
json: `["h""o","l","a"]`,
err: true,
errType: &json.SyntaxError{},
skipCheckResult: true,
},
{
name: "object-error",
json: `{"testStr" "hello world!"}`,
err: true,
errType: &json.SyntaxError{},
skipCheckResult: true,
},
{
name: "string-error",
json: `"hola amigos!`,
err: true,
errType: InvalidJSONError(""),
skipCheckResult: true,
},
{
name: "bool-true-error",
json: `truee`,
err: true,
errType: InvalidJSONError(""),
skipCheckResult: true,
},
{
name: "bool-false-error",
json: `fase`,
expectedResult: interface{}(false),
err: true,
errType: InvalidJSONError(""),
skipCheckResult: true,
},
{
name: "null-error",
json: `nulllll`,
err: true,
errType: InvalidJSONError(""),
skipCheckResult: true,
},
{
name: "number-error",
json: `1234"`,
err: true,
errType: InvalidJSONError(""),
skipCheckResult: true,
},
{
name: "unknown-error",
json: `?`,
err: true,
errType: InvalidJSONError(""),
skipCheckResult: true,
},
{
name: "empty-json-error",
json: ``,
err: true,
errType: InvalidJSONError(""),
skipCheckResult: true,
},
}
for _, testCase := range testCases {
t.Run("DecodeInterface()"+testCase.name, func(t *testing.T) {
var i interface{}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.DecodeInterface(&i)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, i, "value at given index should be the same as expected results")
}
})
}
for _, testCase := range testCases {
t.Run("Decode()"+testCase.name, func(t *testing.T) {
var i interface{}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&i)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, i, "value at given index should be the same as expected results")
}
})
}
}
func TestDecodeInterfaceAsInterface(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult interface{}
err bool
errType interface{}
skipCheckResult bool
}{
{
name: "basic-array",
json: `{
"testStr": "hola",
"testInterface": ["h","o","l","a"]
}`,
expectedResult: map[string]interface{}(
map[string]interface{}{
"testStr": "hola",
"testInterface": []interface{}{"h", "o", "l", "a"},
}),
err: false,
},
{
name: "basic-string",
json: `{
"testInterface": "æ¼¢å—"
}`,
expectedResult: map[string]interface{}(
map[string]interface{}{
"testInterface": "æ¼¢å—",
}),
err: false,
},
{
name: "basic-error",
json: `{
"testInterface": ["a""d","i","o","s"]
}`,
err: true,
errType: &json.SyntaxError{},
skipCheckResult: true,
},
{
name: "basic-interface",
json: `{
"testInterface": {
"string": "prost"
}
}`,
expectedResult: map[string]interface{}(
map[string]interface{}{
"testInterface": map[string]interface{}{"string": "prost"},
}),
err: false,
},
{
name: "complex-interface",
json: `{
"testInterface": {
"number": 1988,
"string": "prost",
"array": ["h","o","l","a"],
"object": {
"k": "v",
"a": [1,2,3]
},
"array-of-objects": [
{"k": "v"},
{"a": "b"}
]
}
}`,
expectedResult: map[string]interface{}(
map[string]interface{}{
"testInterface": map[string]interface{}{
"array-of-objects": []interface{}{
map[string]interface{}{"k": "v"},
map[string]interface{}{"a": "b"},
},
"number": float64(1988),
"string": "prost",
"array": []interface{}{"h", "o", "l", "a"},
"object": map[string]interface{}{
"k": "v",
"a": []interface{}{float64(1), float64(2), float64(3)},
},
},
}),
err: false,
},
}
for _, testCase := range testCases {
t.Run("Decode()"+testCase.name, func(t *testing.T) {
var s interface{}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
}
})
}
for _, testCase := range testCases {
t.Run("DecodeInterface()"+testCase.name, func(t *testing.T) {
var s interface{}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.DecodeInterface(&s)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
}
})
}
}
func TestDecodeAsTestObject(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testObject
err bool
errType interface{}
skipCheckResult bool
}{
{
name: "basic-array",
json: `{
"testStr": "hola",
"testInterface": ["h","o","l","a"]
}`,
expectedResult: testObject{
testStr: "hola",
testInterface: []interface{}([]interface{}{"h", "o", "l", "a"}),
},
err: false,
},
{
name: "basic-string",
json: `{
"testInterface": "æ¼¢å—"
}`,
expectedResult: testObject{
testInterface: interface{}("æ¼¢å—"),
},
err: false,
},
{
name: "basic-error",
json: `{
"testInterface": ["a""d","i","o","s"]
}`,
err: true,
errType: &json.SyntaxError{},
skipCheckResult: true,
},
{
name: "mull-interface",
json: `{
"testInterface": null,
"testStr": "adios"
}`,
expectedResult: testObject{
testInterface: interface{}(nil),
testStr: "adios",
},
err: false,
},
{
name: "basic-interface",
json: `{
"testInterface": {
"string": "prost"
},
}`,
expectedResult: testObject{
testInterface: map[string]interface{}{"string": "prost"},
},
err: false,
},
{
name: "complex-interface",
json: `{
"testInterface": {
"number": 1988,
"string": "prost",
"array": ["h","o","l","a"],
"object": {
"k": "v",
"a": [1,2,3]
},
"array-of-objects": [
{"k": "v"},
{"a": "b"}
]
},
}`,
expectedResult: testObject{
testInterface: map[string]interface{}{
"array-of-objects": []interface{}{
map[string]interface{}{"k": "v"},
map[string]interface{}{"a": "b"},
},
"number": float64(1988),
"string": "prost",
"array": []interface{}{"h", "o", "l", "a"},
"object": map[string]interface{}{
"k": "v",
"a": []interface{}{float64(1), float64(2), float64(3)},
},
},
},
err: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := testObject{}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
}
})
}
}
func TestUnmarshalInterface(t *testing.T) {
json := []byte(`{
"testInterface": {
"number": 1988,
"null": null,
"string": "prost",
"array": ["h","o","l","a"],
"object": {
"k": "v",
"a": [1,2,3]
},
"array-of-objects": [
{"k": "v"},
{"a": "b"}
]
}
}`)
v := &testObject{}
err := Unmarshal(json, v)
assert.Nil(t, err, "Err must be nil")
expectedInterface := map[string]interface{}{
"array-of-objects": []interface{}{
map[string]interface{}{"k": "v"},
map[string]interface{}{"a": "b"},
},
"number": float64(1988),
"string": "prost",
"null": interface{}(nil),
"array": []interface{}{"h", "o", "l", "a"},
"object": map[string]interface{}{
"k": "v",
"a": []interface{}{float64(1), float64(2), float64(3)},
},
}
assert.Equal(t, expectedInterface, v.testInterface, "v.testInterface must be equal to the expected one")
}
func TestUnmarshalInterfaceError(t *testing.T) {
testCases := []struct {
name string
json []byte
}{
{
name: "basic",
json: []byte(`{"testInterface": {"number": 1bc4}}`),
},
{
name: "syntax",
json: []byte(`{
"testInterface": {
"array?": [1,"a", ?]
}
}`),
},
{
name: "complex",
json: []byte(`{
"testInterface": {
"number": 1988,
"string": "prost",
"array": ["h""o","l","a"],
"object": {
"k": "v",
"a": [1,2,3]
},
"array-of-objects": [
{"k": "v"},
{"a": "b"}
]
}
}`),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
v := &testObject{}
err := Unmarshal(testCase.json, v)
assert.NotNil(t, err, "Err must be not nil")
t.Log(err)
assert.IsType(t, &json.SyntaxError{}, err, "err should be a json.SyntaxError{}")
})
}
}
func TestDecodeInterfacePoolError(t *testing.T) {
result := interface{}(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeInterface(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
}
func TestDecodeNull(t *testing.T) {
var i interface{}
dec := BorrowDecoder(strings.NewReader("null"))
defer dec.Release()
err := dec.DecodeInterface(&i)
assert.Nil(t, err, "err should be nil")
assert.Equal(t, interface{}(nil), i, "value at given index should be the same as expected results")
}
golang-github-francoispqt-gojay-1.2.13/decode_number.go 0000664 0000000 0000000 00000005122 13653316651 0023116 0 ustar 00root root 0000000 0000000 package gojay
import (
"math"
)
var digits []int8
const maxInt64toMultiply = math.MaxInt64 / 10
const maxInt32toMultiply = math.MaxInt32 / 10
const maxInt16toMultiply = math.MaxInt16 / 10
const maxInt8toMultiply = math.MaxInt8 / 10
const maxUint8toMultiply = math.MaxUint8 / 10
const maxUint16toMultiply = math.MaxUint16 / 10
const maxUint32toMultiply = math.MaxUint32 / 10
const maxUint64toMultiply = math.MaxUint64 / 10
const maxUint32Length = 10
const maxUint64Length = 20
const maxUint16Length = 5
const maxUint8Length = 3
const maxInt32Length = 10
const maxInt64Length = 19
const maxInt16Length = 5
const maxInt8Length = 3
const invalidNumber = int8(-1)
var pow10uint64 = [21]uint64{
0,
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000,
}
var skipNumberEndCursorIncrement [256]int
func init() {
digits = make([]int8, 256)
for i := 0; i < len(digits); i++ {
digits[i] = invalidNumber
}
for i := int8('0'); i <= int8('9'); i++ {
digits[i] = i - int8('0')
}
for i := 0; i < 256; i++ {
switch i {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E', '+', '-':
skipNumberEndCursorIncrement[i] = 1
}
}
}
func (dec *Decoder) skipNumber() (int, error) {
end := dec.cursor + 1
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
end += skipNumberEndCursorIncrement[dec.data[j]]
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E', '+', '-', ' ', '\n', '\t', '\r':
continue
case ',', '}', ']':
return end, nil
default:
// invalid json we expect numbers, dot (single one), comma, or spaces
return end, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return end, nil
}
func (dec *Decoder) getExponent() (int64, error) {
start := dec.cursor
end := dec.cursor
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] { // is positive
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = dec.cursor + 1
case '-':
dec.cursor++
exp, err := dec.getExponent()
return -exp, err
case '+':
dec.cursor++
return dec.getExponent()
default:
// if nothing return 0
// could raise error
if start == end {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoi64(start, end-1), nil
}
}
if start == end {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoi64(start, end-1), nil
}
golang-github-francoispqt-gojay-1.2.13/decode_number_float.go 0000664 0000000 0000000 00000036232 13653316651 0024311 0 ustar 00root root 0000000 0000000 package gojay
// DecodeFloat64 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the float64 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeFloat64(v *float64) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeFloat64(v)
}
func (dec *Decoder) decodeFloat64(v *float64) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getFloat()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getFloatNegative()
if err != nil {
return err
}
*v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeFloat64Null(v **float64) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getFloat()
if err != nil {
return err
}
if *v == nil {
*v = new(float64)
}
**v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getFloatNegative()
if err != nil {
return err
}
if *v == nil {
*v = new(float64)
}
**v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getFloatNegative() (float64, error) {
// look for following numbers
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return dec.getFloat()
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getFloat() (float64, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case '.':
// we get part before decimal as integer
beforeDecimal := dec.atoi64(start, end)
// then we get part after decimal as integer
start = j + 1
// get number after the decimal point
for i := j + 1; i < dec.length || dec.read(); i++ {
c := dec.data[i]
if isDigit(c) {
end = i
// multiply the before decimal point portion by 10 using bitwise
// make sure it doesn't overflow
if end-start < 18 {
beforeDecimal = (beforeDecimal << 3) + (beforeDecimal << 1)
}
continue
} else if (c == 'e' || c == 'E') && j < i-1 {
// we have an exponent, convert first the value we got before the exponent
var afterDecimal int64
expI := end - start + 2
// if exp is too long, it means number is too long, just truncate the number
if expI >= len(pow10uint64) || expI < 0 {
expI = len(pow10uint64) - 2
afterDecimal = dec.atoi64(start, start+expI-2)
} else {
// then we add both integers
// then we divide the number by the power found
afterDecimal = dec.atoi64(start, end)
}
dec.cursor = i + 1
pow := pow10uint64[expI]
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1 // absolute exponent
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// if exponent is negative
if exp < 0 {
return float64(floatVal) * (1 / float64(pow10uint64[pExp])), nil
}
return float64(floatVal) * float64(pow10uint64[pExp]), nil
}
dec.cursor = i
break
}
if end >= dec.length || end < start {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
var afterDecimal int64
expI := end - start + 2
// if exp is too long, it means number is too long, just truncate the number
if expI >= len(pow10uint64) || expI < 0 {
expI = 19
afterDecimal = dec.atoi64(start, start+expI-2)
} else {
afterDecimal = dec.atoi64(start, end)
}
pow := pow10uint64[expI]
// then we add both integers
// then we divide the number by the power found
return float64(beforeDecimal+afterDecimal) / float64(pow), nil
case 'e', 'E':
dec.cursor = j + 1
// we get part before decimal as integer
beforeDecimal := uint64(dec.atoi64(start, end))
// get exponent
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1 // abs
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// if exponent is negative
if exp < 0 {
return float64(beforeDecimal) * (1 / float64(pow10uint64[pExp])), nil
}
return float64(beforeDecimal) * float64(pow10uint64[pExp]), nil
case ' ', '\n', '\t', '\r', ',', '}', ']': // does not have decimal
dec.cursor = j
return float64(dec.atoi64(start, end)), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return float64(dec.atoi64(start, end)), nil
}
// DecodeFloat32 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the float32 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeFloat32(v *float32) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeFloat32(v)
}
func (dec *Decoder) decodeFloat32(v *float32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getFloat32()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getFloat32Negative()
if err != nil {
return err
}
*v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeFloat32Null(v **float32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getFloat32()
if err != nil {
return err
}
if *v == nil {
*v = new(float32)
}
**v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getFloat32Negative()
if err != nil {
return err
}
if *v == nil {
*v = new(float32)
}
**v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getFloat32Negative() (float32, error) {
// look for following numbers
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return dec.getFloat32()
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getFloat32() (float32, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case '.':
// we get part before decimal as integer
beforeDecimal := dec.atoi64(start, end)
// then we get part after decimal as integer
start = j + 1
// get number after the decimal point
// multiple the before decimal point portion by 10 using bitwise
for i := j + 1; i < dec.length || dec.read(); i++ {
c := dec.data[i]
if isDigit(c) {
end = i
// multiply the before decimal point portion by 10 using bitwise
// make sure it desn't overflow
if end-start < 9 {
beforeDecimal = (beforeDecimal << 3) + (beforeDecimal << 1)
}
continue
} else if (c == 'e' || c == 'E') && j < i-1 {
// we get the number before decimal
var afterDecimal int64
expI := end - start + 2
// if exp is too long, it means number is too long, just truncate the number
if expI >= 12 || expI < 0 {
expI = 10
afterDecimal = dec.atoi64(start, start+expI-2)
} else {
afterDecimal = dec.atoi64(start, end)
}
dec.cursor = i + 1
pow := pow10uint64[expI]
// then we add both integers
// then we divide the number by the power found
floatVal := float32(beforeDecimal+afterDecimal) / float32(pow)
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1 // abs
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// if exponent is negative
if exp < 0 {
return float32(floatVal) * (1 / float32(pow10uint64[pExp])), nil
}
return float32(floatVal) * float32(pow10uint64[pExp]), nil
}
dec.cursor = i
break
}
if end >= dec.length || end < start {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// then we add both integers
// then we divide the number by the power found
var afterDecimal int64
expI := end - start + 2
// if exp is too long, it means number is too long, just truncate the number
if expI >= 12 || expI < 0 {
expI = 10
afterDecimal = dec.atoi64(start, start+expI-2)
} else {
// then we add both integers
// then we divide the number by the power found
afterDecimal = dec.atoi64(start, end)
}
pow := pow10uint64[expI]
return float32(beforeDecimal+afterDecimal) / float32(pow), nil
case 'e', 'E':
dec.cursor = j + 1
// we get part before decimal as integer
beforeDecimal := dec.atoi64(start, end)
// get exponent
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// if exponent is negative
if exp < 0 {
return float32(beforeDecimal) * (1 / float32(pow10uint64[pExp])), nil
}
return float32(beforeDecimal) * float32(pow10uint64[pExp]), nil
case ' ', '\n', '\t', '\r', ',', '}', ']': // does not have decimal
dec.cursor = j
return float32(dec.atoi64(start, end)), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return float32(dec.atoi64(start, end)), nil
}
// Add Values functions
// AddFloat decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddFloat(v *float64) error {
return dec.Float64(v)
}
// AddFloatNull decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddFloatNull(v **float64) error {
return dec.Float64Null(v)
}
// AddFloat64 decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddFloat64(v *float64) error {
return dec.Float64(v)
}
// AddFloat64Null decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddFloat64Null(v **float64) error {
return dec.Float64Null(v)
}
// AddFloat32 decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddFloat32(v *float32) error {
return dec.Float32(v)
}
// AddFloat32Null decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddFloat32Null(v **float32) error {
return dec.Float32Null(v)
}
// Float decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Float(v *float64) error {
return dec.Float64(v)
}
// FloatNull decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) FloatNull(v **float64) error {
return dec.Float64Null(v)
}
// Float64 decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Float64(v *float64) error {
err := dec.decodeFloat64(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Float64Null decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Float64Null(v **float64) error {
err := dec.decodeFloat64Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Float32 decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Float32(v *float32) error {
err := dec.decodeFloat32(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Float32Null decodes the JSON value within an object or an array to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Float32Null(v **float32) error {
err := dec.decodeFloat32Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_number_float_test.go 0000664 0000000 0000000 00000075270 13653316651 0025355 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"math"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecoderFloat64(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult float64
skipResult bool
err bool
errType interface{}
}{
{
name: "basic-float",
json: "1.1",
expectedResult: 1.1,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-null-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-err1",
json: "0.",
expectedResult: 0,
err: true,
},
{
name: "basic-err2",
json: "-1.",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "exp-err",
json: "0e-20",
expectedResult: 0,
err: true,
},
{
name: "exp-err3",
json: "-9e-60",
expectedResult: 0,
err: true,
},
{
name: "exp-err4",
json: "0.e-2",
skipResult: true,
err: true,
},
{
name: "exp-err5",
json: "-5.E-2",
skipResult: true,
err: true,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2",
expectedResult: 0.01,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0.000005,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0.003,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0.00008,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-float2",
json: "877 ",
expectedResult: 877,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8.2e-005",
expectedResult: -0.000082,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2.4595,
},
{
name: "basic-float2",
json: "877",
expectedResult: 877,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7.8876,
},
{
name: "basic-float",
json: "2.4595e1",
expectedResult: 24.595,
},
{
name: "basic-float2",
json: "-7.8876e002",
expectedResult: -788.76,
},
{
name: "basic-float3",
json: "-0.1234",
expectedResult: -0.1234,
},
{
name: "basic-exp-too-big",
json: "1e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exp-too-big",
json: "1.002e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exp-too-big",
json: "0e9223372036000000000 ",
expectedResult: 0,
err: true,
},
{
name: "big float",
json: "1.00232492420002423545849009",
expectedResult: 1.002325,
},
{
name: "big float",
json: "5620.1400000000003",
expectedResult: 5620.14,
},
{
name: "basic-exp-too-big",
json: "1.00232492420002423545849009e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "exponent-err",
json: "0e",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "big float",
json: "5620.1400000000003",
expectedResult: 5620.1400000000003,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v float64
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
if !testCase.skipResult {
assert.Equal(t, math.Round(testCase.expectedResult*1000000), math.Round(v*1000000), fmt.Sprintf("v must be equal to %f", testCase.expectedResult))
}
})
}
t.Run("pool-error", func(t *testing.T) {
result := float64(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeFloat64(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v float64
dec := NewDecoder(strings.NewReader(`1.25`))
defer dec.Release()
err := dec.DecodeFloat64(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, 1.25, v, "v must be equal to 1.25")
})
t.Run("decoder-api2", func(t *testing.T) {
var v float64
dec := NewDecoder(strings.NewReader(`1.25`))
defer dec.Release()
err := dec.DecodeFloat64(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, 1.25, v, "v must be equal to 1.25")
})
t.Run("decoder-api-json-error", func(t *testing.T) {
var v float64
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeFloat64(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderFloat64Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult float64
resultIsNil bool
err bool
errType interface{}
}{
{
name: "basic-float",
json: "1.1",
expectedResult: 1.1,
},
{
name: "basic-exponent-positive-positive-exp",
json: " 1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "basic-null-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "basic-err1",
json: "0.",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-err2",
json: "-1.",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exp-err",
json: "0e-20",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exp-err3",
json: "-9e-60",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exp-err4",
json: "0.e-2",
err: true,
resultIsNil: true,
},
{
name: "exp-err5",
json: "-5.E-2",
err: true,
resultIsNil: true,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2",
expectedResult: 0.01,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0.000005,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0.003,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0.00008,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-float2",
json: "877 ",
expectedResult: 877,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8.2e-005",
expectedResult: -0.000082,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2.4595,
},
{
name: "basic-float2",
json: "877",
expectedResult: 877,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7.8876,
},
{
name: "basic-float",
json: "2.4595e1",
expectedResult: 24.595,
},
{
name: "basic-float2",
json: "-7.8876e002",
expectedResult: -788.76,
},
{
name: "basic-float3",
json: "-0.1234",
expectedResult: -0.1234,
},
{
name: "basic-exp-too-big",
json: "1e10000000000 ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-exp-too-big",
json: "1.002e10000000000 ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-exp-too-big",
json: "0e9223372036000000000 ",
expectedResult: 1,
err: true,
resultIsNil: true,
},
{
name: "basic-exp-too-big",
json: "1.00232492420002423545849009",
expectedResult: 1.002325,
resultIsNil: false,
},
{
name: "basic-exp-too-big",
json: "1.00232492420002423545849009e10000000000 ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "exponent-err",
json: "0.1e ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exponent-err",
json: "0e",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
resultIsNil: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*float64)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, math.Round(testCase.expectedResult*1000000), math.Round(*v*1000000), fmt.Sprintf("v must be equal to %f", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(float64)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(float64)
var dec = NewDecoder(strings.NewReader(``))
err := dec.FloatNull(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(float64)
var dec = NewDecoder(strings.NewReader(``))
err := dec.AddFloat64Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderFloat32(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult float32
skipResult bool
err bool
errType interface{}
}{
{
name: "basic-float",
json: "1.1",
expectedResult: 1.1,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-err1",
json: "0.",
expectedResult: 0,
err: true,
},
{
name: "basic-err2",
json: "-1.",
expectedResult: 0,
err: true,
},
{
name: "exp-err",
json: "0e-20",
expectedResult: 0,
err: true,
},
{
name: "exp-err3",
json: "-9e-60",
expectedResult: 0,
err: true,
},
{
name: "exp-err4",
json: "0.e-2",
err: true,
},
{
name: "exp-err5",
json: "-5.E-2",
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2",
expectedResult: 0.01,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0.000005,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0.003,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0.00008,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8.2e-005",
expectedResult: -0.000082,
},
{
name: "basic-exp-too-big",
json: "1e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exp-too-big",
json: "1.0023249242000242e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exp-too-big",
json: "1.002e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exp-too-big",
json: "1.00232492420002423545849009",
expectedResult: 1.0023249,
},
{
name: "basic-exp-too-big",
json: "1.00232492420002423545849009e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2.4595,
},
{
name: "basic-float2",
json: "877",
expectedResult: 877,
},
{
name: "basic-float2",
json: "877 ",
expectedResult: 877,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7.8876,
},
{
name: "basic-float",
json: "2.459e1",
expectedResult: 24.59,
},
{
name: "basic-float2",
json: "-7.8876e002",
expectedResult: -788.76,
},
{
name: "basic-float3",
json: "-0.1234",
expectedResult: -0.1234,
},
{
name: "float10-digit-decimal",
json: "0.9833984375",
expectedResult: 0.9833984,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err",
json: "0e",
expectedResult: 0,
err: true,
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v float32
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
if !testCase.skipResult {
assert.Equal(
t,
math.Round(float64(testCase.expectedResult*1000000)), math.Round(float64(v*1000000)),
fmt.Sprintf("v must be equal to %f", testCase.expectedResult),
)
}
})
}
t.Run("pool-error", func(t *testing.T) {
result := float32(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeFloat32(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v float32
dec := NewDecoder(strings.NewReader(`1.25`))
defer dec.Release()
err := dec.DecodeFloat32(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, float32(1.25), v, "v must be equal to 1.25")
})
t.Run("decoder-api2", func(t *testing.T) {
var v float32
dec := NewDecoder(strings.NewReader(`1.25`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, float32(1.25), v, "v must be equal to 1.25")
})
t.Run("decoder-api-json-error", func(t *testing.T) {
var v float32
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeFloat32(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderFloat32Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult float32
resultIsNil bool
err bool
errType interface{}
}{
{
name: "basic-float",
json: "1.1",
expectedResult: 1.1,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06 ",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: " 3e+3",
expectedResult: 3000,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-err1",
json: "0.",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-err2",
json: "-1.",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exp-err",
json: "0e-20",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exp-err3",
json: "-9e-60",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "exp-err4",
json: "0.e-2",
err: true,
resultIsNil: true,
},
{
name: "exp-err5",
json: "-5.E-2",
err: true,
resultIsNil: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: " 1e-2",
expectedResult: 0.01,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0.000005,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0.003,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0.00008,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8.2e-005",
expectedResult: -0.000082,
},
{
name: "basic-exp-too-big",
json: "1e10000000000 ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-exp-too-big",
json: "1.0023249242000242e10000000000 ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-exp-too-big",
json: "1.002e10000000000 ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-exp-too-big",
json: "1.00232492420002423545849009",
expectedResult: 1.0023249,
},
{
name: "basic-exp-too-big",
json: "1.00232492420002423545849009e10000000000 ",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2.4595,
},
{
name: "basic-float2",
json: "877",
expectedResult: 877,
},
{
name: "basic-float2",
json: "877 ",
expectedResult: 877,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7.8876,
},
{
name: "basic-float",
json: "2.459e1",
expectedResult: 24.59,
},
{
name: "basic-float2",
json: "-7.8876e002",
expectedResult: -788.76,
},
{
name: "basic-float3",
json: "-0.1234",
expectedResult: -0.1234,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
resultIsNil: true,
},
{
name: "exponent-err",
json: "0e",
expectedResult: 0,
err: true,
resultIsNil: true,
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
resultIsNil: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*float32)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(
t,
math.Round(float64(testCase.expectedResult*1000000)), math.Round(float64(*v*1000000)),
fmt.Sprintf("v must be equal to %f", testCase.expectedResult),
)
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(float32)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(float32)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Float32Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderFloat64Field(t *testing.T) {
var testCasesBasic = []struct {
name string
json string
value float64
}{
{
name: "basic",
json: "[1]",
value: float64(1),
},
{
name: "big",
json: "[0]",
value: float64(0),
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var dec = NewDecoder(strings.NewReader(testCase.json))
var v float64
dec.DecodeArray(DecodeArrayFunc(func(dec *Decoder) error {
return dec.AddFloat64(&v)
}))
assert.Equal(t, testCase.value, v)
})
}
var testCasesBasicAlt = []struct {
name string
json string
value float64
}{
{
name: "basic",
json: "[1]",
value: float64(1),
},
{
name: "big",
json: "[0]",
value: float64(0),
},
}
for _, testCase := range testCasesBasicAlt {
t.Run(testCase.name, func(t *testing.T) {
var dec = NewDecoder(strings.NewReader(testCase.json))
var v float64
dec.DecodeArray(DecodeArrayFunc(func(dec *Decoder) error {
return dec.Float(&v)
}))
assert.Equal(t, testCase.value, v)
})
}
}
golang-github-francoispqt-gojay-1.2.13/decode_number_int.go 0000664 0000000 0000000 00000111417 13653316651 0023775 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"math"
)
// DecodeInt reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeInt(v *int) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt(v)
}
func (dec *Decoder) decodeInt(v *int) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
// we don't look for 0 as leading zeros are invalid per RFC
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt64()
if err != nil {
return err
}
*v = int(val)
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt64Negative()
if err != nil {
return err
}
*v = -int(val)
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = InvalidUnmarshalError(
fmt.Sprintf(
"Cannot unmarshall to int, wrong char '%s' found at pos %d",
string(dec.data[dec.cursor]),
dec.cursor,
),
)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeIntNull(v **int) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
// we don't look for 0 as leading zeros are invalid per RFC
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt64()
if err != nil {
return err
}
if *v == nil {
*v = new(int)
}
**v = int(val)
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt64Negative()
if err != nil {
return err
}
if *v == nil {
*v = new(int)
}
**v = -int(val)
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = InvalidUnmarshalError(
fmt.Sprintf(
"Cannot unmarshall to int, wrong char '%s' found at pos %d",
string(dec.data[dec.cursor]),
dec.cursor,
),
)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
// DecodeInt16 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int16 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeInt16(v *int16) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt16(v)
}
func (dec *Decoder) decodeInt16(v *int16) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
// we don't look for 0 as leading zeros are invalid per RFC
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt16()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt16Negative()
if err != nil {
return err
}
*v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeInt16Null(v **int16) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
// we don't look for 0 as leading zeros are invalid per RFC
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt16()
if err != nil {
return err
}
if *v == nil {
*v = new(int16)
}
**v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt16Negative()
if err != nil {
return err
}
if *v == nil {
*v = new(int16)
}
**v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt16Negative() (int16, error) {
// look for following numbers
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
return dec.getInt16()
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt16() (int16, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case '.':
// if dot is found
// look for exponent (e,E) as exponent can change the
// way number should be parsed to int.
// if no exponent found, just unmarshal the number before decimal point
j++
startDecimal := j
endDecimal := j - 1
for ; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
endDecimal = j
continue
case 'e', 'E':
if startDecimal > endDecimal {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
dec.cursor = j + 1
// can try unmarshalling to int as Exponent might change decimal number to non decimal
// let's get the float value first
// we get part before decimal as integer
beforeDecimal := dec.atoi16(start, end)
// get number after the decimal point
// multiple the before decimal point portion by 10 using bitwise
for i := startDecimal; i <= endDecimal; i++ {
beforeDecimal = (beforeDecimal << 3) + (beforeDecimal << 1)
}
// then we add both integers
// then we divide the number by the power found
afterDecimal := dec.atoi16(startDecimal, endDecimal)
expI := endDecimal - startDecimal + 2
if expI >= len(pow10uint64) || expI < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
pow := pow10uint64[expI]
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
// we have the floating value, now multiply by the exponent
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1 // abs
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
val := floatVal * float64(pow10uint64[pExp])
return int16(val), nil
case ' ', '\t', '\n', ',', ']', '}':
dec.cursor = j
return dec.atoi16(start, end), nil
default:
dec.cursor = j
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return dec.atoi16(start, end), nil
case 'e', 'E':
// get init n
dec.cursor = j + 1
return dec.getInt16WithExp(dec.atoi16(start, end))
case ' ', '\n', '\t', '\r', ',', '}', ']':
dec.cursor = j
return dec.atoi16(start, end), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoi16(start, end), nil
}
func (dec *Decoder) getInt16WithExp(init int16) (int16, error) {
var exp uint16
var sign = int16(1)
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '+':
continue
case '-':
sign = -1
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint16(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
dec.cursor++
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint16(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
exp = exp + 1
if exp >= uint16(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int16(pow10uint64[exp])), nil
}
return init * int16(pow10uint64[exp]), nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
exp = exp + 1
if exp >= uint16(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int16(pow10uint64[exp])), nil
}
return init * int16(pow10uint64[exp]), nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// DecodeInt8 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int8 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeInt8(v *int8) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt8(v)
}
func (dec *Decoder) decodeInt8(v *int8) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
// we don't look for 0 as leading zeros are invalid per RFC
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt8()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt8Negative()
if err != nil {
return err
}
*v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeInt8Null(v **int8) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
// we don't look for 0 as leading zeros are invalid per RFC
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt8()
if err != nil {
return err
}
if *v == nil {
*v = new(int8)
}
**v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt8Negative()
if err != nil {
return err
}
if *v == nil {
*v = new(int8)
}
**v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt8Negative() (int8, error) {
// look for following numbers
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
return dec.getInt8()
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt8() (int8, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case '.':
// if dot is found
// look for exponent (e,E) as exponent can change the
// way number should be parsed to int.
// if no exponent found, just unmarshal the number before decimal point
j++
startDecimal := j
endDecimal := j - 1
for ; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
endDecimal = j
continue
case 'e', 'E':
if startDecimal > endDecimal {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
dec.cursor = j + 1
// can try unmarshalling to int as Exponent might change decimal number to non decimal
// let's get the float value first
// we get part before decimal as integer
beforeDecimal := dec.atoi8(start, end)
// get number after the decimal point
// multiple the before decimal point portion by 10 using bitwise
for i := startDecimal; i <= endDecimal; i++ {
beforeDecimal = (beforeDecimal << 3) + (beforeDecimal << 1)
}
// then we add both integers
// then we divide the number by the power found
afterDecimal := dec.atoi8(startDecimal, endDecimal)
expI := endDecimal - startDecimal + 2
if expI >= len(pow10uint64) || expI < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
pow := pow10uint64[expI]
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
// we have the floating value, now multiply by the exponent
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1 // abs
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
val := floatVal * float64(pow10uint64[pExp])
return int8(val), nil
case ' ', '\t', '\n', ',', ']', '}':
dec.cursor = j
return dec.atoi8(start, end), nil
default:
dec.cursor = j
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return dec.atoi8(start, end), nil
case 'e', 'E':
// get init n
dec.cursor = j + 1
return dec.getInt8WithExp(dec.atoi8(start, end))
case ' ', '\n', '\t', '\r', ',', '}', ']':
dec.cursor = j
return dec.atoi8(start, end), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoi8(start, end), nil
}
func (dec *Decoder) getInt8WithExp(init int8) (int8, error) {
var exp uint8
var sign = int8(1)
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '+':
continue
case '-':
sign = -1
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint8(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
dec.cursor++
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint8(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
if exp+1 >= uint8(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int8(pow10uint64[exp+1])), nil
}
return init * int8(pow10uint64[exp+1]), nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
if exp+1 >= uint8(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int8(pow10uint64[exp+1])), nil
}
return init * int8(pow10uint64[exp+1]), nil
default:
dec.err = dec.raiseInvalidJSONErr(dec.cursor)
return 0, dec.err
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// DecodeInt32 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int32 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeInt32(v *int32) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt32(v)
}
func (dec *Decoder) decodeInt32(v *int32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt32()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt32Negative()
if err != nil {
return err
}
*v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeInt32Null(v **int32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt32()
if err != nil {
return err
}
if *v == nil {
*v = new(int32)
}
**v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt32Negative()
if err != nil {
return err
}
if *v == nil {
*v = new(int32)
}
**v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt32Negative() (int32, error) {
// look for following numbers
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
return dec.getInt32()
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt32() (int32, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case '.':
// if dot is found
// look for exponent (e,E) as exponent can change the
// way number should be parsed to int.
// if no exponent found, just unmarshal the number before decimal point
j++
startDecimal := j
endDecimal := j - 1
for ; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
endDecimal = j
continue
case 'e', 'E':
// if eg 1.E
if startDecimal > endDecimal {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
dec.cursor = j + 1
// can try unmarshalling to int as Exponent might change decimal number to non decimal
// let's get the float value first
// we get part before decimal as integer
beforeDecimal := dec.atoi64(start, end)
// get number after the decimal point
// multiple the before decimal point portion by 10 using bitwise
for i := startDecimal; i <= endDecimal; i++ {
beforeDecimal = (beforeDecimal << 3) + (beforeDecimal << 1)
}
// then we add both integers
// then we divide the number by the power found
afterDecimal := dec.atoi64(startDecimal, endDecimal)
expI := endDecimal - startDecimal + 2
if expI >= len(pow10uint64) || expI < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
pow := pow10uint64[expI]
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
// we have the floating value, now multiply by the exponent
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1 // abs
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
val := floatVal * float64(pow10uint64[pExp])
return int32(val), nil
case ' ', '\t', '\n', ',', ']', '}':
dec.cursor = j
return dec.atoi32(start, end), nil
default:
dec.cursor = j
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return dec.atoi32(start, end), nil
case 'e', 'E':
// get init n
dec.cursor = j + 1
return dec.getInt32WithExp(dec.atoi32(start, end))
case ' ', '\n', '\t', '\r', ',', '}', ']':
dec.cursor = j
return dec.atoi32(start, end), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoi32(start, end), nil
}
func (dec *Decoder) getInt32WithExp(init int32) (int32, error) {
var exp uint32
var sign = int32(1)
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '+':
continue
case '-':
sign = -1
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint32(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
dec.cursor++
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint32(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
if exp+1 >= uint32(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int32(pow10uint64[exp+1])), nil
}
return init * int32(pow10uint64[exp+1]), nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
if exp+1 >= uint32(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int32(pow10uint64[exp+1])), nil
}
return init * int32(pow10uint64[exp+1]), nil
default:
dec.err = dec.raiseInvalidJSONErr(dec.cursor)
return 0, dec.err
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
// DecodeInt64 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int64 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeInt64(v *int64) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt64(v)
}
func (dec *Decoder) decodeInt64(v *int64) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt64()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt64Negative()
if err != nil {
return err
}
*v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeInt64Null(v **int64) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getInt64()
if err != nil {
return err
}
if *v == nil {
*v = new(int64)
}
**v = val
return nil
case '-':
dec.cursor = dec.cursor + 1
val, err := dec.getInt64Negative()
if err != nil {
return err
}
if *v == nil {
*v = new(int64)
}
**v = -val
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt64Negative() (int64, error) {
// look for following numbers
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
return dec.getInt64()
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getInt64() (int64, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case ' ', '\t', '\n', ',', '}', ']':
dec.cursor = j
return dec.atoi64(start, end), nil
case '.':
// if dot is found
// look for exponent (e,E) as exponent can change the
// way number should be parsed to int.
// if no exponent found, just unmarshal the number before decimal point
j++
startDecimal := j
endDecimal := j - 1
for ; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
endDecimal = j
continue
case 'e', 'E':
// if eg 1.E
if startDecimal > endDecimal {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
dec.cursor = j + 1
// can try unmarshalling to int as Exponent might change decimal number to non decimal
// let's get the float value first
// we get part before decimal as integer
beforeDecimal := dec.atoi64(start, end)
// get number after the decimal point
// multiple the before decimal point portion by 10 using bitwise
for i := startDecimal; i <= endDecimal; i++ {
beforeDecimal = (beforeDecimal << 3) + (beforeDecimal << 1)
}
// then we add both integers
// then we divide the number by the power found
afterDecimal := dec.atoi64(startDecimal, endDecimal)
expI := endDecimal - startDecimal + 2
if expI >= len(pow10uint64) || expI < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
pow := pow10uint64[expI]
floatVal := float64(beforeDecimal+afterDecimal) / float64(pow)
// we have the floating value, now multiply by the exponent
exp, err := dec.getExponent()
if err != nil {
return 0, err
}
pExp := (exp + (exp >> 31)) ^ (exp >> 31) + 1 // abs
if pExp >= int64(len(pow10uint64)) || pExp < 0 {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
val := floatVal * float64(pow10uint64[pExp])
return int64(val), nil
case ' ', '\t', '\n', ',', ']', '}':
dec.cursor = j
return dec.atoi64(start, end), nil
default:
dec.cursor = j
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return dec.atoi64(start, end), nil
case 'e', 'E':
// get init n
dec.cursor = j + 1
return dec.getInt64WithExp(dec.atoi64(start, end))
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoi64(start, end), nil
}
func (dec *Decoder) getInt64WithExp(init int64) (int64, error) {
var exp uint64
var sign = int64(1)
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '+':
continue
case '-':
sign = -1
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint64(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
dec.cursor++
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
uintv := uint64(digits[dec.data[dec.cursor]])
exp = (exp << 3) + (exp << 1) + uintv
case ' ', '\t', '\n', '}', ',', ']':
if exp+1 >= uint64(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int64(pow10uint64[exp+1])), nil
}
return init * int64(pow10uint64[exp+1]), nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
if exp+1 >= uint64(len(pow10uint64)) {
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
if sign == -1 {
return init * (1 / int64(pow10uint64[exp+1])), nil
}
return init * int64(pow10uint64[exp+1]), nil
default:
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) atoi64(start, end int) int64 {
var ll = end + 1 - start
var val = int64(digits[dec.data[start]])
end = end + 1
if ll < maxInt64Length {
for i := start + 1; i < end; i++ {
intv := int64(digits[dec.data[i]])
val = (val << 3) + (val << 1) + intv
}
return val
} else if ll == maxInt64Length {
for i := start + 1; i < end; i++ {
intv := int64(digits[dec.data[i]])
if val > maxInt64toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxInt64-val < intv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += intv
}
} else {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
return val
}
func (dec *Decoder) atoi32(start, end int) int32 {
var ll = end + 1 - start
var val = int32(digits[dec.data[start]])
end = end + 1
// overflowing
if ll < maxInt32Length {
for i := start + 1; i < end; i++ {
intv := int32(digits[dec.data[i]])
val = (val << 3) + (val << 1) + intv
}
} else if ll == maxInt32Length {
for i := start + 1; i < end; i++ {
intv := int32(digits[dec.data[i]])
if val > maxInt32toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxInt32-val < intv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += intv
}
} else {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
return val
}
func (dec *Decoder) atoi16(start, end int) int16 {
var ll = end + 1 - start
var val = int16(digits[dec.data[start]])
end = end + 1
// overflowing
if ll < maxInt16Length {
for i := start + 1; i < end; i++ {
intv := int16(digits[dec.data[i]])
val = (val << 3) + (val << 1) + intv
}
} else if ll == maxInt16Length {
for i := start + 1; i < end; i++ {
intv := int16(digits[dec.data[i]])
if val > maxInt16toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxInt16-val < intv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += intv
}
} else {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
return val
}
func (dec *Decoder) atoi8(start, end int) int8 {
var ll = end + 1 - start
var val = int8(digits[dec.data[start]])
end = end + 1
// overflowing
if ll < maxInt8Length {
for i := start + 1; i < end; i++ {
intv := int8(digits[dec.data[i]])
val = (val << 3) + (val << 1) + intv
}
} else if ll == maxInt8Length {
for i := start + 1; i < end; i++ {
intv := int8(digits[dec.data[i]])
if val > maxInt8toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxInt8-val < intv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += intv
}
} else {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
return val
}
// Add Values functions
// AddInt decodes the JSON value within an object or an array to an *int.
// If next key value overflows int, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddInt(v *int) error {
return dec.Int(v)
}
// AddIntNull decodes the JSON value within an object or an array to an *int.
// If next key value overflows int, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddIntNull(v **int) error {
return dec.IntNull(v)
}
// AddInt8 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int8, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddInt8(v *int8) error {
return dec.Int8(v)
}
// AddInt8Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int8, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddInt8Null(v **int8) error {
return dec.Int8Null(v)
}
// AddInt16 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int16, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddInt16(v *int16) error {
return dec.Int16(v)
}
// AddInt16Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int16, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddInt16Null(v **int16) error {
return dec.Int16Null(v)
}
// AddInt32 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int32, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddInt32(v *int32) error {
return dec.Int32(v)
}
// AddInt32Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int32, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddInt32Null(v **int32) error {
return dec.Int32Null(v)
}
// AddInt64 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddInt64(v *int64) error {
return dec.Int64(v)
}
// AddInt64Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int64, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddInt64Null(v **int64) error {
return dec.Int64Null(v)
}
// Int decodes the JSON value within an object or an array to an *int.
// If next key value overflows int, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int(v *int) error {
err := dec.decodeInt(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// IntNull decodes the JSON value within an object or an array to an *int.
// If next key value overflows int, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) IntNull(v **int) error {
err := dec.decodeIntNull(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int8 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int8, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int8(v *int8) error {
err := dec.decodeInt8(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int8Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int8, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int8Null(v **int8) error {
err := dec.decodeInt8Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int16 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int16, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int16(v *int16) error {
err := dec.decodeInt16(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int16Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int16, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int16Null(v **int16) error {
err := dec.decodeInt16Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int32 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int32, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int32(v *int32) error {
err := dec.decodeInt32(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int32Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int32, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int32Null(v **int32) error {
err := dec.decodeInt32Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int64 decodes the JSON value within an object or an array to an *int.
// If next key value overflows int64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int64(v *int64) error {
err := dec.decodeInt64(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Int64Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows int64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Int64Null(v **int64) error {
err := dec.decodeInt64Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_number_int_test.go 0000664 0000000 0000000 00000230435 13653316651 0025036 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecoderInt(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: "1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-big",
json: "9223372036854775807",
expectedResult: 9223372036854775807,
},
{
name: "basic-big-overflow",
json: "9223372036854775808",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-big-overflow2",
json: "92233720368547758089",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-big-overflow3",
json: "92233720368547758089 ",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: -2349557,
},
{
name: "exponent-err-too-big",
json: "0e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876 ",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5.01e+10",
expectedResult: 50100000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "error1",
json: "132zz4",
expectedResult: 0,
err: true,
},
{
name: "negative-error2",
json: " -1213xdde2323 ",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error3",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v int
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil && err != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := int(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeInt(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v int
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeInt(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int(33), v, "v must be equal to 33")
})
t.Run("decoder-api2", func(t *testing.T) {
var v int
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int(33), v, "v must be equal to 33")
})
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v int
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeInt(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderIntNull(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: "1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-big",
json: "9223372036854775807",
expectedResult: 9223372036854775807,
},
{
name: "basic-big-overflow",
json: "9223372036854775808",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-big-overflow2",
json: "92233720368547758089",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-big-overflow3",
json: "92233720368547758089 ",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: -2349557,
},
{
name: "exponent-err-too-big",
json: "0e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876 ",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5.01e+10",
expectedResult: 50100000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "error1",
json: "132zz4",
expectedResult: 0,
err: true,
},
{
name: "negative-error2",
json: " -1213xdde2323 ",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error3",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*int)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil && err != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(int)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(int)
var dec = NewDecoder(strings.NewReader(``))
err := dec.IntNull(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt64(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int64
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-big",
json: "9223372036854775807",
expectedResult: 9223372036854775807,
},
{
name: "basic-big-overflow",
json: " 9223372036854775808",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 9223372036854775827",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "92233720368547758089",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow3",
json: "92233720368547758089 ",
expectedResult: 0,
err: true,
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: -2349557,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06 ",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "before-exp-err-too-big",
json: "10.11231242345325435464364643e1",
expectedResult: 0,
err: true,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5.4e+06",
expectedResult: -5400000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "exponent-err-too-big",
json: "0e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e1000000000000000000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e1000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "8ea+00a5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "error1",
json: "132zz4",
expectedResult: 0,
err: true,
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v int64
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := int64(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeInt64(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v int64
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeInt64(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int64(33), v, "v must be equal to 33")
})
t.Run("decoder-api2", func(t *testing.T) {
var v int64
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int64(33), v, "v must be equal to 33")
})
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v int64
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeInt64(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt64Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int64
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-big",
json: "9223372036854775807",
expectedResult: 9223372036854775807,
},
{
name: "basic-big-overflow",
json: " 9223372036854775808",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 9223372036854775827",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "92233720368547758089",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow3",
json: "92233720368547758089 ",
expectedResult: 0,
err: true,
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: -2349557,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1e2",
expectedResult: 100,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06 ",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5e-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5.4e+06",
expectedResult: -5400000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "exponent-err-too-big",
json: "0e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e1000000000000000000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e1000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "8ea+00a5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "error1",
json: "132zz4",
expectedResult: 0,
err: true,
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*int64)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(int64)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(int64)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Int64Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt32(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int32
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: -2349557,
},
{
name: "basic-big",
json: " 2147483647",
expectedResult: 2147483647,
},
{
name: "basic-big-overflow",
json: " 2147483648",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 2147483657",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "21474836483",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1.2E2",
expectedResult: 120,
},
{
name: "exponent-err-too-big",
json: "0e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+005 ",
expectedResult: 350000,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+005",
expectedResult: 350000,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005 ",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5E-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "before-exp-err-too-big",
json: "10.11231242345325435464364643e1",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e1000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e1000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e100000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e100000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-float",
json: "8.32 ",
expectedResult: 8,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "8ea00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error2",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v int32
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := int32(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeInt32(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v int32
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeInt32(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int32(33), v, "v must be equal to 33")
})
t.Run("decoder-api2", func(t *testing.T) {
var v int32
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int32(33), v, "v must be equal to 33")
})
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v int32
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeInt32(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt32Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int32
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: -2349557,
},
{
name: "basic-big",
json: " 2147483647",
expectedResult: 2147483647,
},
{
name: "basic-big-overflow",
json: " 2147483648",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 2147483657",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "21474836483",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1.2E2",
expectedResult: 120,
},
{
name: "exponent-err-too-big",
json: "0e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+005 ",
expectedResult: 350000,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+005",
expectedResult: 350000,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+06",
expectedResult: 5000000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+005 ",
expectedResult: 800000,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5E-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+06",
expectedResult: -5000000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+005",
expectedResult: -800000,
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e1000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e1000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e100000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e100000000000 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-float",
json: "8.32 ",
expectedResult: 8,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "8ea00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error2",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*int32)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(int32)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(int32)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Int32Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt16(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int16
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 5321",
expectedResult: 5321,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-2456",
expectedResult: -2456,
},
{
name: "basic-big",
json: " 24566",
expectedResult: 24566,
},
{
name: "basic-big-overflow",
json: "66535",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "32768",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 2147483648",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "21474836483",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1.2E2",
expectedResult: 120,
},
{
name: "exponent too big",
json: "1000.202302302422324435342E2",
err: true,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+001 ",
expectedResult: 35,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+002",
expectedResult: 350,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+03",
expectedResult: 5000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+02 ",
expectedResult: 800,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5E-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+03",
expectedResult: -5000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+003",
expectedResult: -8000,
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "8.32 ",
expectedResult: 8,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "8ea00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error2",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "0.e",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error8",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v int16
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := int16(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeInt16(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v int16
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeInt16(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int16(33), v, "v must be equal to 33")
})
t.Run("decoder-api2", func(t *testing.T) {
var v int16
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int16(33), v, "v must be equal to 33")
})
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v int16
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeInt16(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt16Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int16
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 5321",
expectedResult: 5321,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-2456",
expectedResult: -2456,
},
{
name: "basic-big",
json: " 24566",
expectedResult: 24566,
},
{
name: "basic-big-overflow",
json: "66535",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "32768",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 2147483648",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "21474836483",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1.2E2",
expectedResult: 120,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+001 ",
expectedResult: 35,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+002",
expectedResult: 350,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+03",
expectedResult: 5000,
},
{
name: "basic-exponent-positive-positive-exp3",
json: "3e+3",
expectedResult: 3000,
},
{
name: "basic-exponent-positive-positive-exp4",
json: "8e+02 ",
expectedResult: 800,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5E-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-005",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0e10000000000 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+03",
expectedResult: -5000,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e03",
expectedResult: -3000,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+003",
expectedResult: -8000,
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "8.32 ",
expectedResult: 8,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "8ea00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error2",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "0.e",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error8",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*int16)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(int16)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(int16)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Int16Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt8(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int8
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 127",
expectedResult: 127,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-123",
expectedResult: -123,
},
{
name: "basic-big",
json: " 43",
expectedResult: 43,
},
{
name: "basic-big-overflow",
json: " 2147483648",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "137",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "128",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "21474836483",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1.2E2",
expectedResult: 120,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+001 ",
expectedResult: 35,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+001",
expectedResult: 35,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+01",
expectedResult: 50,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5E-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-1 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e1 ",
expectedResult: 80,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-1",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+01",
expectedResult: -50,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e01",
expectedResult: -30,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "before-exp-err-too-big",
json: "10.11231242345325435464364643e1",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+001",
expectedResult: -80,
},
{
name: "exponent-err-too-big2",
json: "0e100 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big2",
json: "0.1e100 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "8.32 ",
expectedResult: 8,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "8ea00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error2",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "0.e",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error8",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error8",
json: "-5.01e",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v int8
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := int8(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeInt8(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v int8
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeInt8(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int8(33), v, "v must be equal to 33")
})
t.Run("decoder-api2", func(t *testing.T) {
var v int8
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int8(33), v, "v must be equal to 33")
})
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v int8
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeInt8(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderInt8Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult int8
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 127",
expectedResult: 127,
},
{
name: "basic-negative",
json: "-2",
expectedResult: -2,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-negative-err",
json: "-",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative-err",
json: "-q",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-123",
expectedResult: -123,
},
{
name: "basic-big",
json: " 43",
expectedResult: 43,
},
{
name: "basic-big-overflow",
json: " 2147483648",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "137",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "128",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "21474836483",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: -7,
},
{
name: "basic-float2",
json: "-7.8876a",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-positive-positive-exp",
json: "1.2E2",
expectedResult: 120,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+001 ",
expectedResult: 35,
},
{
name: "basic-exponent-positive-positive-exp1",
json: "3.5e+001",
expectedResult: 35,
},
{
name: "basic-exponent-positive-positive-exp2",
json: "5e+01",
expectedResult: 50,
},
{
name: "basic-exponent-positive-negative-exp",
json: "1e-2 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp2",
json: "5E-6",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp3",
json: "3e-3",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-1 ",
expectedResult: 0,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e1 ",
expectedResult: 80,
},
{
name: "basic-exponent-positive-negative-exp4",
json: "8e-1",
expectedResult: 0,
},
{
name: "basic-exponent-negative-positive-exp",
json: "-1e2",
expectedResult: -100,
},
{
name: "basic-exponent-negative-positive-exp2",
json: "-5e+01",
expectedResult: -50,
},
{
name: "basic-exponent-negative-positive-exp3",
json: "-3e01",
expectedResult: -30,
},
{
name: "error3",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "exponent-err-",
json: "0.1e",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1e10000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big",
json: "0.1932242242424244244e1000000000000000000000000",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-negative-positive-exp4",
json: "-8e+001",
expectedResult: -80,
},
{
name: "exponent-err-too-big2",
json: "0e100 ",
expectedResult: 0,
err: true,
},
{
name: "exponent-err-too-big2",
json: "0.1e100 ",
expectedResult: 0,
err: true,
},
{
name: "basic-exponent-err",
json: "3e",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "8.32 ",
expectedResult: 8,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "8ea00$aa5",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error2",
json: "-8e+00$aa5",
expectedResult: 0,
err: true,
},
{
name: "error4",
json: "0.E----",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error5",
json: "0E40",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error6",
json: "0.e-9",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error7",
json: "0.e",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error8",
json: "-5.e-2",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error8",
json: "-5.01e",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*int8)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(int8)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(int8)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Int8Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
golang-github-francoispqt-gojay-1.2.13/decode_number_test.go 0000664 0000000 0000000 00000001244 13653316651 0024156 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeNumberExra(t *testing.T) {
t.Run("skip-number-err", func(t *testing.T) {
dec := NewDecoder(strings.NewReader("123456afzfz343"))
_, err := dec.skipNumber()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("get-exponent-err", func(t *testing.T) {
v := 0
dec := NewDecoder(strings.NewReader("1.2Ea"))
err := dec.Decode(&v)
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
golang-github-francoispqt-gojay-1.2.13/decode_number_uint.go 0000664 0000000 0000000 00000044114 13653316651 0024161 0 ustar 00root root 0000000 0000000 package gojay
import (
"math"
)
// DecodeUint8 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint8 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeUint8(v *uint8) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeUint8(v)
}
func (dec *Decoder) decodeUint8(v *uint8) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint8()
if err != nil {
return err
}
*v = val
return nil
case '-': // if negative, we just set it to 0 and set error
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeUint8Null(v **uint8) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint8()
if err != nil {
return err
}
if *v == nil {
*v = new(uint8)
}
**v = val
return nil
case '-': // if negative, we just set it to 0 and set error
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
if *v == nil {
*v = new(uint8)
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getUint8() (uint8, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case ' ', '\n', '\t', '\r':
continue
case '.', ',', '}', ']':
dec.cursor = j
return dec.atoui8(start, end), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoui8(start, end), nil
}
// DecodeUint16 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint16 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeUint16(v *uint16) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeUint16(v)
}
func (dec *Decoder) decodeUint16(v *uint16) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint16()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeUint16Null(v **uint16) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint16()
if err != nil {
return err
}
if *v == nil {
*v = new(uint16)
}
**v = val
return nil
case '-':
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
if *v == nil {
*v = new(uint16)
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getUint16() (uint16, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case ' ', '\n', '\t', '\r':
continue
case '.', ',', '}', ']':
dec.cursor = j
return dec.atoui16(start, end), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoui16(start, end), nil
}
// DecodeUint32 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint32 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeUint32(v *uint32) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeUint32(v)
}
func (dec *Decoder) decodeUint32(v *uint32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint32()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeUint32Null(v **uint32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint32()
if err != nil {
return err
}
if *v == nil {
*v = new(uint32)
}
**v = val
return nil
case '-':
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
if *v == nil {
*v = new(uint32)
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getUint32() (uint32, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case ' ', '\n', '\t', '\r':
continue
case '.', ',', '}', ']':
dec.cursor = j
return dec.atoui32(start, end), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoui32(start, end), nil
}
// DecodeUint64 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint64 pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeUint64(v *uint64) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeUint64(v)
}
func (dec *Decoder) decodeUint64(v *uint64) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint64()
if err != nil {
return err
}
*v = val
return nil
case '-':
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeUint64Null(v **uint64) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch c := dec.data[dec.cursor]; c {
case ' ', '\n', '\t', '\r', ',':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
val, err := dec.getUint64()
if err != nil {
return err
}
if *v == nil {
*v = new(uint64)
}
**v = val
return nil
case '-':
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
if *v == nil {
*v = new(uint64)
}
return nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) getUint64() (uint64, error) {
var end = dec.cursor
var start = dec.cursor
// look for following numbers
for j := dec.cursor + 1; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
end = j
continue
case ' ', '\n', '\t', '\r', '.', ',', '}', ']':
dec.cursor = j
return dec.atoui64(start, end), nil
}
// invalid json we expect numbers, dot (single one), comma, or spaces
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.atoui64(start, end), nil
}
func (dec *Decoder) atoui64(start, end int) uint64 {
var ll = end + 1 - start
var val = uint64(digits[dec.data[start]])
end = end + 1
if ll < maxUint64Length {
for i := start + 1; i < end; i++ {
uintv := uint64(digits[dec.data[i]])
val = (val << 3) + (val << 1) + uintv
}
} else if ll == maxUint64Length {
for i := start + 1; i < end; i++ {
uintv := uint64(digits[dec.data[i]])
if val > maxUint64toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxUint64-val < uintv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += uintv
}
} else {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
return val
}
func (dec *Decoder) atoui32(start, end int) uint32 {
var ll = end + 1 - start
var val uint32
val = uint32(digits[dec.data[start]])
end = end + 1
if ll < maxUint32Length {
for i := start + 1; i < end; i++ {
uintv := uint32(digits[dec.data[i]])
val = (val << 3) + (val << 1) + uintv
}
} else if ll == maxUint32Length {
for i := start + 1; i < end; i++ {
uintv := uint32(digits[dec.data[i]])
if val > maxUint32toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxUint32-val < uintv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += uintv
}
} else if ll > maxUint32Length {
dec.err = dec.makeInvalidUnmarshalErr(val)
val = 0
}
return val
}
func (dec *Decoder) atoui16(start, end int) uint16 {
var ll = end + 1 - start
var val uint16
val = uint16(digits[dec.data[start]])
end = end + 1
if ll < maxUint16Length {
for i := start + 1; i < end; i++ {
uintv := uint16(digits[dec.data[i]])
val = (val << 3) + (val << 1) + uintv
}
} else if ll == maxUint16Length {
for i := start + 1; i < end; i++ {
uintv := uint16(digits[dec.data[i]])
if val > maxUint16toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxUint16-val < uintv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += uintv
}
} else if ll > maxUint16Length {
dec.err = dec.makeInvalidUnmarshalErr(val)
val = 0
}
return val
}
func (dec *Decoder) atoui8(start, end int) uint8 {
var ll = end + 1 - start
var val uint8
val = uint8(digits[dec.data[start]])
end = end + 1
if ll < maxUint8Length {
for i := start + 1; i < end; i++ {
uintv := uint8(digits[dec.data[i]])
val = (val << 3) + (val << 1) + uintv
}
} else if ll == maxUint8Length {
for i := start + 1; i < end; i++ {
uintv := uint8(digits[dec.data[i]])
if val > maxUint8toMultiply {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val = (val << 3) + (val << 1)
if math.MaxUint8-val < uintv {
dec.err = dec.makeInvalidUnmarshalErr(val)
return 0
}
val += uintv
}
} else if ll > maxUint8Length {
dec.err = dec.makeInvalidUnmarshalErr(val)
val = 0
}
return val
}
// Add Values functions
// AddUint8 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint8, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddUint8(v *uint8) error {
return dec.Uint8(v)
}
// AddUint8Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint8, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddUint8Null(v **uint8) error {
return dec.Uint8Null(v)
}
// AddUint16 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint16, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddUint16(v *uint16) error {
return dec.Uint16(v)
}
// AddUint16Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint16, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddUint16Null(v **uint16) error {
return dec.Uint16Null(v)
}
// AddUint32 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint32, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddUint32(v *uint32) error {
return dec.Uint32(v)
}
// AddUint32Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint32, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddUint32Null(v **uint32) error {
return dec.Uint32Null(v)
}
// AddUint64 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddUint64(v *uint64) error {
return dec.Uint64(v)
}
// AddUint64Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint64, an InvalidUnmarshalError error will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddUint64Null(v **uint64) error {
return dec.Uint64Null(v)
}
// Uint8 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint8, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint8(v *uint8) error {
err := dec.decodeUint8(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Uint8Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint8, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint8Null(v **uint8) error {
err := dec.decodeUint8Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Uint16 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint16, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint16(v *uint16) error {
err := dec.decodeUint16(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Uint16Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint16, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint16Null(v **uint16) error {
err := dec.decodeUint16Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Uint32 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint32, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint32(v *uint32) error {
err := dec.decodeUint32(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Uint32Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint32, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint32Null(v **uint32) error {
err := dec.decodeUint32Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Uint64 decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint64(v *uint64) error {
err := dec.decodeUint64(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// Uint64Null decodes the JSON value within an object or an array to an *int.
// If next key value overflows uint64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Uint64Null(v **uint64) error {
err := dec.decodeUint64Null(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_number_uint_test.go 0000664 0000000 0000000 00000076754 13653316651 0025237 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecoderUint64(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint64
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-big",
json: "18446744073709551615",
expectedResult: 18446744073709551615,
},
{
name: "basic-big-overflow",
json: "18446744073709551616",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "18446744073709551625",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "184467440737095516161",
expectedResult: 0,
err: true,
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error1",
json: "132zz4",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v uint64
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := uint64(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeUint64(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v uint64
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeUint64(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, uint64(33), v, "v must be equal to 33")
})
t.Run("decoder-api-json-error", func(t *testing.T) {
var v uint64
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeUint64(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderUint64Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint64
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-big",
json: "18446744073709551615",
expectedResult: 18446744073709551615,
},
{
name: "basic-big-overflow",
json: "18446744073709551616",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "18446744073709551625",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "184467440737095516161",
expectedResult: 0,
err: true,
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error1",
json: "132zz4",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*uint64)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(uint64)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(uint64)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Uint64Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderUint32(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint32
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405 ",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: 0,
err: true,
},
{
name: "basic-big",
json: "4294967295",
expectedResult: 4294967295,
},
{
name: "basic-big-overflow",
json: " 4294967298",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "4294967395",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "42949672983",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `123invalid`,
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v uint32
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := uint32(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeUint32(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v uint32
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeUint32(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, uint32(33), v, "v must be equal to 33")
})
t.Run("decoder-api-json-error", func(t *testing.T) {
var v uint32
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeUint32(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderUint32Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint32
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 1039405 ",
expectedResult: 1039405,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-2349557",
expectedResult: 0,
err: true,
},
{
name: "basic-big",
json: "4294967295",
expectedResult: 4294967295,
},
{
name: "basic-big-overflow",
json: " 4294967298",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: "4294967395",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "42949672983",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `123invalid`,
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*uint32)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(uint32)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(uint32)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Uint32Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderUint16(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint16
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 3224 ",
expectedResult: 3224,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-overflow",
json: "335346564",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-negative2",
json: "-24467",
expectedResult: 0,
err: true,
},
{
name: "basic-big",
json: "54546",
expectedResult: 54546,
},
{
name: "basic-big-overflow",
json: " 4294967298",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 65537",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 66537",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "42949672983",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `123invalid`,
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v uint16
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := uint16(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeUint16(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v uint16
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeUint16(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, uint16(33), v, "v must be equal to 33")
})
t.Run("decoder-api2", func(t *testing.T) {
var v uint16
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, uint16(33), v, "v must be equal to 33")
})
t.Run("decoder-api-json-error", func(t *testing.T) {
var v uint16
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeUint16(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderUint16Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint16
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 3224 ",
expectedResult: 3224,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-overflow",
json: "335346564",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-negative2",
json: "-24467",
expectedResult: 0,
err: true,
},
{
name: "basic-big",
json: "54546",
expectedResult: 54546,
},
{
name: "basic-big-overflow",
json: " 4294967298",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 65537",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow",
json: " 66537",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "42949672983",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `123invalid`,
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*uint16)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(uint16)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(uint16)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Uint16Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderUint8(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint8
err bool
errType interface{}
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 255 ",
expectedResult: 255,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-234",
expectedResult: 0,
err: true,
},
{
name: "basic-big",
json: "200",
expectedResult: 200,
},
{
name: "basic-overflow",
json: "256",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-overflow",
json: "274",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-big-overflow",
json: " 4294967298",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "42949672983",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `123invalid`,
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v uint8
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
} else {
assert.Nil(t, err, "Err must be nil")
}
assert.Equal(t, testCase.expectedResult, v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
})
}
t.Run("pool-error", func(t *testing.T) {
result := uint8(1)
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeUint8(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
})
t.Run("decoder-api", func(t *testing.T) {
var v uint8
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.DecodeUint8(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, uint8(33), v, "v must be equal to 33")
})
t.Run("decoder-api2", func(t *testing.T) {
var v uint8
dec := NewDecoder(strings.NewReader(`33`))
defer dec.Release()
err := dec.Decode(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, uint8(33), v, "v must be equal to 33")
})
t.Run("decoder-api-json-error", func(t *testing.T) {
var v uint8
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.DecodeUint8(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderUint8Null(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult uint8
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-positive",
json: "100",
expectedResult: 100,
},
{
name: "basic-positive2",
json: " 255 ",
expectedResult: 255,
},
{
name: "basic-negative",
json: "-2",
expectedResult: 0,
err: true,
},
{
name: "basic-null",
json: "null",
expectedResult: 0,
resultIsNil: true,
},
{
name: "basic-null-err",
json: "nxll",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-skip-data-err",
json: "trua",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-negative2",
json: "-234",
expectedResult: 0,
err: true,
},
{
name: "basic-big",
json: "200",
expectedResult: 200,
},
{
name: "basic-overflow",
json: "256",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-overflow",
json: "274",
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-big-overflow",
json: " 4294967298",
expectedResult: 0,
err: true,
},
{
name: "basic-big-overflow2",
json: "42949672983",
expectedResult: 0,
err: true,
},
{
name: "basic-float",
json: "2.4595",
expectedResult: 2,
},
{
name: "basic-float2",
json: "-7.8876",
expectedResult: 0,
err: true,
},
{
name: "error",
json: "83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "error",
json: "-83zez4",
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-type",
json: `"string"`,
expectedResult: 0,
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "invalid-json",
json: `123invalid`,
expectedResult: 0,
err: true,
errType: InvalidJSONError(""),
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
json := []byte(testCase.json)
var v = (*uint8)(nil)
err := Unmarshal(json, &v)
if testCase.err {
assert.NotNil(t, err, "Err must not be nil")
if testCase.errType != nil {
assert.IsType(
t,
testCase.errType,
err,
fmt.Sprintf("err should be of type %s", reflect.TypeOf(err).String()),
)
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, v)
} else {
assert.Equal(t, testCase.expectedResult, *v, fmt.Sprintf("v must be equal to %d", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json", func(t *testing.T) {
var v = new(uint8)
err := Unmarshal([]byte(``), &v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(uint8)
var dec = NewDecoder(strings.NewReader(``))
err := dec.Uint8Null(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
golang-github-francoispqt-gojay-1.2.13/decode_object.go 0000664 0000000 0000000 00000023676 13653316651 0023112 0 ustar 00root root 0000000 0000000 package gojay
import (
"reflect"
"unsafe"
)
// DecodeObject reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by v.
//
// v must implement UnmarshalerJSONObject.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeObject(j UnmarshalerJSONObject) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
_, err := dec.decodeObject(j)
return err
}
func (dec *Decoder) decodeObject(j UnmarshalerJSONObject) (int, error) {
keys := j.NKeys()
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
case '{':
dec.cursor = dec.cursor + 1
// if keys is zero we will parse all keys
// we run two loops for micro optimization
if keys == 0 {
for dec.cursor < dec.length || dec.read() {
k, done, err := dec.nextKey()
if err != nil {
return 0, err
} else if done {
return dec.cursor, nil
}
err = j.UnmarshalJSONObject(dec, k)
if err != nil {
dec.err = err
return 0, err
} else if dec.called&1 == 0 {
err := dec.skipData()
if err != nil {
return 0, err
}
} else {
dec.keysDone++
}
dec.called &= 0
}
} else {
for (dec.cursor < dec.length || dec.read()) && dec.keysDone < keys {
k, done, err := dec.nextKey()
if err != nil {
return 0, err
} else if done {
return dec.cursor, nil
}
err = j.UnmarshalJSONObject(dec, k)
if err != nil {
dec.err = err
return 0, err
} else if dec.called&1 == 0 {
err := dec.skipData()
if err != nil {
return 0, err
}
} else {
dec.keysDone++
}
dec.called &= 0
}
}
// will get to that point when keysDone is not lower than keys anymore
// in that case, we make sure cursor goes to the end of object, but we skip
// unmarshalling
if dec.child&1 != 0 {
end, err := dec.skipObject()
dec.cursor = end
return dec.cursor, err
}
return dec.cursor, nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return 0, err
}
return dec.cursor, nil
default:
// can't unmarshal to struct
dec.err = dec.makeInvalidUnmarshalErr(j)
err := dec.skipData()
if err != nil {
return 0, err
}
return dec.cursor, nil
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) decodeObjectNull(v interface{}) (int, error) {
// make sure the value is a pointer
vv := reflect.ValueOf(v)
vvt := vv.Type()
if vvt.Kind() != reflect.Ptr || vvt.Elem().Kind() != reflect.Ptr {
dec.err = ErrUnmarshalPtrExpected
return 0, dec.err
}
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
case '{':
elt := vv.Elem()
n := reflect.New(elt.Type().Elem())
elt.Set(n)
var j UnmarshalerJSONObject
var ok bool
if j, ok = n.Interface().(UnmarshalerJSONObject); !ok {
dec.err = dec.makeInvalidUnmarshalErr((UnmarshalerJSONObject)(nil))
return 0, dec.err
}
keys := j.NKeys()
dec.cursor = dec.cursor + 1
// if keys is zero we will parse all keys
// we run two loops for micro optimization
if keys == 0 {
for dec.cursor < dec.length || dec.read() {
k, done, err := dec.nextKey()
if err != nil {
return 0, err
} else if done {
return dec.cursor, nil
}
err = j.UnmarshalJSONObject(dec, k)
if err != nil {
dec.err = err
return 0, err
} else if dec.called&1 == 0 {
err := dec.skipData()
if err != nil {
return 0, err
}
} else {
dec.keysDone++
}
dec.called &= 0
}
} else {
for (dec.cursor < dec.length || dec.read()) && dec.keysDone < keys {
k, done, err := dec.nextKey()
if err != nil {
return 0, err
} else if done {
return dec.cursor, nil
}
err = j.UnmarshalJSONObject(dec, k)
if err != nil {
dec.err = err
return 0, err
} else if dec.called&1 == 0 {
err := dec.skipData()
if err != nil {
return 0, err
}
} else {
dec.keysDone++
}
dec.called &= 0
}
}
// will get to that point when keysDone is not lower than keys anymore
// in that case, we make sure cursor goes to the end of object, but we skip
// unmarshalling
if dec.child&1 != 0 {
end, err := dec.skipObject()
dec.cursor = end
return dec.cursor, err
}
return dec.cursor, nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return 0, err
}
return dec.cursor, nil
default:
// can't unmarshal to struct
dec.err = dec.makeInvalidUnmarshalErr((UnmarshalerJSONObject)(nil))
err := dec.skipData()
if err != nil {
return 0, err
}
return dec.cursor, nil
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) skipObject() (int, error) {
var objectsOpen = 1
var objectsClosed = 0
for j := dec.cursor; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case '}':
objectsClosed++
// everything is closed return
if objectsOpen == objectsClosed {
// add char to object data
return j + 1, nil
}
case '{':
objectsOpen++
case '"':
j++
var isInEscapeSeq bool
var isFirstQuote = true
for ; j < dec.length || dec.read(); j++ {
if dec.data[j] != '"' {
continue
}
if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) {
break
} else {
isInEscapeSeq = false
}
if isFirstQuote {
isFirstQuote = false
}
// loop backward and count how many anti slash found
// to see if string is effectively escaped
ct := 0
for i := j - 1; i > 0; i-- {
if dec.data[i] != '\\' {
break
}
ct++
}
// is pair number of slashes, quote is not escaped
if ct&1 == 0 {
break
}
isInEscapeSeq = true
}
default:
continue
}
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) nextKey() (string, bool, error) {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
case '"':
dec.cursor = dec.cursor + 1
start, end, err := dec.getString()
if err != nil {
return "", false, err
}
var found byte
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
if dec.data[dec.cursor] == ':' {
found |= 1
break
}
}
if found&1 != 0 {
dec.cursor++
d := dec.data[start : end-1]
return *(*string)(unsafe.Pointer(&d)), false, nil
}
return "", false, dec.raiseInvalidJSONErr(dec.cursor)
case '}':
dec.cursor = dec.cursor + 1
return "", true, nil
default:
// can't unmarshall to struct
return "", false, dec.raiseInvalidJSONErr(dec.cursor)
}
}
return "", false, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) skipData() error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
// is null
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
case 't':
dec.cursor++
err := dec.assertTrue()
if err != nil {
return err
}
return nil
// is false
case 'f':
dec.cursor++
err := dec.assertFalse()
if err != nil {
return err
}
return nil
// is an object
case '{':
dec.cursor = dec.cursor + 1
end, err := dec.skipObject()
dec.cursor = end
return err
// is string
case '"':
dec.cursor = dec.cursor + 1
err := dec.skipString()
return err
// is array
case '[':
dec.cursor = dec.cursor + 1
end, err := dec.skipArray()
dec.cursor = end
return err
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
end, err := dec.skipNumber()
dec.cursor = end
return err
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
// DecodeObjectFunc is a func type implementing UnmarshalerJSONObject.
// Use it to cast a `func(*Decoder, k string) error` to Unmarshal an object on the fly.
type DecodeObjectFunc func(*Decoder, string) error
// UnmarshalJSONObject implements UnmarshalerJSONObject.
func (f DecodeObjectFunc) UnmarshalJSONObject(dec *Decoder, k string) error {
return f(dec, k)
}
// NKeys implements UnmarshalerJSONObject.
func (f DecodeObjectFunc) NKeys() int {
return 0
}
// Add Values functions
// AddObject decodes the JSON value within an object or an array to a UnmarshalerJSONObject.
func (dec *Decoder) AddObject(v UnmarshalerJSONObject) error {
return dec.Object(v)
}
// AddObjectNull decodes the JSON value within an object or an array to a UnmarshalerJSONObject.
func (dec *Decoder) AddObjectNull(v interface{}) error {
return dec.ObjectNull(v)
}
// Object decodes the JSON value within an object or an array to a UnmarshalerJSONObject.
func (dec *Decoder) Object(value UnmarshalerJSONObject) error {
initialKeysDone := dec.keysDone
initialChild := dec.child
dec.keysDone = 0
dec.called = 0
dec.child |= 1
newCursor, err := dec.decodeObject(value)
if err != nil {
return err
}
dec.cursor = newCursor
dec.keysDone = initialKeysDone
dec.child = initialChild
dec.called |= 1
return nil
}
// ObjectNull decodes the JSON value within an object or an array to a UnmarshalerJSONObject.
// v should be a pointer to an UnmarshalerJSONObject,
// if `null` value is encountered in JSON, it will leave the value v untouched,
// else it will create a new instance of the UnmarshalerJSONObject behind v.
func (dec *Decoder) ObjectNull(v interface{}) error {
initialKeysDone := dec.keysDone
initialChild := dec.child
dec.keysDone = 0
dec.called = 0
dec.child |= 1
newCursor, err := dec.decodeObjectNull(v)
if err != nil {
return err
}
dec.cursor = newCursor
dec.keysDone = initialKeysDone
dec.child = initialChild
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_object_test.go 0000664 0000000 0000000 00000135722 13653316651 0024145 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"io"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func makePointer(v interface{}) interface{} {
var ptr = reflect.New(reflect.TypeOf(v))
ptr.Elem().Set(reflect.ValueOf(v))
return ptr.Interface()
}
func TestDecodeObjectBasic(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testObject
err bool
errType interface{}
skipCheckResult bool
}{
{
name: "basic",
json: `{
"testStr": "hello world!",
"testStrNull": "hello world!",
"testInt": 4535,
"testIntNull": 4535,
"testBool": true,
"testBoolNull": true,
"testFloat32": 2.345,
"testFloat32Null": 2.345,
"testFloat64": 123.677,
"testFloat64Null": 123.677,
"testInt8": 23,
"testInt8Null": 23,
"testInt16": 1245,
"testInt16Null": 1245,
"testInt32": 456778,
"testInt32Null": 456778,
"testInt64": 1446685358,
"testInt64Null": 1446685358,
"testUint8": 255,
"testUint8Null": 255,
"testUint16": 3455,
"testUint16Null": 3455,
"testUint32": 343443,
"testUint32Null": 343443,
"testUint64": 545665757,
"testUint64Null": 545665757,
"testSubObjectNull": {
"testStr": "1"
}
}`,
expectedResult: testObject{
testStr: "hello world!",
testStrNull: makePointer("hello world!").(*string),
testInt: 4535,
testIntNull: makePointer(4535).(*int),
testBool: true,
testBoolNull: makePointer(true).(*bool),
testFloat32: 2.345,
testFloat32Null: makePointer(float32(2.345)).(*float32),
testFloat64: 123.677,
testFloat64Null: makePointer(float64(123.677)).(*float64),
testInt8: 23,
testInt8Null: makePointer(int8(23)).(*int8),
testInt16: 1245,
testInt16Null: makePointer(int16(1245)).(*int16),
testInt32: 456778,
testInt32Null: makePointer(int32(456778)).(*int32),
testInt64: 1446685358,
testInt64Null: makePointer(int64(1446685358)).(*int64),
testUint8: 255,
testUint8Null: makePointer(uint8(255)).(*uint8),
testUint16: 3455,
testUint16Null: makePointer(uint16(3455)).(*uint16),
testUint32: 343443,
testUint32Null: makePointer(uint32(343443)).(*uint32),
testUint64: 545665757,
testUint64Null: makePointer(uint64(545665757)).(*uint64),
},
err: false,
},
{
name: "basic-with-exponent",
json: `{
"testStr": "hello world!",
"testInt": 3e3,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{
testStr: "hello world!",
testInt: 3000,
testBool: true,
testFloat32: 2.345,
testFloat64: 123.677,
testInt8: 23,
testInt16: 1245,
testInt32: 456778,
testInt64: 1446685358,
testUint8: 255,
testUint16: 3455,
testUint32: 343443,
testUint64: 545665757,
},
err: false,
},
{
name: "basic-with-exponent3",
json: `{
"testStr": "hello world!",
"testInt": 3e-3,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 12e-3,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{
testStr: "hello world!",
testInt: 0,
testBool: true,
testFloat32: 2.345,
testFloat64: 0.012,
testInt8: 23,
testInt16: 1245,
testInt32: 456778,
testInt64: 1446685358,
testUint8: 255,
testUint16: 3455,
testUint32: 343443,
testUint64: 545665757,
},
err: false,
},
{
name: "basic-err-invalid-type",
json: `1`,
expectedResult: testObject{},
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-err-invalid-json",
json: `hello`,
expectedResult: testObject{},
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-err-invalid-json",
json: `nall`,
expectedResult: testObject{},
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-err-invalid-type",
json: ``,
expectedResult: testObject{},
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-err",
json: `{
"testStr": "hello world!",
"testInt": 453q5,
"testBool": trae,
"testFloat32": 2q.345,
"testFloat64": 12x3.677,
"testInt8": 2s3,
"testInt16": 1245,
"testInt32": 4567q78,
"testInt64": 14466e85358,
"testUint8": 2s55,
"testUint16": 345i5,
"testUint32": 343q443,
"testUint64": 5456657z57
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err2",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 4567x78,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-float32",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2q.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-float64",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 1x23.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err3",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 2q3,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-int16",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1x245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-int64",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446q685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-uint8",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 2x55,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-uint16",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3x455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-uint32",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 3x43443,
"testUint64": 545665757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-err-uint64",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 5456x65757
}`,
expectedResult: testObject{},
err: true,
},
{
name: "basic-skip-data",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"skipObject": {
"escapedString": "string with escaped \\n new line"
},
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"skipArray": [[],[],{}],
"testUint16": 3455,
"skipBool": true,
"skipNull": null,
"testUint32": 343443,
"testUint64": 545665757,
"skipString": "skipping string with escaped \\n new line",
"skipInt": 3,
}`,
expectedResult: testObject{
testStr: "hello world!",
testInt: 4535,
testBool: true,
testFloat32: 2.345,
testFloat64: 123.677,
testInt8: 23,
testInt16: 1245,
testInt32: 456778,
testInt64: 1446685358,
testUint8: 255,
testUint16: 3455,
testUint32: 343443,
testUint64: 545665757,
},
err: false,
},
{
name: "basic-skip-data-error-uint8-negative",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"skipObject": {
"escapedString": "string with escaped \\n new line"
},
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": -255,
"skipArray": [[],[],{}],
"testUint16": 3455,
"skipBool": true,
"skipNull": null,
"testUint32": 343443,
"testUint64": 545665757,
"skipString": "skipping string with escaped \\n new line",
"skipInt": 3
}`,
expectedResult: testObject{
testStr: "hello world!",
testInt: 4535,
testBool: true,
testFloat32: 2.345,
testFloat64: 123.677,
testInt8: 23,
testInt16: 1245,
testInt32: 456778,
testInt64: 1446685358,
testUint8: 0,
testUint16: 3455,
testUint32: 343443,
testUint64: 545665757,
},
err: true,
},
{
name: "skip-data-with-unicode",
json: `{
"skipString": "hello\u1234\u2123",
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"skipObject": {
"escapedString": "string with unicode \u1234\u1234\u1234"
},
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"skipArray": [[],[],{}],
"testUint16": 3455,
"skipBool": true,
"skipNull": null,
"testUint32": 343443,
"testUint64": 545665757,
"skipInt": 3
}`,
expectedResult: testObject{
testStr: "hello world!",
testInt: 4535,
testBool: true,
testFloat32: 2.345,
testFloat64: 123.677,
testInt8: 23,
testInt16: 1245,
testInt32: 456778,
testInt64: 1446685358,
testUint8: 255,
testUint16: 3455,
testUint32: 343443,
testUint64: 545665757,
},
err: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := testObject{}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
}
})
}
}
func TestDecodeObjectBasic0Keys(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testObject0Keys
err bool
errType interface{}
skipCheckResult bool
}{
{
name: "basic",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{
testStr: "hello world!",
testInt: 4535,
testBool: true,
testFloat32: 2.345,
testFloat64: 123.677,
testInt8: 23,
testInt16: 1245,
testInt32: 456778,
testInt64: 1446685358,
testUint8: 255,
testUint16: 3455,
testUint32: 343443,
testUint64: 545665757,
},
err: false,
},
{
name: "basic-err-invalid-type",
json: `1`,
expectedResult: testObject0Keys{},
err: true,
errType: InvalidUnmarshalError(""),
},
{
name: "basic-err-invalid-json",
json: `hello`,
expectedResult: testObject0Keys{},
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-err-invalid-json",
json: `nall`,
expectedResult: testObject0Keys{},
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-err-invalid-type",
json: ``,
expectedResult: testObject0Keys{},
err: true,
errType: InvalidJSONError(""),
},
{
name: "basic-err",
json: `{
"testStr": "hello world!",
"testInt": 453q5,
"testBool": trae,
"testFloat32": 2q.345,
"testFloat64": 12x3.677,
"testInt8": 2s3,
"testInt16": 1245,
"testInt32": 4567q78,
"testInt64": 14466e85358,
"testUint8": 2s55,
"testUint16": 345i5,
"testUint32": 343q443,
"testUint64": 5456657z57
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err2",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 4567x78,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-float32",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2q.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-float64",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 1x23.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err3",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 2q3,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-int16",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1x245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-int64",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446q685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-uint8",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 2x55,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-uint16",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3x455,
"testUint32": 343443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-uint32",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 3x43443,
"testUint64": 545665757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-err-uint64",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"testUint16": 3455,
"testUint32": 343443,
"testUint64": 5456x65757
}`,
expectedResult: testObject0Keys{},
err: true,
},
{
name: "basic-skip-data",
json: `{
"testStr": "hello world!",
"testInt": 4535,
"testBool": true,
"testFloat32": 2.345,
"testFloat64": 123.677,
"testInt8": 23,
"skipObject": {
"escapedString": "string with escaped \\n new line"
},
"testInt16": 1245,
"testInt32": 456778,
"testInt64": 1446685358,
"testUint8": 255,
"skipArray": [[],[],{}],
"testUint16": 3455,
"skipBool": true,
"skipNull": null,
"testUint32": 343443,
"testUint64": 545665757,
"skipString": "skipping string with escaped \\n new line",
"skipInt": 3,
}`,
expectedResult: testObject0Keys{
testStr: "hello world!",
testInt: 4535,
testBool: true,
testFloat32: 2.345,
testFloat64: 123.677,
testInt8: 23,
testInt16: 1245,
testInt32: 456778,
testInt64: 1446685358,
testUint8: 255,
testUint16: 3455,
testUint32: 343443,
testUint64: 545665757,
},
err: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := testObject0Keys{}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
}
})
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := testObject0Keys{}
err := UnmarshalJSONObject([]byte(testCase.json), &s)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
}
})
}
}
type ObjectNull struct {
SubObject *ObjectNull
SubArray *testSliceBools
}
func (o *ObjectNull) UnmarshalJSONObject(dec *Decoder, k string) error {
switch k {
case "subobject":
return dec.ObjectNull(&o.SubObject)
case "subarray":
return dec.AddArrayNull(&o.SubArray)
}
return nil
}
func (o *ObjectNull) NKeys() int {
return 2
}
type ObjectNullZeroNKeys struct {
SubObject *ObjectNullZeroNKeys
SubArray *testSliceBools
}
func (o *ObjectNullZeroNKeys) UnmarshalJSONObject(dec *Decoder, k string) error {
switch k {
case "subobject":
return dec.AddObjectNull(&o.SubObject)
case "subarray":
return dec.AddArrayNull(&o.SubArray)
}
return nil
}
func (o *ObjectNullZeroNKeys) NKeys() int {
return 0
}
func TestDecodeObjectNull(t *testing.T) {
t.Run("sub obj should not be nil", func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject": {},"subarray":[true]}`), o)
assert.Nil(t, err)
assert.NotNil(t, o.SubObject)
assert.NotNil(t, o.SubArray)
})
t.Run("sub obj and sub array should be nil", func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject": null,"subarray": null}`), o)
assert.Nil(t, err)
assert.Nil(t, o.SubObject)
assert.Nil(t, o.SubArray)
})
t.Run(
"sub obj should not be be nil",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject":{"subobject":{}}}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.Nil(t, err)
assert.NotNil(t, o.SubObject)
},
)
t.Run(
"sub obj should be nil",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject":null}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.Nil(t, err)
assert.Nil(t, o.SubObject)
},
)
t.Run(
"skip data",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{
"subobject": {
"subobject": {},
"subarray": [],
"subarray": [],
"skipped": ""
}
}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.Nil(t, err)
assert.NotNil(t, o.SubObject)
assert.Nil(t, o.SubArray)
},
)
t.Run(
"skip data not child",
func(t *testing.T) {
var o = &ObjectNull{}
var dec = NewDecoder(strings.NewReader(`{
"subobject": {},
"subarray": [],
"subarray": [],
"skipped": ""
}`))
var _, err = dec.decodeObjectNull(&o)
assert.Nil(t, err)
assert.NotNil(t, o.SubObject)
},
)
t.Run(
"err empty json",
func(t *testing.T) {
var o = &ObjectNull{}
var dec = NewDecoder(strings.NewReader(``))
var _, err = dec.decodeObjectNull(&o)
assert.NotNil(t, err)
},
)
t.Run(
"should return an error as type is not ptr",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key":{}}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull("")
}))
assert.NotNil(t, err)
assert.Equal(t, ErrUnmarshalPtrExpected, err)
},
)
t.Run(
"should return an error as type is not ptr",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key":[]}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ArrayNull("")
}))
assert.NotNil(t, err)
assert.Equal(t, ErrUnmarshalPtrExpected, err)
},
)
t.Run(
"should return an error as type is not ptr to UnmarshalerJSONObject",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key":{}}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
var strPtr = new(string)
return dec.ObjectNull(&strPtr)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidUnmarshalError(""), err)
},
)
t.Run(
"should return an error as type is not ptr to UnmarshalerJSONObject",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key":[]}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
var strPtr = new(string)
return dec.ArrayNull(&strPtr)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidUnmarshalError(""), err)
},
)
t.Run(
"should return an error as type is not ptr to UnmarshalerJSONObject",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key":{}}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
var strPtr = new(string)
return dec.ArrayNull(&strPtr)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidUnmarshalError(""), err)
},
)
t.Run(
"should return an error as type is not ptr to UnmarshalerJSONObject",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key":"`), DecodeObjectFunc(func(dec *Decoder, k string) error {
var strPtr = new(string)
return dec.ArrayNull(&strPtr)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"skip data",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key": ""}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
var strPtr = new(string)
return dec.ObjectNull(&strPtr)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidUnmarshalError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject":{"subobject":{"a":a}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject":{"subobject":a}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject":{"subobject":{"sub}}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var o = &testSliceBools{}
var err = UnmarshalJSONObject([]byte(`{"subobject":a`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ArrayNull(&o)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"key":a`), DecodeObjectFunc(func(dec *Decoder, k string) error {
var strPtr = new(string)
return dec.ObjectNull(&strPtr)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var err = UnmarshalJSONObject([]byte(`{"subobject": {},"}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
var o = &ObjectNull{}
return dec.ObjectNull(&o)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject": a`), o)
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"invalid JSON for object",
func(t *testing.T) {
var o = &ObjectNull{}
var err = UnmarshalJSONObject([]byte(`{"subobject": na`), o)
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"zero nkeys, no error, two keys",
func(t *testing.T) {
var o = &ObjectNullZeroNKeys{}
var err = UnmarshalJSONObject([]byte(`{
"subobject": {
"subobject": {
"subobject":{}
},
"subarray": []
}
}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.Nil(t, err)
},
)
t.Run(
"zero nkeys, no error, two keys, skip data",
func(t *testing.T) {
var o = &ObjectNullZeroNKeys{}
var err = UnmarshalJSONObject([]byte(`{
"subobject": {
"subobject": {
"subobject":{}
},
"subarray": [],
"skipped": 1
}
}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.Nil(t, err)
},
)
t.Run(
"zero nkeys, error skip data",
func(t *testing.T) {
var o = &ObjectNullZeroNKeys{}
var err = UnmarshalJSONObject([]byte(`{
"subobject": {
"subobject": {
"subobject":{}
},
"subarray": [],
"skippedInvalid": "q
}
}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"zero nkeys, error invalid json in keys",
func(t *testing.T) {
var o = &ObjectNullZeroNKeys{}
var err = UnmarshalJSONObject([]byte(`{
"subobject": {
"subobj
}
}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
t.Run(
"zero nkeys, error invalid json, sub object",
func(t *testing.T) {
var o = &ObjectNullZeroNKeys{}
var err = UnmarshalJSONObject([]byte(`{
"subobject": {
"subobject": {
"subobj
}
}
}`), DecodeObjectFunc(func(dec *Decoder, k string) error {
return dec.ObjectNull(&o.SubObject)
}))
assert.NotNil(t, err)
assert.IsType(t, InvalidJSONError(""), err)
},
)
}
func TestDecodeObjectComplex(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult testObjectComplex
err bool
errType interface{}
skipCheckResult bool
}{
{
name: "basic",
json: `{
"testSubObject": {},
"testSubSliceInts": [1,2]
}`,
expectedResult: testObjectComplex{
testSubObject: &testObject{},
testSubSliceInts: &testSliceInts{1, 2},
},
err: false,
},
{
name: "complex",
json: `{
"testSubObject": {
"testStr": "some string",
"testInt":124465,
"testUint16":120,
"testUint8":15,
"testInt16":-135,
"testInt8":-23
},
"testSubSliceInts": [1,2,3,4,5],
"testStr": "some \n string"
}`,
expectedResult: testObjectComplex{
testSubObject: &testObject{
testStr: "some string",
testInt: 124465,
testUint16: 120,
testUint8: 15,
testInt16: -135,
testInt8: -23,
},
testSubSliceInts: &testSliceInts{1, 2, 3, 4, 5},
testStr: "some \n string",
},
err: false,
},
{
name: "complex-json-err",
json: `{"testSubObject":{"testStr":"some string,"testInt":124465,"testUint16":120, "testUint8":15,"testInt16":-135,"testInt8":-23},"testSubSliceInts":[1,2],"testStr":"some \n string"}`,
expectedResult: testObjectComplex{
testSubObject: &testObject{},
},
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
s := testObjectComplex{
testSubObject: &testObject{},
testSubSliceInts: &testSliceInts{},
}
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
err := dec.Decode(&s)
if testCase.err {
t.Log(err)
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of the given type")
}
return
}
assert.Nil(t, err, "err should be nil")
if !testCase.skipCheckResult {
assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
}
})
}
}
func assertResult(t *testing.T, v *TestObj, err error) {
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, 245, v.test, "v.test must be equal to 245")
assert.Equal(t, 246, v.test2, "v.test2 must be equal to 246")
assert.Equal(t, "string", v.test3, "v.test3 must be equal to 'string'")
assert.Equal(t, "complex string with spaces and some slashes\"", v.test4, "v.test4 must be equal to 'string'")
assert.Equal(t, -1.15657654376543, v.test5, "v.test5 must be equal to 1.15")
assert.Len(t, v.testArr, 2, "v.testArr must be of len 2")
assert.Equal(t, 121, v.testSubObj.test3, "v.testSubObj.test3 must be equal to 121")
assert.Equal(t, 122, v.testSubObj.test4, "v.testSubObj.test4 must be equal to 122")
assert.Equal(t, "string", v.testSubObj.test5, "v.testSubObj.test5 must be equal to 'string'")
assert.Equal(t, 150, v.testSubObj.testSubSubObj.test3, "v.testSubObj.testSubSubObj.test3 must be equal to 150")
assert.Equal(t, 150, v.testSubObj.testSubSubObj2.test3, "v.testSubObj.testSubSubObj2.test3 must be equal to 150")
assert.Equal(t, 122, v.testSubObj2.test3, "v.testSubObj2.test3 must be equal to 121")
assert.Equal(t, 123, v.testSubObj2.test4, "v.testSubObj2.test4 must be equal to 122")
assert.Equal(t, "string", v.testSubObj2.test5, "v.testSubObj2.test5 must be equal to 'string'")
assert.Equal(t, 151, v.testSubObj2.testSubSubObj.test3, "v.testSubObj2.testSubSubObj.test must be equal to 150")
}
func TestDecoderObject(t *testing.T) {
json := []byte(`{
"test": 245,
"test2": 246,
"test3": "string",
"test4": "complex string with spaces and some slashes\"",
"test5": -1.15657654376543,
"testNull": null,
"testArr": [
{
"test": 245,
"test2": 246
},
{
"test": 245,
"test2": 246
}
],
"testSubObj": {
"test": 121,
"test2": 122,
"testNull": null,
"testSubSubObj": {
"test": 150,
"testNull": null
},
"testSubSubObj2": {
"test": 150
},
"test3": "string"
"testNull": null,
},
"testSubObj2": {
"test": 122,
"test3": "string"
"testSubSubObj": {
"test": 151
},
"test2": 123
}
}`)
v := &TestObj{}
err := Unmarshal(json, v)
assertResult(t, v, err)
}
func TestDecodeObjectJSONNull(t *testing.T) {
json := []byte(`null`)
v := &TestObj{}
err := Unmarshal(json, v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, v.test, 0, "v.test must be 0 val")
}
var jsonComplex = []byte(`{
"test": "{\"test\":\"1\",\"test1\":2}",
"test2\n": "\\\\\\\\\n",
"testArrSkip": ["testString with escaped \\\" quotes"],
"testSkipString": "skip \\ string with \n escaped char \" ",
"testSkipObject": {
"testSkipSubObj": {
"test": "test"
}
},
"testSkipNumber": 123.23,
"testSkipNumber2": 123.23 ,
"testBool": true,
"testSkipBoolTrue": true,
"testSkipBoolFalse": false,
"testSkipBoolNull": null,
"testSub": {
"test": "{\"test\":\"1\",\"test1\":2}",
"test2\n": "[1,2,3]",
"test3": 1,
"testObjSkip": {
"test": "test string with escaped \" quotes"
},
"testStrSkip" : "test"
},
"testBoolSkip": false,
"testObjInvalidType": "somestring",
"testArrSkip2": [[],["someString"]],
"test3": 1
}`)
type jsonObjectComplex struct {
Test string
Test2 string
Test3 int
Test4 bool
testSub *jsonObjectComplex
testObjInvalidType *jsonObjectComplex
}
func (j *jsonObjectComplex) UnmarshalJSONObject(dec *Decoder, key string) error {
switch key {
case "test":
return dec.AddString(&j.Test)
case "test2\n":
return dec.AddString(&j.Test2)
case "test3":
return dec.AddInt(&j.Test3)
case "testBool":
return dec.AddBool(&j.Test4)
case "testSub":
j.testSub = &jsonObjectComplex{}
return dec.AddObject(j.testSub)
case "testObjInvalidType":
j.testObjInvalidType = &jsonObjectComplex{}
return dec.AddObject(j.testObjInvalidType)
}
return nil
}
func (j *jsonObjectComplex) NKeys() int {
return 6
}
func TestDecodeObjComplex(t *testing.T) {
result := jsonObjectComplex{}
err := UnmarshalJSONObject(jsonComplex, &result)
assert.NotNil(t, err, "err should not be as invalid type as been encountered nil")
assert.Equal(t, `Cannot unmarshal JSON to type '*gojay.jsonObjectComplex'`, err.Error(), "err should not be as invalid type as been encountered nil")
assert.Equal(t, `{"test":"1","test1":2}`, result.Test, "result.Test is not expected value")
assert.Equal(t, "\\\\\\\\\n", result.Test2, "result.Test2 is not expected value")
assert.Equal(t, 1, result.Test3, "result.test3 is not expected value")
assert.Equal(t, `{"test":"1","test1":2}`, result.testSub.Test, "result.testSub.test is not expected value")
assert.Equal(t, `[1,2,3]`, result.testSub.Test2, "result.testSub.test2 is not expected value")
assert.Equal(t, 1, result.testSub.Test3, "result.testSub.test3 is not expected value")
assert.Equal(t, true, result.Test4, "result.Test4 is not expected value, should be true")
}
type jsonDecodePartial struct {
Test string
Test2 string
}
func (j *jsonDecodePartial) UnmarshalJSONObject(dec *Decoder, key string) error {
switch key {
case "test":
return dec.AddString(&j.Test)
case `test2`:
return dec.AddString(&j.Test2)
}
return nil
}
func (j *jsonDecodePartial) NKeys() int {
return 2
}
func TestDecodeObjectPartial(t *testing.T) {
result := jsonDecodePartial{}
dec := NewDecoder(nil)
dec.data = []byte(`{
"test": "test",
"test2": "test",
"testArrSkip": ["test"],
"testSkipString": "test",
"testSkipNumber": 123.23
}`)
dec.length = len(dec.data)
err := dec.DecodeObject(&result)
assert.Nil(t, err, "err should be nil")
assert.NotEqual(t, len(dec.data), dec.cursor)
}
func TestDecoderObjectInvalidJSON(t *testing.T) {
result := jsonDecodePartial{}
dec := NewDecoder(nil)
dec.data = []byte(`{
"test2": "test",
"testArrSkip": ["test"],
"testSkipString": "testInvalidJSON\\\\
}`)
dec.length = len(dec.data)
err := dec.DecodeObject(&result)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}
type myMap map[string]string
func (m myMap) UnmarshalJSONObject(dec *Decoder, k string) error {
str := ""
err := dec.AddString(&str)
if err != nil {
return err
}
m[k] = str
return nil
}
// return 0 to parse all keys
func (m myMap) NKeys() int {
return 0
}
func TestDecoderObjectMap(t *testing.T) {
json := `{
"test": "string",
"test2": "string",
"test3": "string",
"test4": "string",
"test5": "string",
}`
m := myMap(make(map[string]string))
dec := BorrowDecoder(strings.NewReader(json))
err := dec.Decode(m)
assert.Nil(t, err, "err should be nil")
assert.Len(t, m, 5, "len of m should be 5")
}
func TestDecoderObjectDecoderAPI(t *testing.T) {
json := `{
"test": 245,
"test2": 246,
"test3": "string",
"test4": "complex string with spaces and some slashes\"",
"test5": -1.15657654376543,
"testNull": null,
"testArr": [
{
"test": 245,
"test2": 246
},
{
"test": 245,
"test2": 246
}
],
"testSubObj": {
"test": 121,
"test2": 122,
"testNull": null,
"testSubSubObj": {
"test": 150,
"testNull": null
},
"testSubSubObj2": {
"test": 150
},
"test3": "string"
"testNull": null,
},
"testSubObj2": {
"test": 122,
"test3": "string"
"testSubSubObj": {
"test": 151
},
"test2": 123
}
}`
v := &TestObj{}
dec := NewDecoder(strings.NewReader(json))
err := dec.DecodeObject(v)
assertResult(t, v, err)
}
type ReadCloser struct {
json []byte
}
func (r *ReadCloser) Read(b []byte) (int, error) {
copy(b, r.json)
return len(r.json), io.EOF
}
func TestDecoderObjectDecoderAPIReadCloser(t *testing.T) {
readCloser := ReadCloser{
json: []byte(`{
"test": "string",
"test2": "string",
"test3": "string",
"test4": "string",
"test5": "string",
}`),
}
m := myMap(make(map[string]string))
dec := NewDecoder(&readCloser)
err := dec.DecodeObject(m)
assert.Nil(t, err, "err should be nil")
assert.Len(t, m, 5, "len of m should be 5")
}
func TestDecoderObjectDecoderAPIFuncReadCloser(t *testing.T) {
readCloser := ReadCloser{
json: []byte(`{
"test": "string",
"test2": "string",
"test3": "string",
"test4": "string",
"test5": "string",
}`),
}
m := myMap(make(map[string]string))
dec := NewDecoder(&readCloser)
err := dec.DecodeObject(DecodeObjectFunc(func(dec *Decoder, k string) error {
str := ""
err := dec.AddString(&str)
if err != nil {
return err
}
m[k] = str
return nil
}))
assert.Nil(t, err, "err should be nil")
assert.Len(t, m, 5, "len of m should be 5")
}
func TestDecoderObjectDecoderInvalidJSONError(t *testing.T) {
v := &TestObj{}
dec := NewDecoder(strings.NewReader(`{"err:}`))
err := dec.DecodeObject(v)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}
func TestDecoderObjectDecoderInvalidJSONError2(t *testing.T) {
v := &TestSubObj{}
dec := NewDecoder(strings.NewReader(`{"err:}`))
err := dec.DecodeObject(v)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}
func TestDecoderObjectDecoderInvalidJSONError3(t *testing.T) {
v := &TestSubObj{}
dec := NewDecoder(strings.NewReader(`{"err":"test}`))
err := dec.DecodeObject(v)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}
func TestDecoderObjectDecoderInvalidJSONError4(t *testing.T) {
testArr := testSliceInts{}
dec := NewDecoder(strings.NewReader(`hello`))
err := dec.DecodeArray(&testArr)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}
func TestDecoderObjectPoolError(t *testing.T) {
result := jsonDecodePartial{}
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeObject(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
}
func TestNextKey(t *testing.T) {
testCases := []struct {
name string
json string
expectedValue string
err bool
}{
{
name: "basic",
json: `"key":"value"`,
expectedValue: "key",
},
{
name: "basic-err",
json: ``,
expectedValue: "",
err: true,
},
{
name: "basic-err2",
json: `"key"`,
expectedValue: "",
err: true,
},
{
name: "basic-err3",
json: `"key`,
expectedValue: "",
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
dec := BorrowDecoder(strings.NewReader(testCase.json))
s, _, err := dec.nextKey()
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
return
}
assert.Nil(t, err, "err should be nil")
assert.Equal(t, testCase.expectedValue, s, fmt.Sprintf("s should be '%s'", testCase.expectedValue))
})
}
}
func TestSkipObject(t *testing.T) {
testCases := []struct {
name string
json string
err bool
}{
{
name: "basic",
json: `"key":"value"}`,
},
{
name: "basic-escape-solidus",
json: `"key":"value\/solidus"}`,
},
{
name: "basic-escaped",
json: `"key":"value\\\\\\\" hello"}`,
},
{
name: "basic-escaped",
json: `"key":"value\\\\\\\\"}`,
},
{
name: "basic-err",
json: ``,
err: true,
},
{
name: "basic-err2",
json: `{"key":"value"`,
err: true,
},
{
name: "basic-err2",
json: `"key":"value\n"}`,
err: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
dec := BorrowDecoder(strings.NewReader(testCase.json))
defer dec.Release()
_, err := dec.skipObject()
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
return
}
assert.Nil(t, err, "err should be nil")
})
}
}
func TestSkipData(t *testing.T) {
testCases := []struct {
name string
err bool
json string
}{
{
name: "skip-bool-false-err",
json: `fulse`,
err: true,
},
{
name: "skip-bool-true-err",
json: `trou`,
err: true,
},
{
name: "skip-bool-null-err",
json: `nil`,
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.skipData()
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
} else {
assert.Nil(t, err, "err should be nil")
}
})
}
t.Run("error-invalid-json", func(t *testing.T) {
dec := NewDecoder(strings.NewReader(""))
err := dec.skipData()
assert.NotNil(t, err, "err should not be nil as data is empty")
assert.IsType(t, InvalidJSONError(""), err, "err should of type InvalidJSONError")
})
t.Run("skip-array-error-invalid-json", func(t *testing.T) {
dec := NewDecoder(strings.NewReader(""))
_, err := dec.skipArray()
assert.NotNil(t, err, "err should not be nil as data is empty")
assert.IsType(t, InvalidJSONError(""), err, "err should of type InvalidJSONError")
})
}
golang-github-francoispqt-gojay-1.2.13/decode_pool.go 0000664 0000000 0000000 00000002422 13653316651 0022577 0 ustar 00root root 0000000 0000000 package gojay
import (
"io"
"sync"
)
var decPool = sync.Pool{
New: newDecoderPool,
}
func init() {
for i := 0; i < 32; i++ {
decPool.Put(NewDecoder(nil))
}
}
// NewDecoder returns a new decoder.
// It takes an io.Reader implementation as data input.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
called: 0,
cursor: 0,
keysDone: 0,
err: nil,
r: r,
data: make([]byte, 512),
length: 0,
isPooled: 0,
}
}
func newDecoderPool() interface{} {
return NewDecoder(nil)
}
// BorrowDecoder borrows a Decoder from the pool.
// It takes an io.Reader implementation as data input.
//
// In order to benefit from the pool, a borrowed decoder must be released after usage.
func BorrowDecoder(r io.Reader) *Decoder {
return borrowDecoder(r, 512)
}
func borrowDecoder(r io.Reader, bufSize int) *Decoder {
dec := decPool.Get().(*Decoder)
dec.called = 0
dec.keysDone = 0
dec.cursor = 0
dec.err = nil
dec.r = r
dec.length = 0
dec.isPooled = 0
if bufSize > 0 {
dec.data = make([]byte, bufSize)
}
return dec
}
// Release sends back a Decoder to the pool.
// If a decoder is used after calling Release
// a panic will be raised with an InvalidUsagePooledDecoderError error.
func (dec *Decoder) Release() {
dec.isPooled = 1
decPool.Put(dec)
}
golang-github-francoispqt-gojay-1.2.13/decode_pool_test.go 0000664 0000000 0000000 00000000556 13653316651 0023644 0 ustar 00root root 0000000 0000000 package gojay
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecoderBorrowFromPoolSetBuffSize(t *testing.T) {
dec := borrowDecoder(nil, 512)
assert.Len(t, dec.data, 512, "data buffer should be of len 512")
}
func TestDecoderNewPool(t *testing.T) {
dec := newDecoderPool()
assert.IsType(t, &Decoder{}, dec, "dec should be a *Decoder")
}
golang-github-francoispqt-gojay-1.2.13/decode_slice.go 0000664 0000000 0000000 00000004046 13653316651 0022731 0 ustar 00root root 0000000 0000000 package gojay
// AddSliceString unmarshals the next JSON array of strings to the given *[]string s
func (dec *Decoder) AddSliceString(s *[]string) error {
return dec.SliceString(s)
}
// SliceString unmarshals the next JSON array of strings to the given *[]string s
func (dec *Decoder) SliceString(s *[]string) error {
err := dec.Array(DecodeArrayFunc(func(dec *Decoder) error {
var str string
if err := dec.String(&str); err != nil {
return err
}
*s = append(*s, str)
return nil
}))
if err != nil {
return err
}
return nil
}
// AddSliceInt unmarshals the next JSON array of integers to the given *[]int s
func (dec *Decoder) AddSliceInt(s *[]int) error {
return dec.SliceInt(s)
}
// SliceInt unmarshals the next JSON array of integers to the given *[]int s
func (dec *Decoder) SliceInt(s *[]int) error {
err := dec.Array(DecodeArrayFunc(func(dec *Decoder) error {
var i int
if err := dec.Int(&i); err != nil {
return err
}
*s = append(*s, i)
return nil
}))
if err != nil {
return err
}
return nil
}
// AddFloat64 unmarshals the next JSON array of floats to the given *[]float64 s
func (dec *Decoder) AddSliceFloat64(s *[]float64) error {
return dec.SliceFloat64(s)
}
// SliceFloat64 unmarshals the next JSON array of floats to the given *[]float64 s
func (dec *Decoder) SliceFloat64(s *[]float64) error {
err := dec.Array(DecodeArrayFunc(func(dec *Decoder) error {
var i float64
if err := dec.Float64(&i); err != nil {
return err
}
*s = append(*s, i)
return nil
}))
if err != nil {
return err
}
return nil
}
// AddBool unmarshals the next JSON array of boolegers to the given *[]bool s
func (dec *Decoder) AddSliceBool(s *[]bool) error {
return dec.SliceBool(s)
}
// SliceBool unmarshals the next JSON array of boolegers to the given *[]bool s
func (dec *Decoder) SliceBool(s *[]bool) error {
err := dec.Array(DecodeArrayFunc(func(dec *Decoder) error {
var b bool
if err := dec.Bool(&b); err != nil {
return err
}
*s = append(*s, b)
return nil
}))
if err != nil {
return err
}
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_slice_test.go 0000664 0000000 0000000 00000004336 13653316651 0023772 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
)
type slicesTestObject struct {
sliceString []string
sliceInt []int
sliceFloat64 []float64
sliceBool []bool
}
func (s *slicesTestObject) UnmarshalJSONObject(dec *Decoder, k string) error {
switch k {
case "sliceString":
return dec.AddSliceString(&s.sliceString)
case "sliceInt":
return dec.AddSliceInt(&s.sliceInt)
case "sliceFloat64":
return dec.AddSliceFloat64(&s.sliceFloat64)
case "sliceBool":
return dec.AddSliceBool(&s.sliceBool)
}
return nil
}
func (s *slicesTestObject) NKeys() int {
return 4
}
func TestDecodeSlices(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult slicesTestObject
err bool
}{
{
name: "basic slice string",
json: `{
"sliceString": ["foo","bar"]
}`,
expectedResult: slicesTestObject{
sliceString: []string{"foo", "bar"},
},
},
{
name: "basic slice bool",
json: `{
"sliceBool": [true,false]
}`,
expectedResult: slicesTestObject{
sliceBool: []bool{true, false},
},
},
{
name: "basic slice int",
json: `{
"sliceInt": [1,2,3]
}`,
expectedResult: slicesTestObject{
sliceInt: []int{1, 2, 3},
},
},
{
name: "basic slice float64",
json: `{
"sliceFloat64": [1.3,2.4,3.1]
}`,
expectedResult: slicesTestObject{
sliceFloat64: []float64{1.3, 2.4, 3.1},
},
},
{
name: "err slice float64",
json: `{
"sliceFloat64": [1.3",2.4,3.1]
}`,
err: true,
},
{
name: "err slice str",
json: `{
"sliceString": [",""]
}`,
err: true,
},
{
name: "err slice int",
json: `{
"sliceInt": [1t,2,3]
}`,
err: true,
},
{
name: "err slice bool",
json: `{
"sliceBool": [truo,false]
}`,
err: true,
},
}
for _, testCase := range testCases {
t.Run(
testCase.name,
func(t *testing.T) {
dec := BorrowDecoder(strings.NewReader(testCase.json))
var o slicesTestObject
err := dec.Decode(&o)
if testCase.err {
require.NotNil(t, err, "err should not be nil")
return
}
require.Nil(t, err, "err should be nil")
require.Equal(t, testCase.expectedResult, o)
},
)
}
}
golang-github-francoispqt-gojay-1.2.13/decode_sqlnull.go 0000664 0000000 0000000 00000007455 13653316651 0023333 0 ustar 00root root 0000000 0000000 package gojay
import "database/sql"
// DecodeSQLNullString decodes a sql.NullString
func (dec *Decoder) DecodeSQLNullString(v *sql.NullString) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeSQLNullString(v)
}
func (dec *Decoder) decodeSQLNullString(v *sql.NullString) error {
var str string
if err := dec.decodeString(&str); err != nil {
return err
}
v.String = str
v.Valid = true
return nil
}
// DecodeSQLNullInt64 decodes a sql.NullInt64
func (dec *Decoder) DecodeSQLNullInt64(v *sql.NullInt64) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeSQLNullInt64(v)
}
func (dec *Decoder) decodeSQLNullInt64(v *sql.NullInt64) error {
var i int64
if err := dec.decodeInt64(&i); err != nil {
return err
}
v.Int64 = i
v.Valid = true
return nil
}
// DecodeSQLNullFloat64 decodes a sql.NullString with the given format
func (dec *Decoder) DecodeSQLNullFloat64(v *sql.NullFloat64) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeSQLNullFloat64(v)
}
func (dec *Decoder) decodeSQLNullFloat64(v *sql.NullFloat64) error {
var i float64
if err := dec.decodeFloat64(&i); err != nil {
return err
}
v.Float64 = i
v.Valid = true
return nil
}
// DecodeSQLNullBool decodes a sql.NullString with the given format
func (dec *Decoder) DecodeSQLNullBool(v *sql.NullBool) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeSQLNullBool(v)
}
func (dec *Decoder) decodeSQLNullBool(v *sql.NullBool) error {
var b bool
if err := dec.decodeBool(&b); err != nil {
return err
}
v.Bool = b
v.Valid = true
return nil
}
// Add Values functions
// AddSQLNullString decodes the JSON value within an object or an array to qn *sql.NullString
func (dec *Decoder) AddSQLNullString(v *sql.NullString) error {
return dec.SQLNullString(v)
}
// SQLNullString decodes the JSON value within an object or an array to an *sql.NullString
func (dec *Decoder) SQLNullString(v *sql.NullString) error {
var b *string
if err := dec.StringNull(&b); err != nil {
return err
}
if b == nil {
v.Valid = false
} else {
v.String = *b
v.Valid = true
}
return nil
}
// AddSQLNullInt64 decodes the JSON value within an object or an array to qn *sql.NullInt64
func (dec *Decoder) AddSQLNullInt64(v *sql.NullInt64) error {
return dec.SQLNullInt64(v)
}
// SQLNullInt64 decodes the JSON value within an object or an array to an *sql.NullInt64
func (dec *Decoder) SQLNullInt64(v *sql.NullInt64) error {
var b *int64
if err := dec.Int64Null(&b); err != nil {
return err
}
if b == nil {
v.Valid = false
} else {
v.Int64 = *b
v.Valid = true
}
return nil
}
// AddSQLNullFloat64 decodes the JSON value within an object or an array to qn *sql.NullFloat64
func (dec *Decoder) AddSQLNullFloat64(v *sql.NullFloat64) error {
return dec.SQLNullFloat64(v)
}
// SQLNullFloat64 decodes the JSON value within an object or an array to an *sql.NullFloat64
func (dec *Decoder) SQLNullFloat64(v *sql.NullFloat64) error {
var b *float64
if err := dec.Float64Null(&b); err != nil {
return err
}
if b == nil {
v.Valid = false
} else {
v.Float64 = *b
v.Valid = true
}
return nil
}
// AddSQLNullBool decodes the JSON value within an object or an array to an *sql.NullBool
func (dec *Decoder) AddSQLNullBool(v *sql.NullBool) error {
return dec.SQLNullBool(v)
}
// SQLNullBool decodes the JSON value within an object or an array to an *sql.NullBool
func (dec *Decoder) SQLNullBool(v *sql.NullBool) error {
var b *bool
if err := dec.BoolNull(&b); err != nil {
return err
}
if b == nil {
v.Valid = false
} else {
v.Bool = *b
v.Valid = true
}
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_sqlnull_test.go 0000664 0000000 0000000 00000021244 13653316651 0024362 0 ustar 00root root 0000000 0000000 package gojay
import (
"database/sql"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDecodeSQLNullString(t *testing.T) {
testCases := []struct {
name string
json string
expectedNullString sql.NullString
err bool
}{
{
name: "basic",
json: `"test"`,
expectedNullString: sql.NullString{String: "test", Valid: true},
},
{
name: "basic",
json: `"test`,
expectedNullString: sql.NullString{String: "test", Valid: true},
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
nullString := sql.NullString{}
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.DecodeSQLNullString(&nullString)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedNullString, nullString)
}
})
}
t.Run(
"should panic because decoder is pooled",
func(t *testing.T) {
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeSQLNullString(&sql.NullString{})
assert.True(t, false, "should not be called as decoder should have panicked")
},
)
}
func TestDecodeSQLNullInt64(t *testing.T) {
testCases := []struct {
name string
json string
expectedNullInt64 sql.NullInt64
err bool
}{
{
name: "basic",
json: `1`,
expectedNullInt64: sql.NullInt64{Int64: 1, Valid: true},
},
{
name: "basic",
json: `"test`,
expectedNullInt64: sql.NullInt64{Int64: 1, Valid: true},
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
nullInt64 := sql.NullInt64{}
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.DecodeSQLNullInt64(&nullInt64)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedNullInt64, nullInt64)
}
})
}
t.Run(
"should panic because decoder is pooled",
func(t *testing.T) {
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeSQLNullInt64(&sql.NullInt64{})
assert.True(t, false, "should not be called as decoder should have panicked")
},
)
}
func TestDecodeSQLNullFloat64(t *testing.T) {
testCases := []struct {
name string
json string
expectedNullFloat64 sql.NullFloat64
err bool
}{
{
name: "basic",
json: `1`,
expectedNullFloat64: sql.NullFloat64{Float64: 1, Valid: true},
},
{
name: "basic",
json: `"test`,
expectedNullFloat64: sql.NullFloat64{Float64: 1, Valid: true},
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
nullFloat64 := sql.NullFloat64{}
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.DecodeSQLNullFloat64(&nullFloat64)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedNullFloat64, nullFloat64)
}
})
}
t.Run(
"should panic because decoder is pooled",
func(t *testing.T) {
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeSQLNullFloat64(&sql.NullFloat64{})
assert.True(t, false, "should not be called as decoder should have panicked")
},
)
}
func TestDecodeSQLNullBool(t *testing.T) {
testCases := []struct {
name string
json string
expectedNullBool sql.NullBool
err bool
}{
{
name: "basic",
json: `true`,
expectedNullBool: sql.NullBool{Bool: true, Valid: true},
},
{
name: "basic",
json: `"&`,
expectedNullBool: sql.NullBool{Bool: true, Valid: true},
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
nullBool := sql.NullBool{}
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.DecodeSQLNullBool(&nullBool)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedNullBool, nullBool)
}
})
}
t.Run(
"should panic because decoder is pooled",
func(t *testing.T) {
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeSQLNullBool(&sql.NullBool{})
assert.True(t, false, "should not be called as decoder should have panicked")
},
)
}
type SQLDecodeObject struct {
S sql.NullString
F sql.NullFloat64
I sql.NullInt64
B sql.NullBool
}
func (s *SQLDecodeObject) UnmarshalJSONObject(dec *Decoder, k string) error {
switch k {
case "s":
return dec.AddSQLNullString(&s.S)
case "f":
return dec.AddSQLNullFloat64(&s.F)
case "i":
return dec.AddSQLNullInt64(&s.I)
case "b":
return dec.AddSQLNullBool(&s.B)
}
return nil
}
func (s *SQLDecodeObject) NKeys() int {
return 0
}
func TestDecodeSQLNullKeys(t *testing.T) {
var testCases = []struct {
name string
json string
expectedResult *SQLDecodeObject
err bool
}{
{
name: "basic all valid",
json: `{
"s": "foo",
"f": 0.3,
"i": 3,
"b": true
}`,
expectedResult: &SQLDecodeObject{
S: sql.NullString{
String: "foo",
Valid: true,
},
F: sql.NullFloat64{
Float64: 0.3,
Valid: true,
},
I: sql.NullInt64{
Int64: 3,
Valid: true,
},
B: sql.NullBool{
Bool: true,
Valid: true,
},
},
},
{
name: "string not valid",
json: `{
"s": null,
"f": 0.3,
"i": 3,
"b": true
}`,
expectedResult: &SQLDecodeObject{
S: sql.NullString{
Valid: false,
},
F: sql.NullFloat64{
Float64: 0.3,
Valid: true,
},
I: sql.NullInt64{
Int64: 3,
Valid: true,
},
B: sql.NullBool{
Bool: true,
Valid: true,
},
},
},
{
name: "string not valid, int not valid",
json: `{
"s": null,
"f": 0.3,
"i": null,
"b": true
}`,
expectedResult: &SQLDecodeObject{
S: sql.NullString{
Valid: false,
},
F: sql.NullFloat64{
Float64: 0.3,
Valid: true,
},
I: sql.NullInt64{
Valid: false,
},
B: sql.NullBool{
Bool: true,
Valid: true,
},
},
},
{
name: "keys absent",
json: `{
"f": 0.3,
"i": 3,
"b": true
}`,
expectedResult: &SQLDecodeObject{
S: sql.NullString{
Valid: false,
},
F: sql.NullFloat64{
Float64: 0.3,
Valid: true,
},
I: sql.NullInt64{
Valid: true,
Int64: 3,
},
B: sql.NullBool{
Bool: true,
Valid: true,
},
},
},
{
name: "keys all null",
json: `{
"s": null,
"f": null,
"i": null,
"b": null
}`,
expectedResult: &SQLDecodeObject{
S: sql.NullString{
Valid: false,
},
F: sql.NullFloat64{
Valid: false,
},
I: sql.NullInt64{
Valid: false,
},
B: sql.NullBool{
Valid: false,
},
},
},
{
name: "err string key",
json: `{
"s": "`,
err: true,
},
{
name: "err float key",
json: `{
"s": null,
"f": 1",
"i": null,
"b": null
}`,
err: true,
},
{
name: "err int key",
json: `{
"s": null,
"f": null,
"i": 1",
"b": null
}`,
err: true,
},
{
name: "err bool key",
json: `{
"s": null,
"f": null,
"i": null,
"b": tra
}`,
err: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var o = &SQLDecodeObject{}
var dec = NewDecoder(strings.NewReader(testCase.json))
var err = dec.Decode(o)
if testCase.err {
require.NotNil(t, err)
return
}
require.Nil(t, err)
require.Equal(
t,
testCase.expectedResult,
o,
)
})
}
}
golang-github-francoispqt-gojay-1.2.13/decode_stream.go 0000664 0000000 0000000 00000005752 13653316651 0023132 0 ustar 00root root 0000000 0000000 package gojay
import (
"sync"
"time"
)
// UnmarshalerStream is the interface to implement for a slice, an array or a slice
// to decode a line delimited JSON to.
type UnmarshalerStream interface {
UnmarshalStream(*StreamDecoder) error
}
// Stream is a struct holding the Stream api
var Stream = stream{}
type stream struct{}
// A StreamDecoder reads and decodes JSON values from an input stream.
//
// It implements conext.Context and provide a channel to notify interruption.
type StreamDecoder struct {
mux sync.RWMutex
*Decoder
done chan struct{}
deadline *time.Time
}
// DecodeStream reads the next line delimited JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by c.
//
// c must implement UnmarshalerStream. Ideally c is a channel. See example for implementation.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *StreamDecoder) DecodeStream(c UnmarshalerStream) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
if dec.r == nil {
dec.err = NoReaderError("No reader given to decode stream")
close(dec.done)
return dec.err
}
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
continue
default:
// char is not space start reading
for dec.nextChar() != 0 {
// calling unmarshal stream
err := c.UnmarshalStream(dec)
if err != nil {
dec.err = err
close(dec.done)
return err
}
// garbage collects buffer
// we don't want the buffer to grow extensively
dec.data = dec.data[dec.cursor:]
dec.length = dec.length - dec.cursor
dec.cursor = 0
}
// close the done channel to signal the end of the job
close(dec.done)
return nil
}
}
close(dec.done)
dec.mux.Lock()
err := dec.raiseInvalidJSONErr(dec.cursor)
dec.mux.Unlock()
return err
}
// context.Context implementation
// Done returns a channel that's closed when work is done.
// It implements context.Context
func (dec *StreamDecoder) Done() <-chan struct{} {
return dec.done
}
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
func (dec *StreamDecoder) Deadline() (time.Time, bool) {
if dec.deadline != nil {
return *dec.deadline, true
}
return time.Time{}, false
}
// SetDeadline sets the deadline
func (dec *StreamDecoder) SetDeadline(t time.Time) {
dec.deadline = &t
}
// Err returns nil if Done is not yet closed.
// If Done is closed, Err returns a non-nil error explaining why.
// It implements context.Context
func (dec *StreamDecoder) Err() error {
select {
case <-dec.done:
dec.mux.RLock()
defer dec.mux.RUnlock()
return dec.err
default:
return nil
}
}
// Value implements context.Context
func (dec *StreamDecoder) Value(key interface{}) interface{} {
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_stream_pool.go 0000664 0000000 0000000 00000002757 13653316651 0024165 0 ustar 00root root 0000000 0000000 package gojay
import (
"io"
"sync"
)
var streamDecPool = sync.Pool{
New: newStreamDecoderPool,
}
// NewDecoder returns a new StreamDecoder.
// It takes an io.Reader implementation as data input.
// It initiates the done channel returned by Done().
func (s stream) NewDecoder(r io.Reader) *StreamDecoder {
dec := NewDecoder(r)
streamDec := &StreamDecoder{
Decoder: dec,
done: make(chan struct{}, 1),
mux: sync.RWMutex{},
}
return streamDec
}
func newStreamDecoderPool() interface{} {
return Stream.NewDecoder(nil)
}
// BorrowDecoder borrows a StreamDecoder from the pool.
// It takes an io.Reader implementation as data input.
// It initiates the done channel returned by Done().
//
// If no StreamEncoder is available in the pool, it returns a fresh one
func (s stream) BorrowDecoder(r io.Reader) *StreamDecoder {
return s.borrowDecoder(r, 512)
}
func (s stream) borrowDecoder(r io.Reader, bufSize int) *StreamDecoder {
streamDec := streamDecPool.Get().(*StreamDecoder)
streamDec.called = 0
streamDec.keysDone = 0
streamDec.cursor = 0
streamDec.err = nil
streamDec.r = r
streamDec.length = 0
streamDec.isPooled = 0
streamDec.done = make(chan struct{}, 1)
if bufSize > 0 {
streamDec.data = make([]byte, bufSize)
}
return streamDec
}
// Release sends back a Decoder to the pool.
// If a decoder is used after calling Release
// a panic will be raised with an InvalidUsagePooledDecoderError error.
func (dec *StreamDecoder) Release() {
dec.isPooled = 1
streamDecPool.Put(dec)
}
golang-github-francoispqt-gojay-1.2.13/decode_stream_pool_test.go 0000664 0000000 0000000 00000003527 13653316651 0025220 0 ustar 00root root 0000000 0000000 package gojay
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeStreamDecodePooledDecoderError(t *testing.T) {
// we override the pool chan
dec := Stream.NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
var v = 0
dec.Decode(&v)
// make sure it fails if this is called
assert.True(t, false, "should not be called as decoder should have panicked")
}
func TestDecodeStreamDecodePooledDecoderError1(t *testing.T) {
// we override the pool chan
dec := Stream.NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
var v = testSliceStrings{}
dec.DecodeArray(&v)
// make sure they are the same
assert.True(t, false, "should not be called as decoder should have panicked")
}
func TestDecodeStreamDecodePooledDecoderError2(t *testing.T) {
// we override the pool chan
dec := Stream.NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
assert.Equal(t, "Invalid usage of pooled decoder", err.(InvalidUsagePooledDecoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
var v = TestObj{}
dec.DecodeObject(&v)
// make sure they are the same
assert.True(t, false, "should not be called as decoder should have panicked")
}
func TestStreamDecoderNewPool(t *testing.T) {
dec := newStreamDecoderPool()
assert.IsType(t, &StreamDecoder{}, dec, "dec should be a *StreamDecoder")
}
golang-github-francoispqt-gojay-1.2.13/decode_stream_test.go 0000664 0000000 0000000 00000033161 13653316651 0024164 0 ustar 00root root 0000000 0000000 package gojay
import (
"context"
"errors"
"io"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
// Basic Behaviour Tests
//
func TestDecoderImplementsContext(t *testing.T) {
var dec interface{} = &StreamDecoder{}
_ = dec.(context.Context)
}
func TestDecodeStreamNoReader(t *testing.T) {
dec := Stream.NewDecoder(nil)
dec.done = make(chan struct{}, 1)
testChan := ChannelStreamObjects(make(chan *TestObj))
go dec.DecodeStream(&testChan)
select {
case <-dec.Done():
assert.NotNil(t, dec.Err(), "dec.Err() should not be nil")
assert.Equal(t, "No reader given to decode stream", dec.Err().Error(), "dec.Err().Error() should not be 'No reader given to decode stream'")
case <-testChan:
assert.True(t, false, "should not be called as decoder should not return error right away")
}
}
// Table Tests
// Objects
type StreamTestObject struct {
name string
streamReader *StreamReader
expectations func(error, []*TestObj, *testing.T)
}
func TestStreamDecodingObjectsParallel(t *testing.T) {
var tests = []StreamTestObject{
{
name: "Stream objects",
streamReader: &StreamReader{
readChan: make(chan string),
done: make(chan struct{}),
data: `
{"test":246,"test2":-246,"test3":"string"}
{"test":247,"test2":248,"test3":"string"}
{"test":777,"test2":456,"test3":"string"}
{"test":777,"test2":456,"test3":"string"}
{"test":777,"test2":456,"test3":"string"}
{"test":777,"test2":456,"test3":"string"}
`,
},
expectations: func(err error, result []*TestObj, t *testing.T) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, 246, result[0].test, "v[0].test should be equal to 246")
assert.Equal(t, -246, result[0].test2, "v[0].test2 should be equal to -247")
assert.Equal(t, "string", result[0].test3, "v[0].test3 should be equal to \"string\"")
assert.Equal(t, 247, result[1].test, "result[1].test should be equal to 246")
assert.Equal(t, 248, result[1].test2, "result[1].test2 should be equal to 248")
assert.Equal(t, "string", result[1].test3, "result[1].test3 should be equal to \"string\"")
assert.Equal(t, 777, result[2].test, "result[2].test should be equal to 777")
assert.Equal(t, 456, result[2].test2, "result[2].test2 should be equal to 456")
assert.Equal(t, "string", result[2].test3, "result[2].test3 should be equal to \"string\"")
assert.Equal(t, 777, result[3].test, "result[3].test should be equal to 777")
assert.Equal(t, 456, result[3].test2, "result[3].test2 should be equal to 456")
assert.Equal(t, "string", result[3].test3, "result[3].test3 should be equal to \"string\"")
assert.Equal(t, 777, result[4].test, "result[4].test should be equal to 777")
assert.Equal(t, 456, result[4].test2, "result[4].test2 should be equal to 456")
assert.Equal(t, "string", result[4].test3, "result[4].test3 should be equal to \"string\"")
assert.Equal(t, 777, result[5].test, "result[5].test should be equal to 777")
assert.Equal(t, 456, result[5].test2, "result[5].test2 should be equal to 456")
assert.Equal(t, "string", result[5].test3, "result[5].test3 should be equal to \"string\"")
},
},
{
name: "Stream test objects with null values",
streamReader: &StreamReader{
readChan: make(chan string),
done: make(chan struct{}),
data: `
{"test":246,"test2":-246,"test3":"string"}
{"test":247,"test2":248,"test3":"string"}
null
{"test":777,"test2":456,"test3":"string"}
{"test":777,"test2":456,"test3":"string"}
{"test":777,"test2":456,"test3":"string"}
`,
},
expectations: func(err error, result []*TestObj, t *testing.T) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, 246, result[0].test, "v[0].test should be equal to 246")
assert.Equal(t, -246, result[0].test2, "v[0].test2 should be equal to -247")
assert.Equal(t, "string", result[0].test3, "v[0].test3 should be equal to \"string\"")
assert.Equal(t, 247, result[1].test, "result[1].test should be equal to 246")
assert.Equal(t, 248, result[1].test2, "result[1].test2 should be equal to 248")
assert.Equal(t, "string", result[1].test3, "result[1].test3 should be equal to \"string\"")
assert.Equal(t, 0, result[2].test, "result[2].test should be equal to 0 as input is null")
assert.Equal(t, 0, result[2].test2, "result[2].test2 should be equal to 0 as input is null")
assert.Equal(t, "", result[2].test3, "result[2].test3 should be equal to \"\" as input is null")
assert.Equal(t, 777, result[3].test, "result[3].test should be equal to 777")
assert.Equal(t, 456, result[3].test2, "result[3].test2 should be equal to 456")
assert.Equal(t, "string", result[3].test3, "result[3].test3 should be equal to \"string\"")
assert.Equal(t, 777, result[4].test, "result[4].test should be equal to 777")
assert.Equal(t, 456, result[4].test2, "result[4].test2 should be equal to 456")
assert.Equal(t, "string", result[4].test3, "result[4].test3 should be equal to \"string\"")
assert.Equal(t, 777, result[5].test, "result[5].test should be equal to 777")
assert.Equal(t, 456, result[5].test2, "result[5].test2 should be equal to 456")
assert.Equal(t, "string", result[5].test3, "result[5].test3 should be equal to \"string\"")
},
},
{
name: "Stream test starting with null values",
streamReader: &StreamReader{
readChan: make(chan string),
done: make(chan struct{}),
data: `
null
{"test":246,"test2":-246,"test3":"string"}
{"test":247,"test2":248,"test3":"string"}
`,
},
expectations: func(err error, result []*TestObj, t *testing.T) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, 0, result[0].test, "result[0].test should be equal to 0 as input is null")
assert.Equal(t, 0, result[0].test2, "result[0].test2 should be equal to 0 as input is null")
assert.Equal(t, "", result[0].test3, "result[0].test3 should be equal to \"\" as input is null")
assert.Equal(t, 246, result[1].test, "v[1].test should be equal to 246")
assert.Equal(t, -246, result[1].test2, "v[1].test2 should be equal to -247")
assert.Equal(t, "string", result[1].test3, "v[1].test3 should be equal to \"string\"")
assert.Equal(t, 247, result[2].test, "result[2].test should be equal to 246")
assert.Equal(t, 248, result[2].test2, "result[2].test2 should be equal to 248")
assert.Equal(t, "string", result[2].test3, "result[2].test3 should be equal to \"string\"")
},
},
{
name: "Stream test invalid JSON",
streamReader: &StreamReader{
readChan: make(chan string),
done: make(chan struct{}),
data: `
invalid json
{"test":246,"test2":-246,"test3":"string"}
{"test":247,"test2":248,"test3":"string"}
`,
},
expectations: func(err error, result []*TestObj, t *testing.T) {
assert.NotNil(t, err, "err is not nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err is of type InvalidJSONError")
assert.Equal(t, "Invalid JSON, wrong char 'i' found at position 6", err.Error(), "err message is Invalid JSON")
},
},
}
for _, testCase := range tests {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
runStreamTestCaseObjects(t, testCase)
})
}
}
func runStreamTestCaseObjects(t *testing.T, testCase StreamTestObject) {
// create our channel which will receive our objects
testChan := ChannelStreamObjects(make(chan *TestObj))
dec := Stream.NewDecoder(testCase.streamReader)
// start decoding (will block the goroutine until something is written to the ReadWriter)
go dec.DecodeStream(&testChan)
// start writing to the ReadWriter
go testCase.streamReader.Write()
// prepare our result
result := []*TestObj{}
loop:
for {
select {
case v := <-testChan:
result = append(result, v)
case <-dec.Done():
break loop
}
}
testCase.expectations(dec.Err(), result, t)
}
type ChannelStreamObjects chan *TestObj
func (c *ChannelStreamObjects) UnmarshalStream(dec *StreamDecoder) error {
obj := &TestObj{}
if err := dec.AddObject(obj); err != nil {
return err
}
*c <- obj
return nil
}
// Strings
type StreamTestString struct {
name string
streamReader *StreamReader
expectations func(error, []*string, *testing.T)
}
func TestStreamDecodingStringsParallel(t *testing.T) {
var tests = []StreamTestString{
{
name: "Stream strings basic",
streamReader: &StreamReader{
readChan: make(chan string),
done: make(chan struct{}),
data: `
"hello"
"world"
"!"
`,
},
expectations: func(err error, result []*string, t *testing.T) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "hello", *result[0], "v[0] should be equal to 'hello'")
assert.Equal(t, "world", *result[1], "v[1] should be equal to 'world'")
assert.Equal(t, "!", *result[2], "v[2] should be equal to '!'")
},
},
{
name: "Stream strings with null",
streamReader: &StreamReader{
readChan: make(chan string),
done: make(chan struct{}),
data: `
"hello"
null
"!"
`,
},
expectations: func(err error, result []*string, t *testing.T) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "hello", *result[0], "v[0] should be equal to 'hello'")
assert.Equal(t, "", *result[1], "v[1] should be equal to ''")
assert.Equal(t, "!", *result[2], "v[2] should be equal to '!'")
},
},
{
name: "Stream strings invalid JSON",
streamReader: &StreamReader{
readChan: make(chan string),
done: make(chan struct{}),
data: `
"hello"
world
"!"
`,
},
expectations: func(err error, result []*string, t *testing.T) {
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err is of type InvalidJSONError")
assert.Equal(t, "Invalid JSON, wrong char 'w' found at position 6", err.Error(), "err message is Invalid JSON")
},
},
}
for _, testCase := range tests {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
runStreamTestCaseStrings(t, testCase)
})
}
}
func runStreamTestCaseStrings(t *testing.T, testCase StreamTestString) {
// create our channel which will receive our objects
testChan := ChannelStreamStrings(make(chan *string))
dec := Stream.NewDecoder(testCase.streamReader)
// start decoding (will block the goroutine until something is written to the ReadWriter)
go dec.DecodeStream(testChan)
// start writing to the ReadWriter
go testCase.streamReader.Write()
// prepare our result
result := []*string{}
loop:
for {
select {
case v := <-testChan:
result = append(result, v)
case <-dec.Done():
break loop
}
}
testCase.expectations(dec.Err(), result, t)
}
func TestStreamDecodingErr(t *testing.T) {
testChan := ChannelStreamStrings(make(chan *string))
dec := Stream.NewDecoder(&StreamReaderErr{})
// start decoding (will block the goroutine until something is written to the ReadWriter)
go dec.DecodeStream(testChan)
select {
case <-dec.Done():
assert.NotNil(t, dec.Err(), "dec.Err() should not be nil")
case <-testChan:
assert.True(t, false, "should not be called")
}
}
type ChannelStreamStrings chan *string
func (c ChannelStreamStrings) UnmarshalStream(dec *StreamDecoder) error {
str := ""
if err := dec.AddString(&str); err != nil {
return err
}
c <- &str
return nil
}
// StreamReader mocks a stream reading chunks of data
type StreamReader struct {
writeCounter int
readChan chan string
done chan struct{}
data string
}
func (r *StreamReader) Write() {
l := len(r.data)
t := 4
chunkSize := l / t
carry := 0
lastWrite := 0
for r.writeCounter < t {
time.Sleep(time.Duration(r.writeCounter*100) * time.Millisecond)
currentChunkStart := (chunkSize) * r.writeCounter
lastWrite = currentChunkStart + chunkSize
r.readChan <- r.data[currentChunkStart:lastWrite]
carry = l - lastWrite
r.writeCounter++
}
if carry > 0 {
r.readChan <- r.data[lastWrite:]
}
r.done <- struct{}{}
}
func (r *StreamReader) Read(b []byte) (int, error) {
select {
case v := <-r.readChan:
n := copy(b, v)
return n, nil
case <-r.done:
return 0, io.EOF
}
}
type StreamReaderErr struct{}
func (r *StreamReaderErr) Read(b []byte) (int, error) {
return 0, errors.New("Test Error")
}
// Deadline test
func TestStreamDecodingDeadline(t *testing.T) {
dec := Stream.NewDecoder(&StreamReader{})
now := time.Now()
dec.SetDeadline(now)
deadline, _ := dec.Deadline()
assert.Equal(t, now.String(), deadline.String(), "dec.now and now should be equal")
assert.Equal(t, now.String(), dec.deadline.String(), "dec.now and now should be equal")
}
func TestStreamDecodingDeadlineNotSet(t *testing.T) {
dec := Stream.NewDecoder(&StreamReader{})
_, isSet := dec.Deadline()
assert.Equal(t, false, isSet, "isSet should be false as deadline is not set")
}
// this test is only relevant for coverage
func TestStreamDecodingValue(t *testing.T) {
dec := Stream.NewDecoder(&StreamReader{})
v := dec.Value("")
assert.Nil(t, v, "v should be nil")
}
func TestStreamDecodingErrNotSet(t *testing.T) {
dec := Stream.NewDecoder(&StreamReader{})
assert.Nil(t, dec.Err(), "dec.Err should be nim")
}
func TestStreamDecodingPoolError(t *testing.T) {
dec := Stream.BorrowDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled decoder", err.(InvalidUsagePooledDecoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
testChan := ChannelStreamStrings(make(chan *string))
_ = dec.DecodeStream(testChan)
assert.True(t, false, "should not be called as it should have panicked")
}
golang-github-francoispqt-gojay-1.2.13/decode_string.go 0000664 0000000 0000000 00000014267 13653316651 0023146 0 ustar 00root root 0000000 0000000 package gojay
import (
"unsafe"
)
// DecodeString reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the string pointed to by v.
//
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
func (dec *Decoder) DecodeString(v *string) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeString(v)
}
func (dec *Decoder) decodeString(v *string) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
// is string
continue
case '"':
dec.cursor++
start, end, err := dec.getString()
if err != nil {
return err
}
// we do minus one to remove the last quote
d := dec.data[start : end-1]
*v = *(*string)(unsafe.Pointer(&d))
dec.cursor = end
return nil
// is nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return nil
}
func (dec *Decoder) decodeStringNull(v **string) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
case ' ', '\n', '\t', '\r', ',':
// is string
continue
case '"':
dec.cursor++
start, end, err := dec.getString()
if err != nil {
return err
}
if *v == nil {
*v = new(string)
}
// we do minus one to remove the last quote
d := dec.data[start : end-1]
**v = *(*string)(unsafe.Pointer(&d))
dec.cursor = end
return nil
// is nil
case 'n':
dec.cursor++
err := dec.assertNull()
if err != nil {
return err
}
return nil
default:
dec.err = dec.makeInvalidUnmarshalErr(v)
err := dec.skipData()
if err != nil {
return err
}
return nil
}
}
return nil
}
func (dec *Decoder) parseEscapedString() error {
if dec.cursor >= dec.length && !dec.read() {
return dec.raiseInvalidJSONErr(dec.cursor)
}
switch dec.data[dec.cursor] {
case '"':
dec.data[dec.cursor] = '"'
case '\\':
dec.data[dec.cursor] = '\\'
case '/':
dec.data[dec.cursor] = '/'
case 'b':
dec.data[dec.cursor] = '\b'
case 'f':
dec.data[dec.cursor] = '\f'
case 'n':
dec.data[dec.cursor] = '\n'
case 'r':
dec.data[dec.cursor] = '\r'
case 't':
dec.data[dec.cursor] = '\t'
case 'u':
start := dec.cursor
dec.cursor++
str, err := dec.parseUnicode()
if err != nil {
return err
}
diff := dec.cursor - start
dec.data = append(append(dec.data[:start-1], str...), dec.data[dec.cursor:]...)
dec.length = len(dec.data)
dec.cursor += len(str) - diff - 1
return nil
default:
return dec.raiseInvalidJSONErr(dec.cursor)
}
dec.data = append(dec.data[:dec.cursor-1], dec.data[dec.cursor:]...)
dec.length--
// Since we've lost a character, our dec.cursor offset is now
// 1 past the escaped character which is precisely where we
// want it.
return nil
}
func (dec *Decoder) getString() (int, int, error) {
// extract key
var keyStart = dec.cursor
// var str *Builder
for dec.cursor < dec.length || dec.read() {
switch dec.data[dec.cursor] {
// string found
case '"':
dec.cursor = dec.cursor + 1
return keyStart, dec.cursor, nil
// slash found
case '\\':
dec.cursor = dec.cursor + 1
err := dec.parseEscapedString()
if err != nil {
return 0, 0, err
}
default:
dec.cursor = dec.cursor + 1
continue
}
}
return 0, 0, dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) skipEscapedString() error {
start := dec.cursor
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
if dec.data[dec.cursor] != '\\' {
d := dec.data[dec.cursor]
dec.cursor = dec.cursor + 1
nSlash := dec.cursor - start
switch d {
case '"':
// nSlash must be odd
if nSlash&1 != 1 {
return dec.raiseInvalidJSONErr(dec.cursor)
}
return nil
case 'u': // is unicode, we skip the following characters and place the cursor one one byte backward to avoid it breaking when returning to skipString
if err := dec.skipString(); err != nil {
return err
}
dec.cursor--
return nil
case 'n', 'r', 't', '/', 'f', 'b':
return nil
default:
// nSlash must be even
if nSlash&1 == 1 {
return dec.raiseInvalidJSONErr(dec.cursor)
}
return nil
}
}
}
return dec.raiseInvalidJSONErr(dec.cursor)
}
func (dec *Decoder) skipString() error {
for dec.cursor < dec.length || dec.read() {
switch dec.data[dec.cursor] {
// found the closing quote
// let's return
case '"':
dec.cursor = dec.cursor + 1
return nil
// solidus found start parsing an escaped string
case '\\':
dec.cursor = dec.cursor + 1
err := dec.skipEscapedString()
if err != nil {
return err
}
default:
dec.cursor = dec.cursor + 1
continue
}
}
return dec.raiseInvalidJSONErr(len(dec.data) - 1)
}
// Add Values functions
// AddString decodes the JSON value within an object or an array to a *string.
// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned.
func (dec *Decoder) AddString(v *string) error {
return dec.String(v)
}
// AddStringNull decodes the JSON value within an object or an array to a *string.
// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) AddStringNull(v **string) error {
return dec.StringNull(v)
}
// String decodes the JSON value within an object or an array to a *string.
// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned.
func (dec *Decoder) String(v *string) error {
err := dec.decodeString(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
// StringNull decodes the JSON value within an object or an array to a **string.
// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned.
// If a `null` is encountered, gojay does not change the value of the pointer.
func (dec *Decoder) StringNull(v **string) error {
err := dec.decodeStringNull(v)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_string_test.go 0000664 0000000 0000000 00000045737 13653316651 0024213 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"strings"
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecoderString(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult string
err bool
errType interface{}
}{
{
name: "basic-string",
json: `"string"`,
expectedResult: "string",
err: false,
},
{
name: "string-solidus",
json: `"\/"`,
expectedResult: "/",
err: false,
},
{
name: "basic-string",
json: ``,
expectedResult: "",
err: false,
},
{
name: "basic-string",
json: `""`,
expectedResult: "",
err: false,
},
{
name: "basic-string2",
json: `"hello world!"`,
expectedResult: "hello world!",
err: false,
},
{
name: "escape-control-char",
json: `"\n"`,
expectedResult: "\n",
err: false,
},
{
name: "escape-control-char",
json: `"\\n"`,
expectedResult: `\n`,
err: false,
},
{
name: "escape-control-char",
json: `"\t"`,
expectedResult: "\t",
err: false,
},
{
name: "escape-control-char",
json: `"\\t"`,
expectedResult: `\t`,
err: false,
},
{
name: "escape-control-char",
json: `"\b"`,
expectedResult: "\b",
err: false,
},
{
name: "escape-control-char",
json: `"\\b"`,
expectedResult: `\b`,
err: false,
},
{
name: "escape-control-char",
json: `"\f"`,
expectedResult: "\f",
err: false,
},
{
name: "escape-control-char",
json: `"\\f"`,
expectedResult: `\f`,
err: false,
},
{
name: "escape-control-char",
json: `"\r"`,
expectedResult: "\r",
err: false,
},
{
name: "escape-control-char",
json: `"\`,
expectedResult: "",
err: true,
},
{
name: "escape-control-char-solidus",
json: `"\/"`,
expectedResult: "/",
err: false,
},
{
name: "escape-control-char-solidus",
json: `"/"`,
expectedResult: "/",
err: false,
},
{
name: "escape-control-char-solidus-escape-char",
json: `"\\/"`,
expectedResult: `\/`,
err: false,
},
{
name: "escape-control-char",
json: `"\\r"`,
expectedResult: `\r`,
err: false,
},
{
name: "utf8",
json: `"𠜎 𠜱 ð ¹ ð ±“ 𠱸 ð ²– ð ³ ð ³• ð ´• ð µ¼ 𠵿"`,
expectedResult: "𠜎 𠜱 ð ¹ ð ±“ 𠱸 ð ²– ð ³ ð ³• ð ´• ð µ¼ 𠵿",
err: false,
},
{
name: "utf8-code-point",
json: `"\u06fc"`,
expectedResult: `Û¼`,
err: false,
},
{
name: "utf8-code-point-escaped",
json: `"\\u2070"`,
expectedResult: `\u2070`,
err: false,
},
{
name: "utf8-code-point-err",
json: `"\u2Z70"`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate",
json: `"\uD834\uDD1E"`,
expectedResult: `ð„ž`,
err: false,
},
{
name: "utf16-surrogate",
json: `"\uD834\\"`,
expectedResult: `�\`,
err: false,
},
{
name: "utf16-surrogate",
json: `"\uD834\uD834"`,
expectedResult: "�\x00\x00\x00",
err: false,
},
{
name: "utf16-surrogate",
json: `"\uD834"`,
expectedResult: `�`,
err: false,
},
{
name: "utf16-surrogate-err",
json: `"\uD834\`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate-err2",
json: `"\uD834\uDZ1E`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate-err3",
json: `"\uD834`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\t"`,
expectedResult: "�\t",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\n"`,
expectedResult: "�\n",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\f"`,
expectedResult: "�\f",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\b"`,
expectedResult: "�\b",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\r"`,
expectedResult: "�\r",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\h"`,
expectedResult: "",
err: true,
},
{
name: "null",
json: `null`,
expectedResult: "",
},
{
name: "null-err",
json: `nall`,
expectedResult: "",
err: true,
},
{
name: "escape quote err",
json: `"test string \" escaped"`,
expectedResult: `test string " escaped`,
err: false,
},
{
name: "escape quote err2",
json: `"test string \t escaped"`,
expectedResult: "test string \t escaped",
err: false,
},
{
name: "escape quote err2",
json: `"test string \r escaped"`,
expectedResult: "test string \r escaped",
err: false,
},
{
name: "escape quote err2",
json: `"test string \b escaped"`,
expectedResult: "test string \b escaped",
err: false,
},
{
name: "escape quote err",
json: `"test string \n escaped"`,
expectedResult: "test string \n escaped",
err: false,
},
{
name: "escape quote err",
json: `"test string \\\" escaped`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "escape quote err",
json: `"test string \\\l escaped"`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-json",
json: `invalid`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "string-complex",
json: ` "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char"`,
expectedResult: "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
str := ""
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.Decode(&str)
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should of the given type")
}
} else {
assert.Nil(t, err, "err should be nil")
}
assert.Equal(t, testCase.expectedResult, str, fmt.Sprintf("'%s' should be equal to expectedResult", str))
})
}
}
func TestDecoderStringNull(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult string
err bool
errType interface{}
resultIsNil bool
}{
{
name: "basic-string",
json: `"string"`,
expectedResult: "string",
err: false,
},
{
name: "string-solidus",
json: `"\/"`,
expectedResult: "/",
err: false,
},
{
name: "basic-string",
json: ``,
expectedResult: "",
err: false,
resultIsNil: true,
},
{
name: "basic-string",
json: `""`,
expectedResult: "",
err: false,
},
{
name: "basic-string2",
json: `"hello world!"`,
expectedResult: "hello world!",
err: false,
},
{
name: "escape-control-char",
json: `"\n"`,
expectedResult: "\n",
err: false,
},
{
name: "escape-control-char",
json: `"\\n"`,
expectedResult: `\n`,
err: false,
},
{
name: "escape-control-char",
json: `"\t"`,
expectedResult: "\t",
err: false,
},
{
name: "escape-control-char",
json: `"\\t"`,
expectedResult: `\t`,
err: false,
},
{
name: "escape-control-char",
json: `"\b"`,
expectedResult: "\b",
err: false,
},
{
name: "escape-control-char",
json: `"\\b"`,
expectedResult: `\b`,
err: false,
},
{
name: "escape-control-char",
json: `"\f"`,
expectedResult: "\f",
err: false,
},
{
name: "escape-control-char",
json: `"\\f"`,
expectedResult: `\f`,
err: false,
},
{
name: "escape-control-char",
json: `"\r"`,
expectedResult: "\r",
err: false,
},
{
name: "escape-control-char",
json: `"\`,
expectedResult: "",
err: true,
},
{
name: "escape-control-char-solidus",
json: `"\/"`,
expectedResult: "/",
err: false,
},
{
name: "escape-control-char-solidus",
json: `"/"`,
expectedResult: "/",
err: false,
},
{
name: "escape-control-char-solidus-escape-char",
json: `"\\/"`,
expectedResult: `\/`,
err: false,
},
{
name: "escape-control-char",
json: `"\\r"`,
expectedResult: `\r`,
err: false,
},
{
name: "utf8",
json: `"𠜎 𠜱 ð ¹ ð ±“ 𠱸 ð ²– ð ³ ð ³• ð ´• ð µ¼ 𠵿"`,
expectedResult: "𠜎 𠜱 ð ¹ ð ±“ 𠱸 ð ²– ð ³ ð ³• ð ´• ð µ¼ 𠵿",
err: false,
},
{
name: "utf8-code-point",
json: `"\u06fc"`,
expectedResult: `Û¼`,
err: false,
},
{
name: "utf8-code-point-escaped",
json: `"\\u2070"`,
expectedResult: `\u2070`,
err: false,
},
{
name: "utf8-code-point-err",
json: `"\u2Z70"`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate",
json: `"\uD834\uDD1E"`,
expectedResult: `ð„ž`,
err: false,
},
{
name: "utf16-surrogate",
json: `"\uD834\\"`,
expectedResult: `�\`,
err: false,
},
{
name: "utf16-surrogate",
json: `"\uD834\uD834"`,
expectedResult: "�\x00\x00\x00",
err: false,
},
{
name: "utf16-surrogate",
json: `"\uD834"`,
expectedResult: `�`,
err: false,
},
{
name: "utf16-surrogate-err",
json: `"\uD834\`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate-err2",
json: `"\uD834\uDZ1E`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate-err3",
json: `"\uD834`,
expectedResult: ``,
err: true,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\t"`,
expectedResult: "�\t",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\n"`,
expectedResult: "�\n",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\f"`,
expectedResult: "�\f",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\b"`,
expectedResult: "�\b",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\r"`,
expectedResult: "�\r",
err: false,
},
{
name: "utf16-surrogate-followed-by-control-char",
json: `"\uD834\h"`,
expectedResult: "",
err: true,
},
{
name: "null",
json: `null`,
expectedResult: "",
resultIsNil: true,
},
{
name: "null-err",
json: `nall`,
expectedResult: "",
err: true,
},
{
name: "escape quote err",
json: `"test string \" escaped"`,
expectedResult: `test string " escaped`,
err: false,
},
{
name: "escape quote err2",
json: `"test string \t escaped"`,
expectedResult: "test string \t escaped",
err: false,
},
{
name: "escape quote err2",
json: `"test string \r escaped"`,
expectedResult: "test string \r escaped",
err: false,
},
{
name: "escape quote err2",
json: `"test string \b escaped"`,
expectedResult: "test string \b escaped",
err: false,
},
{
name: "escape quote err",
json: `"test string \n escaped"`,
expectedResult: "test string \n escaped",
err: false,
},
{
name: "escape quote err",
json: `"test string \\\" escaped`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "escape quote err",
json: `"test string \\\l escaped"`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "invalid-json",
json: `invalid`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "string-complex",
json: ` "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char"`,
expectedResult: "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
str := (*string)(nil)
err := Unmarshal([]byte(testCase.json), &str)
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should of the given type")
}
return
}
assert.Nil(t, err, "Err must be nil")
if testCase.resultIsNil {
assert.Nil(t, str)
} else {
assert.Equal(t, testCase.expectedResult, *str, fmt.Sprintf("v must be equal to %s", testCase.expectedResult))
}
})
}
t.Run("decoder-api-invalid-json2", func(t *testing.T) {
var v = new(string)
var dec = NewDecoder(strings.NewReader(`a`))
err := dec.StringNull(&v)
assert.NotNil(t, err, "Err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
func TestDecoderStringInvalidType(t *testing.T) {
json := []byte(`1`)
var v string
err := Unmarshal(json, &v)
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidUnmarshalError(""), err, "err message must be 'Invalid JSON'")
}
func TestDecoderStringDecoderAPI(t *testing.T) {
var v string
dec := NewDecoder(strings.NewReader(`"hello world!"`))
defer dec.Release()
err := dec.DecodeString(&v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, "hello world!", v, "v must be equal to 'hello world!'")
}
func TestDecoderStringPoolError(t *testing.T) {
// reset the pool to make sure it's not full
decPool = sync.Pool{
New: func() interface{} {
return NewDecoder(nil)
},
}
result := ""
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeString(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
}
func TestDecoderSkipEscapedStringError(t *testing.T) {
dec := NewDecoder(strings.NewReader(``))
defer dec.Release()
err := dec.skipEscapedString()
assert.NotNil(t, err, "Err must be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestDecoderSkipEscapedStringError2(t *testing.T) {
dec := NewDecoder(strings.NewReader(`\"`))
defer dec.Release()
err := dec.skipEscapedString()
assert.NotNil(t, err, "Err must be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestDecoderSkipEscapedStringError3(t *testing.T) {
dec := NewDecoder(strings.NewReader(`invalid`))
defer dec.Release()
err := dec.skipEscapedString()
assert.NotNil(t, err, "Err must be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestDecoderSkipEscapedStringError4(t *testing.T) {
dec := NewDecoder(strings.NewReader(`\u12`))
defer dec.Release()
err := dec.skipEscapedString()
assert.NotNil(t, err, "Err must be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestDecoderSkipStringError(t *testing.T) {
dec := NewDecoder(strings.NewReader(`invalid`))
defer dec.Release()
err := dec.skipString()
assert.NotNil(t, err, "Err must be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestSkipString(t *testing.T) {
testCases := []struct {
name string
json string
expectedResult string
err bool
errType interface{}
}{
{
name: "escape quote err",
json: `test string \\" escaped"`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "escape quote err",
json: `test string \\\l escaped"`,
expectedResult: ``,
err: true,
errType: InvalidJSONError(""),
},
{
name: "string-solidus",
json: `Asia\/Bangkok","enable":true}"`,
expectedResult: "",
err: false,
},
{
name: "string-unicode",
json: `[2]\u66fe\u5b97\u5357"`,
expectedResult: "",
err: false,
},
}
for _, testCase := range testCases {
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.skipString()
if testCase.err {
assert.NotNil(t, err, "err should not be nil")
if testCase.errType != nil {
assert.IsType(t, testCase.errType, err, "err should be of expected type")
}
return
}
assert.Nil(t, err, "err should be nil")
}
}
golang-github-francoispqt-gojay-1.2.13/decode_string_unicode.go 0000664 0000000 0000000 00000004062 13653316651 0024644 0 ustar 00root root 0000000 0000000 package gojay
import (
"unicode/utf16"
"unicode/utf8"
)
func (dec *Decoder) getUnicode() (rune, error) {
i := 0
r := rune(0)
for ; (dec.cursor < dec.length || dec.read()) && i < 4; dec.cursor++ {
c := dec.data[dec.cursor]
if c >= '0' && c <= '9' {
r = r*16 + rune(c-'0')
} else if c >= 'a' && c <= 'f' {
r = r*16 + rune(c-'a'+10)
} else if c >= 'A' && c <= 'F' {
r = r*16 + rune(c-'A'+10)
} else {
return 0, InvalidJSONError("Invalid unicode code point")
}
i++
}
return r, nil
}
func (dec *Decoder) appendEscapeChar(str []byte, c byte) ([]byte, error) {
switch c {
case 't':
str = append(str, '\t')
case 'n':
str = append(str, '\n')
case 'r':
str = append(str, '\r')
case 'b':
str = append(str, '\b')
case 'f':
str = append(str, '\f')
case '\\':
str = append(str, '\\')
default:
return nil, InvalidJSONError("Invalid JSON")
}
return str, nil
}
func (dec *Decoder) parseUnicode() ([]byte, error) {
// get unicode after u
r, err := dec.getUnicode()
if err != nil {
return nil, err
}
// no error start making new string
str := make([]byte, 16, 16)
i := 0
// check if code can be a surrogate utf16
if utf16.IsSurrogate(r) {
if dec.cursor >= dec.length && !dec.read() {
return nil, dec.raiseInvalidJSONErr(dec.cursor)
}
c := dec.data[dec.cursor]
if c != '\\' {
i += utf8.EncodeRune(str, r)
return str[:i], nil
}
dec.cursor++
if dec.cursor >= dec.length && !dec.read() {
return nil, dec.raiseInvalidJSONErr(dec.cursor)
}
c = dec.data[dec.cursor]
if c != 'u' {
i += utf8.EncodeRune(str, r)
str, err = dec.appendEscapeChar(str[:i], c)
if err != nil {
dec.err = err
return nil, err
}
i++
dec.cursor++
return str[:i], nil
}
dec.cursor++
r2, err := dec.getUnicode()
if err != nil {
return nil, err
}
combined := utf16.DecodeRune(r, r2)
if combined == '\uFFFD' {
i += utf8.EncodeRune(str, r)
i += utf8.EncodeRune(str, r2)
} else {
i += utf8.EncodeRune(str, combined)
}
return str[:i], nil
}
i += utf8.EncodeRune(str, r)
return str[:i], nil
}
golang-github-francoispqt-gojay-1.2.13/decode_test.go 0000664 0000000 0000000 00000035222 13653316651 0022611 0 ustar 00root root 0000000 0000000 package gojay
import (
"bytes"
"fmt"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
type testDecodeObj struct {
test string
}
func (t *testDecodeObj) UnmarshalJSONObject(dec *Decoder, key string) error {
switch key {
case "test":
return dec.AddString(&t.test)
}
return nil
}
func (t *testDecodeObj) NKeys() int {
return 1
}
type testDecodeSlice []*testDecodeObj
func (t *testDecodeSlice) UnmarshalJSONArray(dec *Decoder) error {
obj := &testDecodeObj{}
if err := dec.AddObject(obj); err != nil {
return err
}
*t = append(*t, obj)
return nil
}
type allTypeDecodeTestCase struct {
name string
v interface{}
d []byte
expectations func(err error, v interface{}, t *testing.T)
}
func allTypesTestCases() []allTypeDecodeTestCase {
return []allTypeDecodeTestCase{
{
v: new(string),
d: []byte(`"test string"`),
name: "test decode string",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*string)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "test string", *vt, "v must be equal to 1")
},
},
{
v: new(*string),
d: []byte(`"test string"`),
name: "test decode string",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**string)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "test string", **vt, "v must be equal to 1")
},
},
{
v: new(string),
d: []byte(`null`),
name: "test decode string null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*string)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", *vt, "v must be equal to 1")
},
},
{
v: new(*string),
d: []byte(`null`),
name: "test decode string null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**string)
assert.Nil(t, err, "err must be nil")
assert.Nil(t, *vt, "v must be nil")
},
},
{
v: new(*string),
d: []byte(`1`),
name: "test decode string null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**string)
assert.NotNil(t, err, "err must be nil")
assert.Nil(t, *vt, "v must be nil")
},
},
{
v: new(int),
d: []byte(`1`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, 1, *vt, "v must be equal to 1")
},
},
{
v: new(*int),
d: []byte(`1`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**int)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, 1, **vt, "v must be equal to 1")
},
},
{
v: new(*int),
d: []byte(`""`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must be nil")
},
},
{
v: new(*int8),
d: []byte(`1`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**int8)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int8(1), **vt, "v must be equal to 1")
},
},
{
v: new(*int8),
d: []byte(`""`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must be nil")
},
},
{
v: new(*int16),
d: []byte(`1`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**int16)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int16(1), **vt, "v must be equal to 1")
},
},
{
v: new(*int16),
d: []byte(`""`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must be nil")
},
},
{
v: new(int64),
d: []byte(`1`),
name: "test decode int64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int64(1), *vt, "v must be equal to 1")
},
},
{
v: new(*int64),
d: []byte(`1`),
name: "test decode int64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**int64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int64(1), **vt, "v must be equal to 1")
},
},
{
v: new(*int64),
d: []byte(`""`),
name: "test decode int64",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must be nil")
},
},
{
v: new(uint64),
d: []byte(`1`),
name: "test decode uint64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint64(1), *vt, "v must be equal to 1")
},
},
{
v: new(*uint64),
d: []byte(`1`),
name: "test decode uint64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**uint64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint64(1), **vt, "v must be equal to 1")
},
},
{
v: new(interface{}),
d: []byte(`[{"test":"test"},{"test":"test2"}]`),
name: "test decode interface",
expectations: func(err error, v interface{}, t *testing.T) {
assert.Nil(t, err, "err must be nil")
// v is a pointer to an interface{}, we need to extract the content
vCont := reflect.ValueOf(v).Elem().Interface()
vt := vCont.([]interface{})
assert.Len(t, vt, 2, "len of vt must be 2")
vt1 := vt[0].(map[string]interface{})
assert.Equal(t, "test", vt1["test"], "vt1['test'] must be equal to 'test'")
vt2 := vt[1].(map[string]interface{})
assert.Equal(t, "test2", vt2["test"], "vt2['test'] must be equal to 'test2'")
},
},
{
v: new(uint64),
d: []byte(`-1`),
name: "test decode uint64 negative",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint64)
assert.NotNil(t, err, "err must not be nil")
assert.Equal(t, uint64(0), *vt, "v must be equal to 1")
},
},
{
v: new(int32),
d: []byte(`1`),
name: "test decode int32",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int32(1), *vt, "v must be equal to 1")
},
},
{
v: new(*int32),
d: []byte(`1`),
name: "test decode int32",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**int32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int32(1), **vt, "v must be equal to 1")
},
},
{
v: new(uint32),
d: []byte(`1`),
name: "test decode uint32",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint32(1), *vt, "v must be equal to 1")
},
},
{
v: new(*uint32),
d: []byte(`1`),
name: "test decode uint32",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**uint32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint32(1), **vt, "v must be equal to 1")
},
},
{
v: new(uint32),
d: []byte(`-1`),
name: "test decode uint32 negative",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint32)
assert.NotNil(t, err, "err must not be nil")
assert.Equal(t, uint32(0), *vt, "v must be equal to 1")
},
},
{
v: new(*uint16),
d: []byte(`1`),
name: "test decode uint16",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**uint16)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint16(1), **vt, "v must be equal to 1")
},
},
{
v: new(*uint8),
d: []byte(`1`),
name: "test decode uint8",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**uint8)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint8(1), **vt, "v must be equal to 1")
},
},
{
v: new(float64),
d: []byte(`1.15`),
name: "test decode float64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*float64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, float64(1.15), *vt, "v must be equal to 1")
},
},
{
v: new(*float64),
d: []byte(`1.15`),
name: "test decode float64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**float64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, float64(1.15), **vt, "v must be equal to 1")
},
},
{
v: new(float64),
d: []byte(`null`),
name: "test decode float64 null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*float64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, float64(0), *vt, "v must be equal to 1")
},
},
{
v: new(*float32),
d: []byte(`1.15`),
name: "test decode float64 null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**float32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, float32(1.15), **vt, "v must be equal to 1")
},
},
{
v: new(bool),
d: []byte(`true`),
name: "test decode bool true",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*bool)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, true, *vt, "v must be equal to 1")
},
},
{
v: new(*bool),
d: []byte(`true`),
name: "test decode bool true",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(**bool)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, true, **vt, "v must be equal to 1")
},
},
{
v: new(bool),
d: []byte(`false`),
name: "test decode bool false",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*bool)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, false, *vt, "v must be equal to 1")
},
},
{
v: new(bool),
d: []byte(`null`),
name: "test decode bool null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*bool)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, false, *vt, "v must be equal to 1")
},
},
{
v: new(testDecodeObj),
d: []byte(`{"test":"test"}`),
name: "test decode object",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "test", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`{"test":null}`),
name: "test decode object null key",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`null`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 1, "len of vt must be 1")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"},{"test":"test2"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 2, "len of vt must be 2")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
assert.Equal(t, "test2", vt[1].test, "vt[1].test must be equal to 'test2'")
},
},
{
v: new(struct{}),
d: []byte(`{"test":"test"}`),
name: "test decode invalid type",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must not be nil")
assert.IsType(t, InvalidUnmarshalError(""), err, "err must be of type InvalidUnmarshalError")
assert.Equal(t, fmt.Sprintf(invalidUnmarshalErrorMsg, v), err.Error(), "err message should be equal to invalidUnmarshalErrorMsg")
},
},
}
}
// Unmarshal tests
func TestUnmarshalAllTypes(t *testing.T) {
for _, testCase := range allTypesTestCases() {
testCase := testCase
t.Run(testCase.name, func(*testing.T) {
err := Unmarshal(testCase.d, testCase.v)
testCase.expectations(err, testCase.v, t)
})
}
}
// Decode tests
func TestDecodeAllTypes(t *testing.T) {
for _, testCase := range allTypesTestCases() {
testCase := testCase
t.Run(testCase.name, func(*testing.T) {
dec := NewDecoder(bytes.NewReader(testCase.d))
err := dec.Decode(testCase.v)
testCase.expectations(err, testCase.v, t)
})
}
}
func TestUnmarshalJSONObjects(t *testing.T) {
testCases := []struct {
name string
v UnmarshalerJSONObject
d []byte
expectations func(err error, v interface{}, t *testing.T)
}{
{
v: new(testDecodeObj),
d: []byte(`{"test":"test"}`),
name: "test decode object",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "test", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`{"test":null}`),
name: "test decode object null key",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`null`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`invalid json`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(*testing.T) {
err := UnmarshalJSONObject(testCase.d, testCase.v)
testCase.expectations(err, testCase.v, t)
})
}
}
golang-github-francoispqt-gojay-1.2.13/decode_time.go 0000664 0000000 0000000 00000002316 13653316651 0022566 0 ustar 00root root 0000000 0000000 package gojay
import (
"time"
)
// DecodeTime decodes time with the given format
func (dec *Decoder) DecodeTime(v *time.Time, format string) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeTime(v, format)
}
func (dec *Decoder) decodeTime(v *time.Time, format string) error {
if format == time.RFC3339 {
var ej = make(EmbeddedJSON, 0, 20)
if err := dec.decodeEmbeddedJSON(&ej); err != nil {
return err
}
if err := v.UnmarshalJSON(ej); err != nil {
return err
}
return nil
}
var str string
if err := dec.decodeString(&str); err != nil {
return err
}
tt, err := time.Parse(format, str)
if err != nil {
return err
}
*v = tt
return nil
}
// Add Values functions
// AddTime decodes the JSON value within an object or an array to a *time.Time with the given format
func (dec *Decoder) AddTime(v *time.Time, format string) error {
return dec.Time(v, format)
}
// Time decodes the JSON value within an object or an array to a *time.Time with the given format
func (dec *Decoder) Time(v *time.Time, format string) error {
err := dec.decodeTime(v, format)
if err != nil {
return err
}
dec.called |= 1
return nil
}
golang-github-francoispqt-gojay-1.2.13/decode_time_test.go 0000664 0000000 0000000 00000006207 13653316651 0023630 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestDecodeTime(t *testing.T) {
testCases := []struct {
name string
json string
format string
err bool
expectedTime string
}{
{
name: "basic",
json: `"2018-02-18"`,
format: `2006-01-02`,
err: false,
expectedTime: "2018-02-18",
},
{
name: "basic",
json: `"2017-01-02T15:04:05Z"`,
format: time.RFC3339,
err: false,
expectedTime: "2017-01-02T15:04:05Z",
},
{
name: "basic",
json: `"2017-01-02T15:04:05ZINVALID"`,
format: time.RFC3339,
err: true,
expectedTime: "",
},
{
name: "basic",
json: `"2017-01-02T15:04:05ZINVALID`,
format: time.RFC1123,
err: true,
expectedTime: "",
},
{
name: "basic",
json: `"2017-01-02T15:04:05ZINVALID"`,
format: time.RFC1123,
err: true,
expectedTime: "",
},
{
name: "basic",
json: `"2017-01-02T15:04:05ZINVALID`,
format: time.RFC3339,
err: true,
expectedTime: "",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
tm := time.Time{}
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.DecodeTime(&tm, testCase.format)
if !testCase.err {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedTime, tm.Format(testCase.format))
return
}
assert.NotNil(t, err)
})
}
}
func TestDecodeAddTime(t *testing.T) {
testCases := []struct {
name string
json string
format string
err bool
expectedTime string
}{
{
name: "basic",
json: `"2018-02-18"`,
format: `2006-01-02`,
err: false,
expectedTime: "2018-02-18",
},
{
name: "basic",
json: ` "2017-01-02T15:04:05Z"`,
format: time.RFC3339,
err: false,
expectedTime: "2017-01-02T15:04:05Z",
},
{
name: "basic",
json: ` "2017-01-02T15:04:05ZINVALID"`,
format: time.RFC3339,
err: true,
expectedTime: "",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
tm := time.Time{}
dec := NewDecoder(strings.NewReader(testCase.json))
err := dec.AddTime(&tm, testCase.format)
if !testCase.err {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedTime, tm.Format(testCase.format))
return
}
assert.NotNil(t, err)
})
}
}
func TestDecoderTimePoolError(t *testing.T) {
// reset the pool to make sure it's not full
decPool = sync.Pool{
New: func() interface{} {
return NewDecoder(nil)
},
}
dec := NewDecoder(nil)
dec.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
}()
_ = dec.DecodeTime(&time.Time{}, time.RFC3339)
assert.True(t, false, "should not be called as decoder should have panicked")
}
golang-github-francoispqt-gojay-1.2.13/decode_unsafe.go 0000664 0000000 0000000 00000005532 13653316651 0023114 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
)
// Unsafe is the structure holding the unsafe version of the API.
// The difference between unsafe api and regular api is that the regular API
// copies the buffer passed to Unmarshal functions to a new internal buffer.
// Making it safer because internally GoJay uses unsafe.Pointer to transform slice of bytes into a string.
var Unsafe = decUnsafe{}
type decUnsafe struct{}
func (u decUnsafe) UnmarshalJSONArray(data []byte, v UnmarshalerJSONArray) error {
dec := borrowDecoder(nil, 0)
defer dec.Release()
dec.data = data
dec.length = len(data)
_, err := dec.decodeArray(v)
return err
}
func (u decUnsafe) UnmarshalJSONObject(data []byte, v UnmarshalerJSONObject) error {
dec := borrowDecoder(nil, 0)
defer dec.Release()
dec.data = data
dec.length = len(data)
_, err := dec.decodeObject(v)
return err
}
func (u decUnsafe) Unmarshal(data []byte, v interface{}) error {
var err error
var dec *Decoder
switch vt := v.(type) {
case *string:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeString(vt)
case *int:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt(vt)
case *int8:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt8(vt)
case *int16:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt16(vt)
case *int32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt32(vt)
case *int64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt64(vt)
case *uint8:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint8(vt)
case *uint16:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint16(vt)
case *uint32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint32(vt)
case *uint64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint64(vt)
case *float64:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeFloat64(vt)
case *float32:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeFloat32(vt)
case *bool:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeBool(vt)
case UnmarshalerJSONObject:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
_, err = dec.decodeObject(vt)
case UnmarshalerJSONArray:
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
_, err = dec.decodeArray(vt)
default:
return InvalidUnmarshalError(fmt.Sprintf(invalidUnmarshalErrorMsg, vt))
}
defer dec.Release()
if err != nil {
return err
}
return dec.err
}
golang-github-francoispqt-gojay-1.2.13/decode_unsafe_test.go 0000664 0000000 0000000 00000027375 13653316651 0024164 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestUnmarshalUnsafeAllTypes(t *testing.T) {
testCases := []struct {
name string
v interface{}
d []byte
expectations func(err error, v interface{}, t *testing.T)
}{
{
v: new(string),
d: []byte(`"test string"`),
name: "test decode string",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*string)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "test string", *vt, "v must be equal to 1")
},
},
{
v: new(string),
d: []byte(`null`),
name: "test decode string null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*string)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", *vt, "v must be equal to 1")
},
},
{
v: new(int),
d: []byte(`1`),
name: "test decode int",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, 1, *vt, "v must be equal to 1")
},
},
{
v: new(int8),
d: []byte(`1`),
name: "test decode int8",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int8)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int8(1), *vt, "v must be equal to 1")
},
},
{
v: new(int16),
d: []byte(`1`),
name: "test decode int16",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int16)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int16(1), *vt, "v must be equal to 1")
},
},
{
v: new(int32),
d: []byte(`1`),
name: "test decode int32",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int32(1), *vt, "v must be equal to 1")
},
},
{
v: new(int64),
d: []byte(`1`),
name: "test decode int64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int64(1), *vt, "v must be equal to 1")
},
},
{
v: new(uint64),
d: []byte(`1`),
name: "test decode uint64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint64(1), *vt, "v must be equal to 1")
},
},
{
v: new(uint64),
d: []byte(`-1`),
name: "test decode uint64 negative",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint64)
assert.NotNil(t, err, "err must not be nil")
assert.Equal(t, uint64(0), *vt, "v must be equal to 1")
},
},
{
v: new(int32),
d: []byte(`1`),
name: "test decode int32",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*int32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, int32(1), *vt, "v must be equal to 1")
},
},
{
v: new(uint32),
d: []byte(`1`),
name: "test decode uint32",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint32(1), *vt, "v must be equal to 1")
},
},
{
v: new(uint32),
d: []byte(`-1`),
name: "test decode uint32 negative",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint32)
assert.NotNil(t, err, "err must not be nil")
assert.Equal(t, uint32(0), *vt, "v must be equal to 1")
},
},
{
v: new(uint8),
d: []byte(`1`),
name: "test decode int8",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint8)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint8(1), *vt, "v must be equal to 1")
},
},
{
v: new(uint16),
d: []byte(`1`),
name: "test decode uint16",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*uint16)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, uint16(1), *vt, "v must be equal to 1")
},
},
{
v: new(float64),
d: []byte(`1.15`),
name: "test decode float64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*float64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, float64(1.15), *vt, "v must be equal to 1")
},
},
{
v: new(float64),
d: []byte(`null`),
name: "test decode float64 null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*float64)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, float64(0), *vt, "v must be equal to 1")
},
},
{
v: new(float32),
d: []byte(`1.15`),
name: "test decode float64",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*float32)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, float32(1.15), *vt, "v must be equal to 1")
},
},
{
v: new(bool),
d: []byte(`true`),
name: "test decode bool true",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*bool)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, true, *vt, "v must be equal to 1")
},
},
{
v: new(bool),
d: []byte(`false`),
name: "test decode bool false",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*bool)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, false, *vt, "v must be equal to 1")
},
},
{
v: new(bool),
d: []byte(`null`),
name: "test decode bool null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*bool)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, false, *vt, "v must be equal to 1")
},
},
{
v: new(testDecodeObj),
d: []byte(`{"test":"test"}`),
name: "test decode object",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "test", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`{"test":null}`),
name: "test decode object null key",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`null`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 1, "len of vt must be 1")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"},{"test":"test2"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 2, "len of vt must be 2")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
assert.Equal(t, "test2", vt[1].test, "vt[1].test must be equal to 'test2'")
},
},
{
v: new(struct{}),
d: []byte(`{"test":"test"}`),
name: "test decode invalid type",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must not be nil")
assert.IsType(t, InvalidUnmarshalError(""), err, "err must be of type InvalidUnmarshalError")
assert.Equal(t, fmt.Sprintf(invalidUnmarshalErrorMsg, v), err.Error(), "err message should be equal to invalidUnmarshalErrorMsg")
},
},
{
v: new(int),
d: []byte(`1a2`),
name: "test decode invalid json",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(*testing.T) {
err := Unsafe.Unmarshal(testCase.d, testCase.v)
testCase.expectations(err, testCase.v, t)
})
}
}
func TestUnmarshalUnsafeObjects(t *testing.T) {
testCases := []struct {
name string
v UnmarshalerJSONObject
d []byte
expectations func(err error, v interface{}, t *testing.T)
}{
{
v: new(testDecodeObj),
d: []byte(`{"test":"test"}`),
name: "test decode object",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "test", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`{"test":null}`),
name: "test decode object null key",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`null`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
vt := v.(*testDecodeObj)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "", vt.test, "v.test must be equal to 'test'")
},
},
{
v: new(testDecodeObj),
d: []byte(`invalid json`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(*testing.T) {
err := Unsafe.UnmarshalJSONObject(testCase.d, testCase.v)
testCase.expectations(err, testCase.v, t)
})
}
}
func TestUnmarshalUnsafeArrays(t *testing.T) {
testCases := []struct {
name string
v UnmarshalerJSONArray
d []byte
expectations func(err error, v interface{}, t *testing.T)
}{
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 1, "len of vt must be 1")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`[{"test":"test"},{"test":"test2"}]`),
name: "test decode slice",
expectations: func(err error, v interface{}, t *testing.T) {
vtPtr := v.(*testDecodeSlice)
vt := *vtPtr
assert.Nil(t, err, "err must be nil")
assert.Len(t, vt, 2, "len of vt must be 2")
assert.Equal(t, "test", vt[0].test, "vt[0].test must be equal to 'test'")
assert.Equal(t, "test2", vt[1].test, "vt[1].test must be equal to 'test2'")
},
},
{
v: new(testDecodeSlice),
d: []byte(`invalid json`),
name: "test decode object null",
expectations: func(err error, v interface{}, t *testing.T) {
assert.NotNil(t, err, "err must not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(*testing.T) {
err := Unsafe.UnmarshalJSONArray(testCase.d, testCase.v)
testCase.expectations(err, testCase.v, t)
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode.go 0000664 0000000 0000000 00000011073 13653316651 0021562 0 ustar 00root root 0000000 0000000 package gojay
import (
"encoding/json"
"fmt"
"io"
)
var nullBytes = []byte("null")
// MarshalJSONArray returns the JSON encoding of v, an implementation of MarshalerJSONArray.
//
//
// Example:
// type TestSlice []*TestStruct
//
// func (t TestSlice) MarshalJSONArray(enc *Encoder) {
// for _, e := range t {
// enc.AddObject(e)
// }
// }
//
// func main() {
// test := &TestSlice{
// &TestStruct{123456},
// &TestStruct{7890},
// }
// b, _ := Marshal(test)
// fmt.Println(b) // [{"id":123456},{"id":7890}]
// }
func MarshalJSONArray(v MarshalerJSONArray) ([]byte, error) {
enc := BorrowEncoder(nil)
enc.grow(512)
enc.writeByte('[')
v.(MarshalerJSONArray).MarshalJSONArray(enc)
enc.writeByte(']')
defer func() {
enc.buf = make([]byte, 0, 512)
enc.Release()
}()
return enc.buf, nil
}
// MarshalJSONObject returns the JSON encoding of v, an implementation of MarshalerJSONObject.
//
// Example:
// type Object struct {
// id int
// }
// func (s *Object) MarshalJSONObject(enc *gojay.Encoder) {
// enc.IntKey("id", s.id)
// }
// func (s *Object) IsNil() bool {
// return s == nil
// }
//
// func main() {
// test := &Object{
// id: 123456,
// }
// b, _ := gojay.Marshal(test)
// fmt.Println(b) // {"id":123456}
// }
func MarshalJSONObject(v MarshalerJSONObject) ([]byte, error) {
enc := BorrowEncoder(nil)
enc.grow(512)
defer func() {
enc.buf = make([]byte, 0, 512)
enc.Release()
}()
return enc.encodeObject(v)
}
// Marshal returns the JSON encoding of v.
//
// If v is nil, not an implementation MarshalerJSONObject or MarshalerJSONArray or not one of the following types:
// string, int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float64, float32, bool
// Marshal returns an InvalidMarshalError.
func Marshal(v interface{}) ([]byte, error) {
return marshal(v, false)
}
// MarshalAny returns the JSON encoding of v.
//
// If v is nil, not an implementation MarshalerJSONObject or MarshalerJSONArray or not one of the following types:
// string, int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float64, float32, bool
// MarshalAny falls back to "json/encoding" package to marshal the value.
func MarshalAny(v interface{}) ([]byte, error) {
return marshal(v, true)
}
func marshal(v interface{}, any bool) ([]byte, error) {
var (
enc = BorrowEncoder(nil)
buf []byte
err error
)
defer func() {
enc.buf = make([]byte, 0, 512)
enc.Release()
}()
buf, err = func() ([]byte, error) {
switch vt := v.(type) {
case MarshalerJSONObject:
return enc.encodeObject(vt)
case MarshalerJSONArray:
return enc.encodeArray(vt)
case string:
return enc.encodeString(vt)
case bool:
return enc.encodeBool(vt)
case int:
return enc.encodeInt(vt)
case int64:
return enc.encodeInt64(vt)
case int32:
return enc.encodeInt(int(vt))
case int16:
return enc.encodeInt(int(vt))
case int8:
return enc.encodeInt(int(vt))
case uint64:
return enc.encodeInt(int(vt))
case uint32:
return enc.encodeInt(int(vt))
case uint16:
return enc.encodeInt(int(vt))
case uint8:
return enc.encodeInt(int(vt))
case float64:
return enc.encodeFloat(vt)
case float32:
return enc.encodeFloat32(vt)
case *EmbeddedJSON:
return enc.encodeEmbeddedJSON(vt)
default:
if any {
return json.Marshal(vt)
}
return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt))
}
}()
return buf, err
}
// MarshalerJSONObject is the interface to implement for struct to be encoded
type MarshalerJSONObject interface {
MarshalJSONObject(enc *Encoder)
IsNil() bool
}
// MarshalerJSONArray is the interface to implement
// for a slice or an array to be encoded
type MarshalerJSONArray interface {
MarshalJSONArray(enc *Encoder)
IsNil() bool
}
// An Encoder writes JSON values to an output stream.
type Encoder struct {
buf []byte
isPooled byte
w io.Writer
err error
hasKeys bool
keys []string
}
// AppendBytes allows a modular usage by appending bytes manually to the current state of the buffer.
func (enc *Encoder) AppendBytes(b []byte) {
enc.writeBytes(b)
}
// AppendByte allows a modular usage by appending a single byte manually to the current state of the buffer.
func (enc *Encoder) AppendByte(b byte) {
enc.writeByte(b)
}
// Buf returns the Encoder's buffer.
func (enc *Encoder) Buf() []byte {
return enc.buf
}
// Write writes to the io.Writer and resets the buffer.
func (enc *Encoder) Write() (int, error) {
i, err := enc.w.Write(enc.buf)
enc.buf = enc.buf[:0]
return i, err
}
func (enc *Encoder) getPreviousRune() byte {
last := len(enc.buf) - 1
return enc.buf[last]
}
golang-github-francoispqt-gojay-1.2.13/encode_array.go 0000664 0000000 0000000 00000013233 13653316651 0022760 0 ustar 00root root 0000000 0000000 package gojay
// EncodeArray encodes an implementation of MarshalerJSONArray to JSON
func (enc *Encoder) EncodeArray(v MarshalerJSONArray) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeArray(v)
_, err := enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
func (enc *Encoder) encodeArray(v MarshalerJSONArray) ([]byte, error) {
enc.grow(200)
enc.writeByte('[')
v.MarshalJSONArray(enc)
enc.writeByte(']')
return enc.buf, enc.err
}
// AddArray adds an implementation of MarshalerJSONArray to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement Marshaler
func (enc *Encoder) AddArray(v MarshalerJSONArray) {
enc.Array(v)
}
// AddArrayOmitEmpty adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerAddArrayOmitEmpty
func (enc *Encoder) AddArrayOmitEmpty(v MarshalerJSONArray) {
enc.ArrayOmitEmpty(v)
}
// AddArrayNullEmpty adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement Marshaler, if v is empty, `null` will be encoded`
func (enc *Encoder) AddArrayNullEmpty(v MarshalerJSONArray) {
enc.ArrayNullEmpty(v)
}
// AddArrayKey adds an array or slice to be encoded, must be used inside an object as it will encode a key
// value must implement Marshaler
func (enc *Encoder) AddArrayKey(key string, v MarshalerJSONArray) {
enc.ArrayKey(key, v)
}
// AddArrayKeyOmitEmpty adds an array or slice to be encoded and skips it if it is nil.
// Must be called inside an object as it will encode a key.
func (enc *Encoder) AddArrayKeyOmitEmpty(key string, v MarshalerJSONArray) {
enc.ArrayKeyOmitEmpty(key, v)
}
// AddArrayKeyNullEmpty adds an array or slice to be encoded and skips it if it is nil.
// Must be called inside an object as it will encode a key. `null` will be encoded`
func (enc *Encoder) AddArrayKeyNullEmpty(key string, v MarshalerJSONArray) {
enc.ArrayKeyNullEmpty(key, v)
}
// Array adds an implementation of MarshalerJSONArray to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement Marshaler
func (enc *Encoder) Array(v MarshalerJSONArray) {
if v.IsNil() {
enc.grow(3)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeByte('[')
enc.writeByte(']')
return
}
enc.grow(100)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeByte('[')
v.MarshalJSONArray(enc)
enc.writeByte(']')
}
// ArrayOmitEmpty adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement Marshaler
func (enc *Encoder) ArrayOmitEmpty(v MarshalerJSONArray) {
if v.IsNil() {
return
}
enc.grow(4)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeByte('[')
v.MarshalJSONArray(enc)
enc.writeByte(']')
}
// ArrayNullEmpty adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement Marshaler
func (enc *Encoder) ArrayNullEmpty(v MarshalerJSONArray) {
enc.grow(4)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v.IsNil() {
enc.writeBytes(nullBytes)
return
}
enc.writeByte('[')
v.MarshalJSONArray(enc)
enc.writeByte(']')
}
// ArrayKey adds an array or slice to be encoded, must be used inside an object as it will encode a key
// value must implement Marshaler
func (enc *Encoder) ArrayKey(key string, v MarshalerJSONArray) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v.IsNil() {
enc.grow(2 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyArr)
enc.writeByte(']')
return
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyArr)
v.MarshalJSONArray(enc)
enc.writeByte(']')
}
// ArrayKeyOmitEmpty adds an array or slice to be encoded and skips if it is nil.
// Must be called inside an object as it will encode a key.
func (enc *Encoder) ArrayKeyOmitEmpty(key string, v MarshalerJSONArray) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v.IsNil() {
return
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyArr)
v.MarshalJSONArray(enc)
enc.writeByte(']')
}
// ArrayKeyNullEmpty adds an array or slice to be encoded and encodes `null`` if it is nil.
// Must be called inside an object as it will encode a key.
func (enc *Encoder) ArrayKeyNullEmpty(key string, v MarshalerJSONArray) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
if v.IsNil() {
enc.writeBytes(nullBytes)
return
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyArr)
v.MarshalJSONArray(enc)
enc.writeByte(']')
}
// EncodeArrayFunc is a custom func type implementing MarshaleArray.
// Use it to cast a func(*Encoder) to Marshal an object.
//
// enc := gojay.NewEncoder(io.Writer)
// enc.EncodeArray(gojay.EncodeArrayFunc(func(enc *gojay.Encoder) {
// enc.AddStringKey("hello", "world")
// }))
type EncodeArrayFunc func(*Encoder)
// MarshalJSONArray implements MarshalerJSONArray.
func (f EncodeArrayFunc) MarshalJSONArray(enc *Encoder) {
f(enc)
}
// IsNil implements MarshalerJSONArray.
func (f EncodeArrayFunc) IsNil() bool {
return f == nil
}
golang-github-francoispqt-gojay-1.2.13/encode_array_test.go 0000664 0000000 0000000 00000024261 13653316651 0024022 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
type TestEncodingArrStrings []string
func (t TestEncodingArrStrings) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddString(e)
}
}
func (t TestEncodingArrStrings) IsNil() bool {
return len(t) == 0
}
type TestEncodingArr []*TestEncoding
func (t TestEncodingArr) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddObject(e)
}
}
func (t TestEncodingArr) IsNil() bool {
return t == nil
}
type testEncodingArrInterfaces []interface{}
func (t testEncodingArrInterfaces) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddInterface(e)
}
}
func (t testEncodingArrInterfaces) IsNil() bool {
return t == nil
}
func TestEncoderArrayMarshalAPI(t *testing.T) {
t.Run("array-objects", func(t *testing.T) {
v := &TestEncodingArr{
&TestEncoding{
test: "hello world",
test2: "æ¼¢å—",
testInt: 1,
testBool: true,
testInterface: 1,
sub: &SubObject{
test1: 10,
test2: "hello world",
test3: 1.23543,
testBool: true,
sub: &SubObject{
test1: 10,
testBool: false,
test2: "hello world",
},
},
},
&TestEncoding{
test: "hello world",
test2: "æ¼¢å—",
testInt: 1,
testBool: true,
sub: &SubObject{
test1: 10,
test2: "hello world",
test3: 1.23543,
testBool: true,
sub: &SubObject{
test1: 10,
testBool: false,
test2: "hello world",
},
},
},
nil,
}
r, err := Marshal(v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`[{"test":"hello world","test2":"æ¼¢å—","testInt":1,"testBool":true,`+
`"testArr":[],"testF64":0,"testF32":0,"testInterface":1,"sub":{"test1":10,"test2":"hello world",`+
`"test3":1.23543,"testBool":true,"sub":{"test1":10,"test2":"hello world",`+
`"test3":0,"testBool":false,"sub":{}}}},{"test":"hello world","test2":"æ¼¢å—","testInt":1,`+
`"testBool":true,"testArr":[],"testF64":0,"testF32":0,"sub":{"test1":10,"test2":"hello world","test3":1.23543,`+
`"testBool":true,"sub":{"test1":10,"test2":"hello world","test3":0,"testBool":false,"sub":{}}}},{}]`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("array-interfaces", func(t *testing.T) {
v := &testEncodingArrInterfaces{
1,
int64(1),
int32(1),
int16(1),
int8(1),
uint64(1),
uint32(1),
uint16(1),
uint8(1),
float64(1.31),
float32(1.31),
&TestEncodingArr{},
&TestEncodingArrStrings{},
true,
false,
"test",
&TestEncoding{
test: "hello world",
test2: "foobar",
testInt: 1,
testBool: true,
},
}
r, err := MarshalJSONArray(v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`[1,1,1,1,1,1,1,1,1.31,1.31,[],[],true,false,"test",{"test":"hello world","test2":"foobar","testInt":1,"testBool":true,"testArr":[],"testF64":0,"testF32":0,"sub":{}}]`,
string(r),
"Result of marshalling is different as the one expected")
})
}
func TestEncoderArrayEncodeAPI(t *testing.T) {
t.Run("array-interfaces", func(t *testing.T) {
v := &testEncodingArrInterfaces{
1,
int64(1),
int32(1),
int16(1),
int8(1),
uint64(1),
uint32(1),
uint16(1),
uint8(1),
float64(1.31),
// float32(1.31),
&TestEncodingArr{},
true,
"test",
&TestEncoding{
test: "hello world",
test2: "foobar",
testInt: 1,
testBool: true,
},
}
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
defer enc.Release()
err := enc.EncodeArray(v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`[1,1,1,1,1,1,1,1,1.31,[],true,"test",{"test":"hello world","test2":"foobar","testInt":1,"testBool":true,"testArr":[],"testF64":0,"testF32":0,"sub":{}}]`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("array-interfaces-write-error", func(t *testing.T) {
v := &testEncodingArrInterfaces{}
w := TestWriterError("")
enc := BorrowEncoder(w)
defer enc.Release()
err := enc.EncodeArray(v)
assert.NotNil(t, err, "err should not be nil")
})
}
// Array add with omit key tests
type TestEncodingIntOmitEmpty []int
func (t TestEncodingIntOmitEmpty) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddIntOmitEmpty(e)
}
}
func (t TestEncodingIntOmitEmpty) IsNil() bool {
return t == nil
}
type TestEncodingStringOmitEmpty []string
func (t TestEncodingStringOmitEmpty) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddStringOmitEmpty(e)
}
}
func (t TestEncodingStringOmitEmpty) IsNil() bool {
return t == nil
}
type TestEncodingFloatOmitEmpty []float64
func (t TestEncodingFloatOmitEmpty) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddFloatOmitEmpty(e)
}
}
func (t TestEncodingFloatOmitEmpty) IsNil() bool {
return t == nil
}
type TestEncodingFloat32OmitEmpty []float32
func (t TestEncodingFloat32OmitEmpty) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddFloat32OmitEmpty(e)
}
}
func (t TestEncodingFloat32OmitEmpty) IsNil() bool {
return t == nil
}
type TestEncodingBoolOmitEmpty []bool
func (t TestEncodingBoolOmitEmpty) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddBoolOmitEmpty(e)
}
}
func (t TestEncodingBoolOmitEmpty) IsNil() bool {
return len(t) == 0
}
type TestEncodingArrOmitEmpty []TestEncodingBoolOmitEmpty
func (t TestEncodingArrOmitEmpty) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddArrayOmitEmpty(e)
}
}
func (t TestEncodingArrOmitEmpty) IsNil() bool {
return len(t) == 0
}
type TestObjEmpty struct {
empty bool
}
func (t *TestObjEmpty) MarshalJSONObject(enc *Encoder) {
}
func (t *TestObjEmpty) IsNil() bool {
return !t.empty
}
type TestEncodingObjOmitEmpty []*TestObjEmpty
func (t TestEncodingObjOmitEmpty) MarshalJSONArray(enc *Encoder) {
for _, e := range t {
enc.AddObjectOmitEmpty(e)
}
}
func (t TestEncodingObjOmitEmpty) IsNil() bool {
return t == nil
}
func TestEncoderArrayOmitEmpty(t *testing.T) {
t.Run("omit-int", func(t *testing.T) {
intArr := TestEncodingIntOmitEmpty{0, 1, 0, 1}
b, err := Marshal(intArr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, `[1,1]`, string(b), "string(b) must be equal to `[1,1]`")
})
t.Run("omit-float", func(t *testing.T) {
floatArr := TestEncodingFloatOmitEmpty{0, 1, 0, 1}
b, err := Marshal(floatArr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, `[1,1]`, string(b), "string(b) must be equal to `[1,1]`")
})
t.Run("omit-float32", func(t *testing.T) {
float32Arr := TestEncodingFloat32OmitEmpty{0, 1, 0, 1}
b, err := Marshal(float32Arr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, `[1,1]`, string(b), "string(b) must be equal to `[1,1]`")
})
t.Run("omit-string", func(t *testing.T) {
stringArr := TestEncodingStringOmitEmpty{"", "hello", "", "world"}
b, err := Marshal(stringArr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, `["hello","world"]`, string(b), "string(b) must be equal to `[\"hello\",\"world\"]`")
})
t.Run("omit-bool", func(t *testing.T) {
boolArr := TestEncodingBoolOmitEmpty{false, true, false, true}
b, err := Marshal(boolArr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, `[true,true]`, string(b), "string(b) must be equal to `[true,true]`")
})
t.Run("omit-arr", func(t *testing.T) {
arrArr := TestEncodingArrOmitEmpty{TestEncodingBoolOmitEmpty{true}, nil, TestEncodingBoolOmitEmpty{true}, nil}
b, err := Marshal(arrArr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, `[[true],[true]]`, string(b), "string(b) must be equal to `[[true],[true]]`")
})
t.Run("omit-obj", func(t *testing.T) {
objArr := TestEncodingObjOmitEmpty{&TestObjEmpty{true}, &TestObjEmpty{false}, &TestObjEmpty{true}, &TestObjEmpty{false}}
b, err := Marshal(objArr)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, `[{},{}]`, string(b), "string(b) must be equal to `[{},{}]`")
})
}
func TestEncoderArrErrors(t *testing.T) {
t.Run("add-interface-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.AddInterface(nil)
assert.Nil(t, enc.err, "enc.Err() should not be nil")
assert.Equal(t, "", builder.String(), "builder.String() should not be ''")
})
t.Run("array-pooled-error", func(t *testing.T) {
v := &testEncodingArrInterfaces{}
enc := BorrowEncoder(nil)
enc.Release()
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
_ = enc.EncodeArray(v)
assert.True(t, false, "should not be called as it should have panicked")
})
}
func TestEncoderArrayFunc(t *testing.T) {
var f EncodeArrayFunc
assert.True(t, f.IsNil())
}
func TestEncodeArrayNullEmpty(t *testing.T) {
var testCases = []struct {
name, baseJSON, expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,["foo"]`,
},
{
name: "basic 1st elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,["foo"]`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddArrayNullEmpty(&TestEncodingArrStrings{})
enc.ArrayNullEmpty(&TestEncodingArrStrings{"foo"})
})
}
}
func TestEncodeArrayKeyNullEmpty(t *testing.T) {
var testCases = []struct {
name, baseJSON, expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":["foo"]`,
},
{
name: "basic 1st elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":["foo"]`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddArrayKeyNullEmpty("foo", &TestEncodingArrStrings{})
enc.ArrayKeyNullEmpty("bar", &TestEncodingArrStrings{"foo"})
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_bool.go 0000664 0000000 0000000 00000007764 13653316651 0022611 0 ustar 00root root 0000000 0000000 package gojay
import "strconv"
// EncodeBool encodes a bool to JSON
func (enc *Encoder) EncodeBool(v bool) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeBool(v)
_, err := enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
// encodeBool encodes a bool to JSON
func (enc *Encoder) encodeBool(v bool) ([]byte, error) {
enc.grow(5)
if v {
enc.writeString("true")
} else {
enc.writeString("false")
}
return enc.buf, enc.err
}
// AddBool adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddBool(v bool) {
enc.Bool(v)
}
// AddBoolOmitEmpty adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddBoolOmitEmpty(v bool) {
enc.BoolOmitEmpty(v)
}
// AddBoolNullEmpty adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddBoolNullEmpty(v bool) {
enc.BoolNullEmpty(v)
}
// AddBoolKey adds a bool to be encoded, must be used inside an object as it will encode a key.
func (enc *Encoder) AddBoolKey(key string, v bool) {
enc.BoolKey(key, v)
}
// AddBoolKeyOmitEmpty adds a bool to be encoded and skips if it is zero value.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddBoolKeyOmitEmpty(key string, v bool) {
enc.BoolKeyOmitEmpty(key, v)
}
// AddBoolKeyNullEmpty adds a bool to be encoded and encodes `null` if it is zero value.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddBoolKeyNullEmpty(key string, v bool) {
enc.BoolKeyNullEmpty(key, v)
}
// Bool adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Bool(v bool) {
enc.grow(5)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v {
enc.writeString("true")
} else {
enc.writeString("false")
}
}
// BoolOmitEmpty adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) BoolOmitEmpty(v bool) {
if v == false {
return
}
enc.grow(5)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeString("true")
}
// BoolNullEmpty adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) BoolNullEmpty(v bool) {
enc.grow(5)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v == false {
enc.writeBytes(nullBytes)
return
}
enc.writeString("true")
}
// BoolKey adds a bool to be encoded, must be used inside an object as it will encode a key.
func (enc *Encoder) BoolKey(key string, value bool) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendBool(enc.buf, value)
}
// BoolKeyOmitEmpty adds a bool to be encoded and skips it if it is zero value.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) BoolKeyOmitEmpty(key string, v bool) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v == false {
return
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendBool(enc.buf, v)
}
// BoolKeyNullEmpty adds a bool to be encoded and skips it if it is zero value.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) BoolKeyNullEmpty(key string, v bool) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v == false {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendBool(enc.buf, v)
}
golang-github-francoispqt-gojay-1.2.13/encode_bool_test.go 0000664 0000000 0000000 00000006424 13653316651 0023640 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncoderBoolMarshalAPI(t *testing.T) {
t.Run("true", func(t *testing.T) {
b, err := Marshal(true)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "true", string(b), "string(b) must be equal to 'true'")
})
t.Run("false", func(t *testing.T) {
b, err := Marshal(false)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "false", string(b), "string(b) must be equal to 'false'")
})
}
func TestEncoderBoolEncodeAPI(t *testing.T) {
t.Run("true", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
defer enc.Release()
err := enc.EncodeBool(true)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "true", builder.String(), "string(b) must be equal to 'true'")
})
t.Run("false", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
defer enc.Release()
err := enc.EncodeBool(false)
assert.Nil(t, err, "err must be nil")
assert.Equal(t, "false", builder.String(), "string(b) must be equal to 'false'")
})
}
func TestEncoderBoolErrors(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeBool(false)
assert.True(t, false, "should not be called as it should have panicked")
})
t.Run("encode-api-write-error", func(t *testing.T) {
v := true
w := TestWriterError("")
enc := BorrowEncoder(w)
defer enc.Release()
err := enc.EncodeBool(v)
assert.NotNil(t, err, "err should not be nil")
})
}
func TestEncoderBoolNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: "[null,true",
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,true`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.BoolNullEmpty(false)
enc.AddBoolNullEmpty(true)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderBoolNullKeyEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":true`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":true`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.BoolKeyNullEmpty("foo", false)
enc.AddBoolKeyNullEmpty("bar", true)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_builder.go 0000664 0000000 0000000 00000003052 13653316651 0023266 0 ustar 00root root 0000000 0000000 package gojay
const hex = "0123456789abcdef"
// grow grows b's capacity, if necessary, to guarantee space for
// another n bytes. After grow(n), at least n bytes can be written to b
// without another allocation. If n is negative, grow panics.
func (enc *Encoder) grow(n int) {
if cap(enc.buf)-len(enc.buf) < n {
Buf := make([]byte, len(enc.buf), 2*cap(enc.buf)+n)
copy(Buf, enc.buf)
enc.buf = Buf
}
}
// Write appends the contents of p to b's Buffer.
// Write always returns len(p), nil.
func (enc *Encoder) writeBytes(p []byte) {
enc.buf = append(enc.buf, p...)
}
func (enc *Encoder) writeTwoBytes(b1 byte, b2 byte) {
enc.buf = append(enc.buf, b1, b2)
}
// WriteByte appends the byte c to b's Buffer.
// The returned error is always nil.
func (enc *Encoder) writeByte(c byte) {
enc.buf = append(enc.buf, c)
}
// WriteString appends the contents of s to b's Buffer.
// It returns the length of s and a nil error.
func (enc *Encoder) writeString(s string) {
enc.buf = append(enc.buf, s...)
}
func (enc *Encoder) writeStringEscape(s string) {
l := len(s)
for i := 0; i < l; i++ {
c := s[i]
if c >= 0x20 && c != '\\' && c != '"' {
enc.writeByte(c)
continue
}
switch c {
case '\\', '"':
enc.writeTwoBytes('\\', c)
case '\n':
enc.writeTwoBytes('\\', 'n')
case '\f':
enc.writeTwoBytes('\\', 'f')
case '\b':
enc.writeTwoBytes('\\', 'b')
case '\r':
enc.writeTwoBytes('\\', 'r')
case '\t':
enc.writeTwoBytes('\\', 't')
default:
enc.writeString(`\u00`)
enc.writeTwoBytes(hex[c>>4], hex[c&0xF])
}
continue
}
}
golang-github-francoispqt-gojay-1.2.13/encode_builder_test.go 0000664 0000000 0000000 00000000016 13653316651 0024322 0 ustar 00root root 0000000 0000000 package gojay
golang-github-francoispqt-gojay-1.2.13/encode_embedded_json.go 0000664 0000000 0000000 00000004574 13653316651 0024434 0 ustar 00root root 0000000 0000000 package gojay
// EncodeEmbeddedJSON encodes an embedded JSON.
// is basically sets the internal buf as the value pointed by v and calls the io.Writer.Write()
func (enc *Encoder) EncodeEmbeddedJSON(v *EmbeddedJSON) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
enc.buf = *v
_, err := enc.Write()
if err != nil {
return err
}
return nil
}
func (enc *Encoder) encodeEmbeddedJSON(v *EmbeddedJSON) ([]byte, error) {
enc.writeBytes(*v)
return enc.buf, nil
}
// AddEmbeddedJSON adds an EmbeddedJSON to be encoded.
//
// It basically blindly writes the bytes to the final buffer. Therefore,
// it expects the JSON to be of proper format.
func (enc *Encoder) AddEmbeddedJSON(v *EmbeddedJSON) {
enc.grow(len(*v) + 4)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeBytes(*v)
}
// AddEmbeddedJSONOmitEmpty adds an EmbeddedJSON to be encoded or skips it if nil pointer or empty.
//
// It basically blindly writes the bytes to the final buffer. Therefore,
// it expects the JSON to be of proper format.
func (enc *Encoder) AddEmbeddedJSONOmitEmpty(v *EmbeddedJSON) {
if v == nil || len(*v) == 0 {
return
}
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeBytes(*v)
}
// AddEmbeddedJSONKey adds an EmbeddedJSON and a key to be encoded.
//
// It basically blindly writes the bytes to the final buffer. Therefore,
// it expects the JSON to be of proper format.
func (enc *Encoder) AddEmbeddedJSONKey(key string, v *EmbeddedJSON) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(len(key) + len(*v) + 5)
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.writeBytes(*v)
}
// AddEmbeddedJSONKeyOmitEmpty adds an EmbeddedJSON and a key to be encoded or skips it if nil pointer or empty.
//
// It basically blindly writes the bytes to the final buffer. Therefore,
// it expects the JSON to be of proper format.
func (enc *Encoder) AddEmbeddedJSONKeyOmitEmpty(key string, v *EmbeddedJSON) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v == nil || len(*v) == 0 {
return
}
enc.grow(len(key) + len(*v) + 5)
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.writeBytes(*v)
}
golang-github-francoispqt-gojay-1.2.13/encode_embedded_json_test.go 0000664 0000000 0000000 00000007376 13653316651 0025476 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func (r *Request) MarshalJSONObject(enc *Encoder) {
enc.AddStringKey("id", r.id)
enc.AddStringKey("method", r.method)
enc.AddEmbeddedJSONKey("params", &r.params)
params2 := EmbeddedJSON([]byte(``))
enc.AddEmbeddedJSONKeyOmitEmpty("params2", ¶ms2)
params3 := EmbeddedJSON([]byte(`"test"`))
enc.AddEmbeddedJSONKeyOmitEmpty("params3", ¶ms3)
enc.AddIntKey("more", r.more)
}
func (r *Request) IsNil() bool {
return r == nil
}
type EmbeddedJSONArr []EmbeddedJSON
func (ear EmbeddedJSONArr) MarshalJSONArray(enc *Encoder) {
for _, e := range ear {
enc.AddEmbeddedJSON(&e)
}
}
func (ear EmbeddedJSONArr) IsNil() bool {
return len(ear) == 0
}
type EmbeddedJSONOmitEmptyArr []EmbeddedJSON
func (ear EmbeddedJSONOmitEmptyArr) MarshalJSONArray(enc *Encoder) {
for _, e := range ear {
enc.AddEmbeddedJSONOmitEmpty(&e)
}
}
func (ear EmbeddedJSONOmitEmptyArr) IsNil() bool {
return len(ear) == 0
}
func TestEncodingEmbeddedJSON(t *testing.T) {
t.Run("basic-embedded-json", func(t *testing.T) {
ej := EmbeddedJSON([]byte(`"test"`))
b := &strings.Builder{}
enc := BorrowEncoder(b)
err := enc.Encode(&ej)
assert.Nil(t, err, "err should be nil")
assert.Equal(t, b.String(), `"test"`, "b should be equal to content of EmbeddedJSON")
})
t.Run("basic-embedded-json-marshal-api", func(t *testing.T) {
ej := EmbeddedJSON([]byte(`"test"`))
b, err := Marshal(&ej)
assert.Nil(t, err, "err should be nil")
assert.Equal(t, string(b), `"test"`, "b should be equal to content of EmbeddedJSON")
})
t.Run("object-embedded-json", func(t *testing.T) {
req := Request{
id: "test",
method: "GET",
params: EmbeddedJSON([]byte(`"test"`)),
}
b := &strings.Builder{}
enc := BorrowEncoder(b)
err := enc.EncodeObject(&req)
assert.Nil(t, err, "err should be nil")
assert.Equal(
t,
b.String(),
`{"id":"test","method":"GET","params":"test","params3":"test","more":0}`,
"b should be equal to content of EmbeddedJSON",
)
})
t.Run("array-embedded-json", func(t *testing.T) {
ear := EmbeddedJSONArr{
[]byte(`"test"`),
[]byte(`{"test":"test"}`),
}
b := &strings.Builder{}
enc := BorrowEncoder(b)
err := enc.EncodeArray(ear)
assert.Nil(t, err, "err should be nil")
assert.Equal(
t,
b.String(),
`["test",{"test":"test"}]`,
"b should be equal to content of EmbeddedJSON",
)
})
t.Run("array-embedded-json-omit-empty", func(t *testing.T) {
ear := EmbeddedJSONOmitEmptyArr{
[]byte(`"test"`),
[]byte(``),
[]byte(`{"test":"test"}`),
[]byte(``),
[]byte(`{"test":"test"}`),
}
b := &strings.Builder{}
enc := BorrowEncoder(b)
err := enc.EncodeArray(ear)
assert.Nil(t, err, "err should be nil")
assert.Equal(
t,
b.String(),
`["test",{"test":"test"},{"test":"test"}]`,
"b should be equal to content of EmbeddedJSON",
)
})
t.Run("write-error", func(t *testing.T) {
w := TestWriterError("")
v := EmbeddedJSON([]byte(`"test"`))
enc := NewEncoder(w)
err := enc.EncodeEmbeddedJSON(&v)
assert.NotNil(t, err, "Error should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err.Error() should be 'Test Error'")
})
t.Run("pool-error", func(t *testing.T) {
v := EmbeddedJSON([]byte(`"test"`))
enc := BorrowEncoder(nil)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
_ = enc.EncodeEmbeddedJSON(&v)
assert.True(t, false, "should not be called as it should have panicked")
})
}
golang-github-francoispqt-gojay-1.2.13/encode_example_test.go 0000664 0000000 0000000 00000001713 13653316651 0024334 0 ustar 00root root 0000000 0000000 package gojay_test
import (
"fmt"
"log"
"os"
"github.com/francoispqt/gojay"
)
func ExampleMarshal_string() {
str := "gojay"
d, err := gojay.Marshal(str)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(d)) // "gojay"
}
func ExampleMarshal_bool() {
b := true
d, err := gojay.Marshal(b)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(d)) // true
}
func ExampleNewEncoder() {
enc := gojay.BorrowEncoder(os.Stdout)
var str = "gojay"
err := enc.EncodeString(str)
if err != nil {
log.Fatal(err)
}
// Output:
// "gojay"
}
func ExampleBorrowEncoder() {
enc := gojay.BorrowEncoder(os.Stdout)
defer enc.Release()
var str = "gojay"
err := enc.EncodeString(str)
if err != nil {
log.Fatal(err)
}
// Output:
// "gojay"
}
func ExampleEncoder_EncodeString() {
enc := gojay.BorrowEncoder(os.Stdout)
defer enc.Release()
var str = "gojay"
err := enc.EncodeString(str)
if err != nil {
log.Fatal(err)
}
// Output:
// "gojay"
}
golang-github-francoispqt-gojay-1.2.13/encode_interface.go 0000664 0000000 0000000 00000007771 13653316651 0023614 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
)
// Encode encodes a value to JSON.
//
// If Encode cannot find a way to encode the type to JSON
// it will return an InvalidMarshalError.
func (enc *Encoder) Encode(v interface{}) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
switch vt := v.(type) {
case string:
return enc.EncodeString(vt)
case bool:
return enc.EncodeBool(vt)
case MarshalerJSONArray:
return enc.EncodeArray(vt)
case MarshalerJSONObject:
return enc.EncodeObject(vt)
case int:
return enc.EncodeInt(vt)
case int64:
return enc.EncodeInt64(vt)
case int32:
return enc.EncodeInt(int(vt))
case int8:
return enc.EncodeInt(int(vt))
case uint64:
return enc.EncodeUint64(vt)
case uint32:
return enc.EncodeInt(int(vt))
case uint16:
return enc.EncodeInt(int(vt))
case uint8:
return enc.EncodeInt(int(vt))
case float64:
return enc.EncodeFloat(vt)
case float32:
return enc.EncodeFloat32(vt)
case *EmbeddedJSON:
return enc.EncodeEmbeddedJSON(vt)
default:
return InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt))
}
}
// AddInterface adds an interface{} to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInterface(value interface{}) {
switch vt := value.(type) {
case string:
enc.AddString(vt)
case bool:
enc.AddBool(vt)
case MarshalerJSONArray:
enc.AddArray(vt)
case MarshalerJSONObject:
enc.AddObject(vt)
case int:
enc.AddInt(vt)
case int64:
enc.AddInt(int(vt))
case int32:
enc.AddInt(int(vt))
case int8:
enc.AddInt(int(vt))
case uint64:
enc.AddUint64(vt)
case uint32:
enc.AddInt(int(vt))
case uint16:
enc.AddInt(int(vt))
case uint8:
enc.AddInt(int(vt))
case float64:
enc.AddFloat(vt)
case float32:
enc.AddFloat32(vt)
default:
if vt != nil {
enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt))
return
}
return
}
}
// AddInterfaceKey adds an interface{} to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInterfaceKey(key string, value interface{}) {
switch vt := value.(type) {
case string:
enc.AddStringKey(key, vt)
case bool:
enc.AddBoolKey(key, vt)
case MarshalerJSONArray:
enc.AddArrayKey(key, vt)
case MarshalerJSONObject:
enc.AddObjectKey(key, vt)
case int:
enc.AddIntKey(key, vt)
case int64:
enc.AddIntKey(key, int(vt))
case int32:
enc.AddIntKey(key, int(vt))
case int16:
enc.AddIntKey(key, int(vt))
case int8:
enc.AddIntKey(key, int(vt))
case uint64:
enc.AddIntKey(key, int(vt))
case uint32:
enc.AddIntKey(key, int(vt))
case uint16:
enc.AddIntKey(key, int(vt))
case uint8:
enc.AddIntKey(key, int(vt))
case float64:
enc.AddFloatKey(key, vt)
case float32:
enc.AddFloat32Key(key, vt)
default:
if vt != nil {
enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt))
return
}
return
}
}
// AddInterfaceKeyOmitEmpty adds an interface{} to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInterfaceKeyOmitEmpty(key string, v interface{}) {
switch vt := v.(type) {
case string:
enc.AddStringKeyOmitEmpty(key, vt)
case bool:
enc.AddBoolKeyOmitEmpty(key, vt)
case MarshalerJSONArray:
enc.AddArrayKeyOmitEmpty(key, vt)
case MarshalerJSONObject:
enc.AddObjectKeyOmitEmpty(key, vt)
case int:
enc.AddIntKeyOmitEmpty(key, vt)
case int64:
enc.AddIntKeyOmitEmpty(key, int(vt))
case int32:
enc.AddIntKeyOmitEmpty(key, int(vt))
case int16:
enc.AddIntKeyOmitEmpty(key, int(vt))
case int8:
enc.AddIntKeyOmitEmpty(key, int(vt))
case uint64:
enc.AddIntKeyOmitEmpty(key, int(vt))
case uint32:
enc.AddIntKeyOmitEmpty(key, int(vt))
case uint16:
enc.AddIntKeyOmitEmpty(key, int(vt))
case uint8:
enc.AddIntKeyOmitEmpty(key, int(vt))
case float64:
enc.AddFloatKeyOmitEmpty(key, vt)
case float32:
enc.AddFloat32KeyOmitEmpty(key, vt)
default:
if vt != nil {
enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt))
return
}
return
}
}
golang-github-francoispqt-gojay-1.2.13/encode_interface_test.go 0000664 0000000 0000000 00000012176 13653316651 0024646 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
var encoderTestCases = []struct {
v interface{}
expectations func(t *testing.T, b string, err error)
}{
{
v: 100,
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: int64(100),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: int32(100),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: int8(100),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: uint64(100),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: uint32(100),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: uint16(100),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: uint8(100),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100", b, "b should equal 100")
},
},
{
v: float64(100.12),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100.12", b, "b should equal 100.12")
},
},
{
v: float32(100.12),
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "100.12", b, "b should equal 100.12")
},
},
{
v: true,
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "true", b, "b should equal true")
},
},
{
v: "hello world",
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `"hello world"`, b, `b should equal "hello world"`)
},
},
{
v: "hello world",
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `"hello world"`, b, `b should equal "hello world"`)
},
},
{
v: &TestEncodingArrStrings{"hello world", "foo bar"},
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `["hello world","foo bar"]`, b, `b should equal ["hello world","foo bar"]`)
},
},
{
v: &testObject{
"æ¼¢å—", nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil,
1, nil, 1, nil, 1, nil, 1, nil, 1.1, nil, 1.1, nil, true, nil,
&testObject{}, testSliceInts{}, []interface{}{"h", "o", "l", "a"},
},
expectations: func(t *testing.T, b string, err error) {
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"testStr":"æ¼¢å—","testInt":1,"testInt64":1,"testInt32":1,"testInt16":1,"testInt8":1,"testUint64":1,"testUint32":1,"testUint16":1,"testUint8":1,"testFloat64":1.1,"testFloat32":1.1,"testBool":true}`, string(b), `string(b) should equal {"testStr":"æ¼¢å—","testInt":1,"testInt64":1,"testInt32":1,"testInt16":1,"testInt8":1,"testUint64":1,"testUint32":1,"testUint16":1,"testUint8":1,"testFloat64":1.1,"testFloat32":1.1,"testBool":true}`)
},
},
{
v: &struct{}{},
expectations: func(t *testing.T, b string, err error) {
assert.NotNil(t, err, "err should be nil")
assert.IsType(t, InvalidMarshalError(""), err, "err should be of type InvalidMarshalError")
var s = struct{}{}
assert.Equal(t, fmt.Sprintf(invalidMarshalErrorMsg, &s), err.Error(), "err message should be equal to invalidMarshalErrorMsg")
},
},
}
func TestEncoderInterfaceEncodeAPI(t *testing.T) {
t.Run("encode-all-types", func(t *testing.T) {
for _, test := range encoderTestCases {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
err := enc.Encode(test.v)
enc.Release()
test.expectations(t, builder.String(), err)
}
})
t.Run("encode-all-types-write-error", func(t *testing.T) {
v := ""
w := TestWriterError("")
enc := BorrowEncoder(w)
err := enc.Encode(v)
assert.NotNil(t, err, "err should not be nil")
})
t.Run("encode-all-types-pool-error", func(t *testing.T) {
v := ""
w := TestWriterError("")
enc := BorrowEncoder(w)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.Encode(v)
assert.True(t, false, "should not be called as decoder should have panicked")
})
}
func TestEncoderInterfaceMarshalAPI(t *testing.T) {
t.Run("marshal-all-types", func(t *testing.T) {
for _, test := range encoderTestCases {
b, err := Marshal(test.v)
test.expectations(t, string(b), err)
}
})
}
golang-github-francoispqt-gojay-1.2.13/encode_null.go 0000664 0000000 0000000 00000001557 13653316651 0022622 0 ustar 00root root 0000000 0000000 package gojay
// AddNull adds a `null` to be encoded. Must be used while encoding an array.`
func (enc *Encoder) AddNull() {
enc.Null()
}
// Null adds a `null` to be encoded. Must be used while encoding an array.`
func (enc *Encoder) Null() {
enc.grow(5)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeBytes(nullBytes)
}
// AddNullKey adds a `null` to be encoded. Must be used while encoding an array.`
func (enc *Encoder) AddNullKey(key string) {
enc.NullKey(key)
}
// NullKey adds a `null` to be encoded. Must be used while encoding an array.`
func (enc *Encoder) NullKey(key string) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.writeBytes(nullBytes)
}
golang-github-francoispqt-gojay-1.2.13/encode_null_test.go 0000664 0000000 0000000 00000002610 13653316651 0023650 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncodeNull(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st element",
baseJSON: `[`,
expectedJSON: `[null,null`,
},
{
name: "basic last element",
baseJSON: `["test"`,
expectedJSON: `["test",null,null`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Null()
enc.AddNull()
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncodeNullKey(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st element",
baseJSON: `{`,
expectedJSON: `{"foo":null,"bar":null`,
},
{
name: "basic last element",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":null`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.NullKey("foo")
enc.AddNullKey("bar")
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_number.go 0000664 0000000 0000000 00000000016 13653316651 0023125 0 ustar 00root root 0000000 0000000 package gojay
golang-github-francoispqt-gojay-1.2.13/encode_number_float.go 0000664 0000000 0000000 00000025231 13653316651 0024320 0 ustar 00root root 0000000 0000000 package gojay
import "strconv"
// EncodeFloat encodes a float64 to JSON
func (enc *Encoder) EncodeFloat(n float64) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeFloat(n)
_, err := enc.Write()
if err != nil {
return err
}
return nil
}
// encodeFloat encodes a float64 to JSON
func (enc *Encoder) encodeFloat(n float64) ([]byte, error) {
enc.buf = strconv.AppendFloat(enc.buf, n, 'f', -1, 64)
return enc.buf, nil
}
// EncodeFloat32 encodes a float32 to JSON
func (enc *Encoder) EncodeFloat32(n float32) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeFloat32(n)
_, err := enc.Write()
if err != nil {
return err
}
return nil
}
func (enc *Encoder) encodeFloat32(n float32) ([]byte, error) {
enc.buf = strconv.AppendFloat(enc.buf, float64(n), 'f', -1, 32)
return enc.buf, nil
}
// AddFloat adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat(v float64) {
enc.Float64(v)
}
// AddFloatOmitEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddFloatOmitEmpty(v float64) {
enc.Float64OmitEmpty(v)
}
// AddFloatNullEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddFloatNullEmpty(v float64) {
enc.Float64NullEmpty(v)
}
// Float adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Float(v float64) {
enc.Float64(v)
}
// FloatOmitEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) FloatOmitEmpty(v float64) {
enc.Float64OmitEmpty(v)
}
// FloatNullEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) FloatNullEmpty(v float64) {
enc.Float64NullEmpty(v)
}
// AddFloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloatKey(key string, v float64) {
enc.Float64Key(key, v)
}
// AddFloatKeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddFloatKeyOmitEmpty(key string, v float64) {
enc.Float64KeyOmitEmpty(key, v)
}
// AddFloatKeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddFloatKeyNullEmpty(key string, v float64) {
enc.Float64KeyNullEmpty(key, v)
}
// FloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) FloatKey(key string, v float64) {
enc.Float64Key(key, v)
}
// FloatKeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) FloatKeyOmitEmpty(key string, v float64) {
enc.Float64KeyOmitEmpty(key, v)
}
// FloatKeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) FloatKeyNullEmpty(key string, v float64) {
enc.Float64KeyNullEmpty(key, v)
}
// AddFloat64 adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat64(v float64) {
enc.Float(v)
}
// AddFloat64OmitEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddFloat64OmitEmpty(v float64) {
enc.FloatOmitEmpty(v)
}
// Float64 adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Float64(v float64) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
// Float64OmitEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Float64OmitEmpty(v float64) {
if v == 0 {
return
}
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
// Float64NullEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Float64NullEmpty(v float64) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
// AddFloat64Key adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat64Key(key string, v float64) {
enc.FloatKey(key, v)
}
// AddFloat64KeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat64KeyOmitEmpty(key string, v float64) {
enc.FloatKeyOmitEmpty(key, v)
}
// Float64Key adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Float64Key(key string, value float64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.grow(10)
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendFloat(enc.buf, value, 'f', -1, 64)
}
// Float64KeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) Float64KeyOmitEmpty(key string, v float64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v == 0 {
return
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
// Float64KeyNullEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Float64KeyNullEmpty(key string, v float64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
// AddFloat32 adds a float32 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat32(v float32) {
enc.Float32(v)
}
// AddFloat32OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddFloat32OmitEmpty(v float32) {
enc.Float32OmitEmpty(v)
}
// AddFloat32NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddFloat32NullEmpty(v float32) {
enc.Float32NullEmpty(v)
}
// Float32 adds a float32 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Float32(v float32) {
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
// Float32OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Float32OmitEmpty(v float32) {
if v == 0 {
return
}
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
// Float32NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Float32NullEmpty(v float32) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
// AddFloat32Key adds a float32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat32Key(key string, v float32) {
enc.Float32Key(key, v)
}
// AddFloat32KeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat32KeyOmitEmpty(key string, v float32) {
enc.Float32KeyOmitEmpty(key, v)
}
// AddFloat32KeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat32KeyNullEmpty(key string, v float32) {
enc.Float32KeyNullEmpty(key, v)
}
// Float32Key adds a float32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Float32Key(key string, v float32) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeByte('"')
enc.writeByte(':')
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
// Float32KeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) Float32KeyOmitEmpty(key string, v float32) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v == 0 {
return
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
// Float32KeyNullEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
func (enc *Encoder) Float32KeyNullEmpty(key string, v float32) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
}
golang-github-francoispqt-gojay-1.2.13/encode_number_float_test.go 0000664 0000000 0000000 00000012502 13653316651 0025354 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncoderFloat64(t *testing.T) {
var testCasesBasic = []struct {
name string
v float64
expectedJSON string
}{
{
name: "basic",
v: float64(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: float64(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Float64(testCase.v)
enc.AddFloat64(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v float64
expectedJSON string
}{
{
name: "basic",
v: float64(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: float64(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Float64OmitEmpty(testCase.v)
enc.AddFloat64OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v float64
expectedJSON string
}{
{
name: "basic",
v: float64(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: float64(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Float64Key("foo", testCase.v)
enc.AddFloat64Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v float64
expectedJSON string
}{
{
name: "basic",
v: float64(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: float64(0),
expectedJSON: "{}",
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Float64KeyOmitEmpty("foo", testCase.v)
enc.AddFloat64KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderFloat64NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.FloatNullEmpty(0)
enc.AddFloatNullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderFloat64KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.FloatKeyNullEmpty("foo", 0)
enc.AddFloatKeyNullEmpty("bar", 1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderFloat32NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Float32NullEmpty(0)
enc.AddFloat32NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderFloat32KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Float32KeyNullEmpty("foo", 0)
enc.AddFloat32KeyNullEmpty("bar", 1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_number_int.go 0000664 0000000 0000000 00000036353 13653316651 0024014 0 ustar 00root root 0000000 0000000 package gojay
import "strconv"
// EncodeInt encodes an int to JSON
func (enc *Encoder) EncodeInt(n int) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeInt(n)
_, err := enc.Write()
if err != nil {
return err
}
return nil
}
// encodeInt encodes an int to JSON
func (enc *Encoder) encodeInt(n int) ([]byte, error) {
enc.buf = strconv.AppendInt(enc.buf, int64(n), 10)
return enc.buf, nil
}
// EncodeInt64 encodes an int64 to JSON
func (enc *Encoder) EncodeInt64(n int64) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeInt64(n)
_, err := enc.Write()
if err != nil {
return err
}
return nil
}
// encodeInt64 encodes an int to JSON
func (enc *Encoder) encodeInt64(n int64) ([]byte, error) {
enc.buf = strconv.AppendInt(enc.buf, n, 10)
return enc.buf, nil
}
// AddInt adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt(v int) {
enc.Int(v)
}
// AddIntOmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddIntOmitEmpty(v int) {
enc.IntOmitEmpty(v)
}
// AddIntNullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddIntNullEmpty(v int) {
enc.IntNullEmpty(v)
}
// Int adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int(v int) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
// IntOmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) IntOmitEmpty(v int) {
if v == 0 {
return
}
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
// IntNullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) IntNullEmpty(v int) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
// AddIntKey adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddIntKey(key string, v int) {
enc.IntKey(key, v)
}
// AddIntKeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddIntKeyOmitEmpty(key string, v int) {
enc.IntKeyOmitEmpty(key, v)
}
// AddIntKeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddIntKeyNullEmpty(key string, v int) {
enc.IntKeyNullEmpty(key, v)
}
// IntKey adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) IntKey(key string, v int) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
// IntKeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) IntKeyOmitEmpty(key string, v int) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v == 0 {
return
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
// IntKeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) IntKeyNullEmpty(key string, v int) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
}
// AddInt64 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt64(v int64) {
enc.Int64(v)
}
// AddInt64OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddInt64OmitEmpty(v int64) {
enc.Int64OmitEmpty(v)
}
// AddInt64NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddInt64NullEmpty(v int64) {
enc.Int64NullEmpty(v)
}
// Int64 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int64(v int64) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
// Int64OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int64OmitEmpty(v int64) {
if v == 0 {
return
}
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
// Int64NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int64NullEmpty(v int64) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
// AddInt64Key adds an int64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt64Key(key string, v int64) {
enc.Int64Key(key, v)
}
// AddInt64KeyOmitEmpty adds an int64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddInt64KeyOmitEmpty(key string, v int64) {
enc.Int64KeyOmitEmpty(key, v)
}
// AddInt64KeyNullEmpty adds an int64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddInt64KeyNullEmpty(key string, v int64) {
enc.Int64KeyNullEmpty(key, v)
}
// Int64Key adds an int64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Int64Key(key string, v int64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
// Int64KeyOmitEmpty adds an int64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int64KeyOmitEmpty(key string, v int64) {
if v == 0 {
return
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
// Int64KeyNullEmpty adds an int64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int64KeyNullEmpty(key string, v int64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendInt(enc.buf, v, 10)
}
// AddInt32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt32(v int32) {
enc.Int64(int64(v))
}
// AddInt32OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddInt32OmitEmpty(v int32) {
enc.Int64OmitEmpty(int64(v))
}
// AddInt32NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddInt32NullEmpty(v int32) {
enc.Int64NullEmpty(int64(v))
}
// Int32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int32(v int32) {
enc.Int64(int64(v))
}
// Int32OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int32OmitEmpty(v int32) {
enc.Int64OmitEmpty(int64(v))
}
// Int32NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int32NullEmpty(v int32) {
enc.Int64NullEmpty(int64(v))
}
// AddInt32Key adds an int32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt32Key(key string, v int32) {
enc.Int64Key(key, int64(v))
}
// AddInt32KeyOmitEmpty adds an int32 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddInt32KeyOmitEmpty(key string, v int32) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
// Int32Key adds an int32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Int32Key(key string, v int32) {
enc.Int64Key(key, int64(v))
}
// Int32KeyOmitEmpty adds an int32 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int32KeyOmitEmpty(key string, v int32) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
// Int32KeyNullEmpty adds an int32 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int32KeyNullEmpty(key string, v int32) {
enc.Int64KeyNullEmpty(key, int64(v))
}
// AddInt16 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt16(v int16) {
enc.Int64(int64(v))
}
// AddInt16OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddInt16OmitEmpty(v int16) {
enc.Int64OmitEmpty(int64(v))
}
// Int16 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int16(v int16) {
enc.Int64(int64(v))
}
// Int16OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int16OmitEmpty(v int16) {
enc.Int64OmitEmpty(int64(v))
}
// Int16NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int16NullEmpty(v int16) {
enc.Int64NullEmpty(int64(v))
}
// AddInt16Key adds an int16 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt16Key(key string, v int16) {
enc.Int64Key(key, int64(v))
}
// AddInt16KeyOmitEmpty adds an int16 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddInt16KeyOmitEmpty(key string, v int16) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
// AddInt16KeyNullEmpty adds an int16 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddInt16KeyNullEmpty(key string, v int16) {
enc.Int64KeyNullEmpty(key, int64(v))
}
// Int16Key adds an int16 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Int16Key(key string, v int16) {
enc.Int64Key(key, int64(v))
}
// Int16KeyOmitEmpty adds an int16 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int16KeyOmitEmpty(key string, v int16) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
// Int16KeyNullEmpty adds an int16 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int16KeyNullEmpty(key string, v int16) {
enc.Int64KeyNullEmpty(key, int64(v))
}
// AddInt8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt8(v int8) {
enc.Int64(int64(v))
}
// AddInt8OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddInt8OmitEmpty(v int8) {
enc.Int64OmitEmpty(int64(v))
}
// AddInt8NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddInt8NullEmpty(v int8) {
enc.Int64NullEmpty(int64(v))
}
// Int8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Int8(v int8) {
enc.Int64(int64(v))
}
// Int8OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int8OmitEmpty(v int8) {
enc.Int64OmitEmpty(int64(v))
}
// Int8NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Int8NullEmpty(v int8) {
enc.Int64NullEmpty(int64(v))
}
// AddInt8Key adds an int8 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddInt8Key(key string, v int8) {
enc.Int64Key(key, int64(v))
}
// AddInt8KeyOmitEmpty adds an int8 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddInt8KeyOmitEmpty(key string, v int8) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
// AddInt8KeyNullEmpty adds an int8 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddInt8KeyNullEmpty(key string, v int8) {
enc.Int64KeyNullEmpty(key, int64(v))
}
// Int8Key adds an int8 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Int8Key(key string, v int8) {
enc.Int64Key(key, int64(v))
}
// Int8KeyOmitEmpty adds an int8 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int8KeyOmitEmpty(key string, v int8) {
enc.Int64KeyOmitEmpty(key, int64(v))
}
// Int8KeyNullEmpty adds an int8 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Int8KeyNullEmpty(key string, v int8) {
enc.Int64KeyNullEmpty(key, int64(v))
}
golang-github-francoispqt-gojay-1.2.13/encode_number_int_test.go 0000664 0000000 0000000 00000045047 13653316651 0025053 0 ustar 00root root 0000000 0000000 package gojay
import (
"math"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncoderInt64(t *testing.T) {
var testCasesBasic = []struct {
name string
v int64
expectedJSON string
}{
{
name: "basic",
v: int64(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt64,
expectedJSON: "[9223372036854775807,9223372036854775807]",
},
{
name: "big",
v: int64(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int64(testCase.v)
enc.AddInt64(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v int64
expectedJSON string
}{
{
name: "basic",
v: int64(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt64,
expectedJSON: "[9223372036854775807,9223372036854775807]",
},
{
name: "big",
v: int64(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int64OmitEmpty(testCase.v)
enc.AddInt64OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v int64
expectedJSON string
}{
{
name: "basic",
v: int64(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt64,
expectedJSON: `{"foo":9223372036854775807,"bar":9223372036854775807}`,
},
{
name: "big",
v: int64(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int64Key("foo", testCase.v)
enc.AddInt64Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v int64
expectedJSON string
}{
{
name: "basic",
v: int64(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt64,
expectedJSON: `{"foo":9223372036854775807,"bar":9223372036854775807}`,
},
{
name: "big",
v: int64(0),
expectedJSON: `{}`,
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int64KeyOmitEmpty("foo", testCase.v)
enc.AddInt64KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt32(t *testing.T) {
var testCasesBasic = []struct {
name string
v int32
expectedJSON string
}{
{
name: "basic",
v: int32(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt32,
expectedJSON: "[2147483647,2147483647]",
},
{
name: "big",
v: int32(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int32(testCase.v)
enc.AddInt32(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v int32
expectedJSON string
}{
{
name: "basic",
v: int32(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt32,
expectedJSON: "[2147483647,2147483647]",
},
{
name: "big",
v: int32(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int32OmitEmpty(testCase.v)
enc.AddInt32OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v int32
expectedJSON string
}{
{
name: "basic",
v: int32(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt32,
expectedJSON: `{"foo":2147483647,"bar":2147483647}`,
},
{
name: "big",
v: int32(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int32Key("foo", testCase.v)
enc.AddInt32Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v int32
expectedJSON string
}{
{
name: "basic",
v: int32(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt32,
expectedJSON: `{"foo":2147483647,"bar":2147483647}`,
},
{
name: "big",
v: int32(0),
expectedJSON: `{}`,
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int32KeyOmitEmpty("foo", testCase.v)
enc.AddInt32KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt16(t *testing.T) {
var testCasesBasic = []struct {
name string
v int16
expectedJSON string
}{
{
name: "basic",
v: int16(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt16,
expectedJSON: "[32767,32767]",
},
{
name: "big",
v: int16(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int16(testCase.v)
enc.AddInt16(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v int16
expectedJSON string
}{
{
name: "basic",
v: int16(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt16,
expectedJSON: "[32767,32767]",
},
{
name: "big",
v: int16(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int16OmitEmpty(testCase.v)
enc.AddInt16OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v int16
expectedJSON string
}{
{
name: "basic",
v: int16(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt16,
expectedJSON: `{"foo":32767,"bar":32767}`,
},
{
name: "big",
v: int16(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int16Key("foo", testCase.v)
enc.AddInt16Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v int16
expectedJSON string
}{
{
name: "basic",
v: int16(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt16,
expectedJSON: `{"foo":32767,"bar":32767}`,
},
{
name: "big",
v: int16(0),
expectedJSON: `{}`,
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int16KeyOmitEmpty("foo", testCase.v)
enc.AddInt16KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt8(t *testing.T) {
var testCasesBasic = []struct {
name string
v int8
expectedJSON string
}{
{
name: "basic",
v: int8(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt8,
expectedJSON: "[127,127]",
},
{
name: "big",
v: int8(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int8(testCase.v)
enc.AddInt8(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v int8
expectedJSON string
}{
{
name: "basic",
v: int8(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxInt8,
expectedJSON: "[127,127]",
},
{
name: "big",
v: int8(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Int8OmitEmpty(testCase.v)
enc.AddInt8OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v int8
expectedJSON string
}{
{
name: "basic",
v: int8(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt8,
expectedJSON: `{"foo":127,"bar":127}`,
},
{
name: "big",
v: int8(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int8Key("foo", testCase.v)
enc.AddInt8Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v int8
expectedJSON string
}{
{
name: "basic",
v: int8(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxInt8,
expectedJSON: `{"foo":127,"bar":127}`,
},
{
name: "big",
v: int8(0),
expectedJSON: `{}`,
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Int8KeyOmitEmpty("foo", testCase.v)
enc.AddInt8KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderIntNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.IntNullEmpty(0)
enc.AddIntNullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderIntKeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.IntKeyNullEmpty("foo", 0)
enc.AddIntKeyNullEmpty("bar", 1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt64NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Int64NullEmpty(0)
enc.AddInt64NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt64KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Int64KeyNullEmpty("foo", 0)
enc.AddInt64KeyNullEmpty("bar", 1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt32NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Int32NullEmpty(0)
enc.AddInt32NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt32KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Int32KeyNullEmpty("foo", 0)
enc.Int32KeyNullEmpty("bar", int32(1))
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt16NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Int16NullEmpty(0)
enc.Int16NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt16KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddInt16KeyNullEmpty("foo", 0)
enc.Int16KeyNullEmpty("bar", int16(1))
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt8NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddInt8NullEmpty(0)
enc.Int8NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderInt8KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddInt8KeyNullEmpty("foo", 0)
enc.Int8KeyNullEmpty("bar", int8(1))
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_number_test.go 0000664 0000000 0000000 00000035034 13653316651 0024174 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"fmt"
"math"
"github.com/stretchr/testify/assert"
)
func TestEncoderNumberEncodeAPI(t *testing.T) {
t.Run("encoder-int", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeInt(1)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("encode-int64", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeInt64(math.MaxInt64)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
fmt.Sprintf("%d", math.MaxInt64),
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("encode-uint64", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeUint64(uint64(math.MaxUint64))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
fmt.Sprintf("%d", uint64(math.MaxUint64)),
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("encode-float64", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeFloat(float64(1.1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1.1`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("encode-float32", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeFloat32(float32(1.12))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1.12`,
builder.String(),
"Result of marshalling is different as the one expected")
})
}
func TestEncoderNumberEncodeAPIErrors(t *testing.T) {
t.Run("encode-int-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeInt(1)
assert.True(t, false, "should not be called as encoder should have panicked")
})
t.Run("encode-int-write-error", func(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
err := enc.EncodeInt(1)
assert.NotNil(t, err, "err should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err should be of type InvalidUsagePooledEncoderError")
})
t.Run("encode-int64-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeInt64(1)
assert.True(t, false, "should not be called as encoder should have panicked")
})
t.Run("encode-int64-write-error", func(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
err := enc.EncodeInt64(1)
assert.NotNil(t, err, "err should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err should be of type InvalidUsagePooledEncoderError")
})
t.Run("encode-uint64-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeUint64(1)
assert.True(t, false, "should not be called as encoder should have panicked")
})
t.Run("encode-unt64-write-error", func(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
err := enc.EncodeUint64(1)
assert.NotNil(t, err, "err should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err should be of type InvalidUsagePooledEncoderError")
})
t.Run("encode-float64-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeFloat(1.1)
assert.True(t, false, "should not be called as encoder should have panicked")
})
t.Run("encode-float64-write-error", func(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
err := enc.EncodeFloat(1.1)
assert.NotNil(t, err, "err should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err should be of type InvalidUsagePooledEncoderError")
})
t.Run("encode-float32-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeFloat32(float32(1.1))
assert.True(t, false, "should not be called as encoder should have panicked")
})
t.Run("encode-float32-write-error", func(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
err := enc.EncodeFloat32(float32(1.1))
assert.NotNil(t, err, "err should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err should be of type InvalidUsagePooledEncoderError")
})
}
func TestEncoderNumberMarshalAPI(t *testing.T) {
t.Run("int", func(t *testing.T) {
r, err := Marshal(1)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("int64", func(t *testing.T) {
r, err := Marshal(int64(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("int32", func(t *testing.T) {
r, err := Marshal(int32(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("int16", func(t *testing.T) {
r, err := Marshal(int16(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("int8", func(t *testing.T) {
r, err := Marshal(int8(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("uint64", func(t *testing.T) {
r, err := Marshal(uint64(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("uint32", func(t *testing.T) {
r, err := Marshal(uint32(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("uint16", func(t *testing.T) {
r, err := Marshal(uint16(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("uint8", func(t *testing.T) {
r, err := Marshal(uint8(1))
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("float64", func(t *testing.T) {
r, err := Marshal(1.1)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`1.1`,
string(r),
"Result of marshalling is different as the one expected")
})
}
func TestAddNumberFunc(t *testing.T) {
t.Run("int64-key", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('{')
enc.AddInt64Key("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-key-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`{"test":1`))
enc.AddInt64Key("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":1,"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-key-omit-empty", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('{')
enc.AddInt64KeyOmitEmpty("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-key-omit-empty-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`{"test":1`))
enc.AddInt64KeyOmitEmpty("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":1,"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-key-omit-empty-3", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('{')
enc.AddInt64KeyOmitEmpty("test", 0)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('[')
enc.AddInt64(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`[1`))
enc.AddInt64(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[1,10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-omit-empty", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('[')
enc.AddInt64OmitEmpty(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-omit-empty-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`[1`))
enc.AddInt64OmitEmpty(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[1,10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("int64-omit-empty-3", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('[')
enc.AddInt64OmitEmpty(0)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
}
func TestEncodeUint64(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
err := enc.Encode(uint64(145509))
assert.Nil(t, err, "err should be nil")
assert.Equal(t, "145509", builder.String(), "builder.String() should be 145509")
}
func TestUint64Add(t *testing.T) {
t.Run("uint64-key", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('{')
enc.AddUint64Key("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-key-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`{"test":1`))
enc.AddUint64Key("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":1,"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-key-omit-empty", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('{')
enc.AddUint64KeyOmitEmpty("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-key-omit-empty-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`{"test":1`))
enc.AddUint64KeyOmitEmpty("test", 10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{"test":1,"test":10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-key-omit-empty-3", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('{')
enc.AddUint64KeyOmitEmpty("test", 0)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `{`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('[')
enc.AddUint64(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`[1`))
enc.AddUint64(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[1,10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-omit-empty", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('[')
enc.AddUint64OmitEmpty(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-omit-empty-2", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeBytes([]byte(`[1`))
enc.AddUint64OmitEmpty(10)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[1,10`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
t.Run("uint64-omit-empty-3", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
enc.writeByte('[')
enc.AddUint64OmitEmpty(0)
_, err := enc.Write()
assert.Nil(t, err, "err should be nil")
assert.Equal(t, `[`, builder.String(), `builder.String() should be equal to {"test":10"`)
})
}
golang-github-francoispqt-gojay-1.2.13/encode_number_uint.go 0000664 0000000 0000000 00000027666 13653316651 0024210 0 ustar 00root root 0000000 0000000 package gojay
import "strconv"
// EncodeUint64 encodes an int64 to JSON
func (enc *Encoder) EncodeUint64(n uint64) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeUint64(n)
_, err := enc.Write()
if err != nil {
return err
}
return nil
}
// encodeUint64 encodes an int to JSON
func (enc *Encoder) encodeUint64(n uint64) ([]byte, error) {
enc.buf = strconv.AppendUint(enc.buf, n, 10)
return enc.buf, nil
}
// AddUint64 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddUint64(v uint64) {
enc.Uint64(v)
}
// AddUint64OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint64OmitEmpty(v uint64) {
enc.Uint64OmitEmpty(v)
}
// AddUint64NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint64NullEmpty(v uint64) {
enc.Uint64NullEmpty(v)
}
// Uint64 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint64(v uint64) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
// Uint64OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint64OmitEmpty(v uint64) {
if v == 0 {
return
}
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
// Uint64NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint64NullEmpty(v uint64) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
// AddUint64Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint64Key(key string, v uint64) {
enc.Uint64Key(key, v)
}
// AddUint64KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint64KeyOmitEmpty(key string, v uint64) {
enc.Uint64KeyOmitEmpty(key, v)
}
// AddUint64KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint64KeyNullEmpty(key string, v uint64) {
enc.Uint64KeyNullEmpty(key, v)
}
// Uint64Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint64Key(key string, v uint64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
// Uint64KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint64KeyOmitEmpty(key string, v uint64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v == 0 {
return
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
// Uint64KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint64KeyNullEmpty(key string, v uint64) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v == 0 {
enc.writeBytes(nullBytes)
return
}
enc.buf = strconv.AppendUint(enc.buf, v, 10)
}
// AddUint32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddUint32(v uint32) {
enc.Uint64(uint64(v))
}
// AddUint32OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint32OmitEmpty(v uint32) {
enc.Uint64OmitEmpty(uint64(v))
}
// AddUint32NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint32NullEmpty(v uint32) {
enc.Uint64NullEmpty(uint64(v))
}
// Uint32 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint32(v uint32) {
enc.Uint64(uint64(v))
}
// Uint32OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint32OmitEmpty(v uint32) {
enc.Uint64OmitEmpty(uint64(v))
}
// Uint32NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint32NullEmpty(v uint32) {
enc.Uint64NullEmpty(uint64(v))
}
// AddUint32Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint32Key(key string, v uint32) {
enc.Uint64Key(key, uint64(v))
}
// AddUint32KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint32KeyOmitEmpty(key string, v uint32) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
// AddUint32KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint32KeyNullEmpty(key string, v uint32) {
enc.Uint64KeyNullEmpty(key, uint64(v))
}
// Uint32Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint32Key(key string, v uint32) {
enc.Uint64Key(key, uint64(v))
}
// Uint32KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint32KeyOmitEmpty(key string, v uint32) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
// Uint32KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint32KeyNullEmpty(key string, v uint32) {
enc.Uint64KeyNullEmpty(key, uint64(v))
}
// AddUint16 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddUint16(v uint16) {
enc.Uint64(uint64(v))
}
// AddUint16OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint16OmitEmpty(v uint16) {
enc.Uint64OmitEmpty(uint64(v))
}
// AddUint16NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint16NullEmpty(v uint16) {
enc.Uint64NullEmpty(uint64(v))
}
// Uint16 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint16(v uint16) {
enc.Uint64(uint64(v))
}
// Uint16OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint16OmitEmpty(v uint16) {
enc.Uint64OmitEmpty(uint64(v))
}
// Uint16NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint16NullEmpty(v uint16) {
enc.Uint64NullEmpty(uint64(v))
}
// AddUint16Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint16Key(key string, v uint16) {
enc.Uint64Key(key, uint64(v))
}
// AddUint16KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint16KeyOmitEmpty(key string, v uint16) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
// AddUint16KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint16KeyNullEmpty(key string, v uint16) {
enc.Uint64KeyNullEmpty(key, uint64(v))
}
// Uint16Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint16Key(key string, v uint16) {
enc.Uint64Key(key, uint64(v))
}
// Uint16KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint16KeyOmitEmpty(key string, v uint16) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
// Uint16KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint16KeyNullEmpty(key string, v uint16) {
enc.Uint64KeyNullEmpty(key, uint64(v))
}
// AddUint8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddUint8(v uint8) {
enc.Uint64(uint64(v))
}
// AddUint8OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint8OmitEmpty(v uint8) {
enc.Uint64OmitEmpty(uint64(v))
}
// AddUint8NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddUint8NullEmpty(v uint8) {
enc.Uint64NullEmpty(uint64(v))
}
// Uint8 adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Uint8(v uint8) {
enc.Uint64(uint64(v))
}
// Uint8OmitEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint8OmitEmpty(v uint8) {
enc.Uint64OmitEmpty(uint64(v))
}
// Uint8NullEmpty adds an int to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) Uint8NullEmpty(v uint8) {
enc.Uint64NullEmpty(uint64(v))
}
// AddUint8Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddUint8Key(key string, v uint8) {
enc.Uint64Key(key, uint64(v))
}
// AddUint8KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint8KeyOmitEmpty(key string, v uint8) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
// AddUint8KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) AddUint8KeyNullEmpty(key string, v uint8) {
enc.Uint64KeyNullEmpty(key, uint64(v))
}
// Uint8Key adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) Uint8Key(key string, v uint8) {
enc.Uint64Key(key, uint64(v))
}
// Uint8KeyOmitEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint8KeyOmitEmpty(key string, v uint8) {
enc.Uint64KeyOmitEmpty(key, uint64(v))
}
// Uint8KeyNullEmpty adds an int to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key.
func (enc *Encoder) Uint8KeyNullEmpty(key string, v uint8) {
enc.Uint64KeyNullEmpty(key, uint64(v))
}
golang-github-francoispqt-gojay-1.2.13/encode_number_uint_test.go 0000664 0000000 0000000 00000042547 13653316651 0025242 0 ustar 00root root 0000000 0000000 package gojay
import (
"math"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncoderUint64(t *testing.T) {
var testCasesBasic = []struct {
name string
v uint64
expectedJSON string
}{
{
name: "basic",
v: uint64(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint64,
expectedJSON: "[18446744073709551615,18446744073709551615]",
},
{
name: "big",
v: uint64(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint64(testCase.v)
enc.AddUint64(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v uint64
expectedJSON string
}{
{
name: "basic",
v: uint64(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint64,
expectedJSON: "[18446744073709551615,18446744073709551615]",
},
{
name: "big",
v: uint64(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint64OmitEmpty(testCase.v)
enc.AddUint64OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v uint64
expectedJSON string
}{
{
name: "basic",
v: uint64(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint64,
expectedJSON: `{"foo":18446744073709551615,"bar":18446744073709551615}`,
},
{
name: "big",
v: uint64(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint64Key("foo", testCase.v)
enc.AddUint64Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v uint64
expectedJSON string
}{
{
name: "basic",
v: uint64(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint64,
expectedJSON: `{"foo":18446744073709551615,"bar":18446744073709551615}`,
},
{
name: "big",
v: uint64(0),
expectedJSON: "{}",
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint64KeyOmitEmpty("foo", testCase.v)
enc.AddUint64KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint32(t *testing.T) {
var testCasesBasic = []struct {
name string
v uint32
expectedJSON string
}{
{
name: "basic",
v: uint32(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint32,
expectedJSON: "[4294967295,4294967295]",
},
{
name: "big",
v: uint32(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint32(testCase.v)
enc.AddUint32(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v uint32
expectedJSON string
}{
{
name: "basic",
v: uint32(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint32,
expectedJSON: "[4294967295,4294967295]",
},
{
name: "big",
v: uint32(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint32OmitEmpty(testCase.v)
enc.AddUint32OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v uint32
expectedJSON string
}{
{
name: "basic",
v: uint32(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint32,
expectedJSON: `{"foo":4294967295,"bar":4294967295}`,
},
{
name: "big",
v: uint32(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint32Key("foo", testCase.v)
enc.AddUint32Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v uint32
expectedJSON string
}{
{
name: "basic",
v: uint32(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint32,
expectedJSON: `{"foo":4294967295,"bar":4294967295}`,
},
{
name: "big",
v: uint32(0),
expectedJSON: `{}`,
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint32KeyOmitEmpty("foo", testCase.v)
enc.AddUint32KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint16(t *testing.T) {
var testCasesBasic = []struct {
name string
v uint16
expectedJSON string
}{
{
name: "basic",
v: uint16(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint16,
expectedJSON: "[65535,65535]",
},
{
name: "big",
v: uint16(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint16(testCase.v)
enc.AddUint16(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v uint16
expectedJSON string
}{
{
name: "basic",
v: uint16(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint16,
expectedJSON: "[65535,65535]",
},
{
name: "big",
v: uint16(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint16OmitEmpty(testCase.v)
enc.AddUint16OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v uint16
expectedJSON string
}{
{
name: "basic",
v: uint16(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint16,
expectedJSON: `{"foo":65535,"bar":65535}`,
},
{
name: "big",
v: uint16(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint16Key("foo", testCase.v)
enc.AddUint16Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v uint16
expectedJSON string
}{
{
name: "basic",
v: uint16(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint16,
expectedJSON: `{"foo":65535,"bar":65535}`,
},
{
name: "big",
v: uint16(0),
expectedJSON: `{}`,
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint16KeyOmitEmpty("foo", testCase.v)
enc.AddUint16KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint8(t *testing.T) {
var testCasesBasic = []struct {
name string
v uint8
expectedJSON string
}{
{
name: "basic",
v: uint8(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint8,
expectedJSON: "[255,255]",
},
{
name: "big",
v: uint8(0),
expectedJSON: "[0,0]",
},
}
for _, testCase := range testCasesBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint8(testCase.v)
enc.AddUint8(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesOmitEmpty = []struct {
name string
v uint8
expectedJSON string
}{
{
name: "basic",
v: uint8(1),
expectedJSON: "[1,1]",
},
{
name: "big",
v: math.MaxUint8,
expectedJSON: "[255,255]",
},
{
name: "big",
v: uint8(0),
expectedJSON: "[]",
},
}
for _, testCase := range testCasesOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
enc.Uint8OmitEmpty(testCase.v)
enc.AddUint8OmitEmpty(testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyBasic = []struct {
name string
v uint8
expectedJSON string
}{
{
name: "basic",
v: uint8(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint8,
expectedJSON: `{"foo":255,"bar":255}`,
},
{
name: "big",
v: uint8(0),
expectedJSON: `{"foo":0,"bar":0}`,
},
}
for _, testCase := range testCasesKeyBasic {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint8Key("foo", testCase.v)
enc.AddUint8Key("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
var testCasesKeyOmitEmpty = []struct {
name string
v uint8
expectedJSON string
}{
{
name: "basic",
v: uint8(1),
expectedJSON: `{"foo":1,"bar":1}`,
},
{
name: "big",
v: math.MaxUint8,
expectedJSON: `{"foo":255,"bar":255}`,
},
{
name: "big",
v: uint8(0),
expectedJSON: `{}`,
},
}
for _, testCase := range testCasesKeyOmitEmpty {
t.Run(testCase.name, func(t *testing.T) {
var b = &strings.Builder{}
var enc = NewEncoder(b)
enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
enc.Uint8KeyOmitEmpty("foo", testCase.v)
enc.AddUint8KeyOmitEmpty("bar", testCase.v)
}))
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint64NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Uint64NullEmpty(0)
enc.AddUint64NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint64KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Uint64KeyNullEmpty("foo", 0)
enc.AddUint64KeyNullEmpty("bar", 1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint32NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.Uint32NullEmpty(0)
enc.AddUint32NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint32KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddUint32KeyNullEmpty("foo", 0)
enc.Uint32KeyNullEmpty("bar", uint32(1))
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint16NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddUint16NullEmpty(0)
enc.Uint16NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint16KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddUint16KeyNullEmpty("foo", 0)
enc.Uint16KeyNullEmpty("bar", uint16(1))
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint8NullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddUint8NullEmpty(0)
enc.Uint8NullEmpty(1)
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderUint8KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddUint8KeyNullEmpty("foo", 0)
enc.Uint8KeyNullEmpty("bar", uint8(1))
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_object.go 0000664 0000000 0000000 00000022443 13653316651 0023113 0 ustar 00root root 0000000 0000000 package gojay
var objKeyStr = []byte(`":"`)
var objKeyObj = []byte(`":{`)
var objKeyArr = []byte(`":[`)
var objKey = []byte(`":`)
// EncodeObject encodes an object to JSON
func (enc *Encoder) EncodeObject(v MarshalerJSONObject) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, err := enc.encodeObject(v)
if err != nil {
enc.err = err
return err
}
_, err = enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
// EncodeObjectKeys encodes an object to JSON
func (enc *Encoder) EncodeObjectKeys(v MarshalerJSONObject, keys []string) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
enc.hasKeys = true
enc.keys = keys
_, err := enc.encodeObject(v)
if err != nil {
enc.err = err
return err
}
_, err = enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
func (enc *Encoder) encodeObject(v MarshalerJSONObject) ([]byte, error) {
enc.grow(512)
enc.writeByte('{')
if !v.IsNil() {
v.MarshalJSONObject(enc)
}
if enc.hasKeys {
enc.hasKeys = false
enc.keys = nil
}
enc.writeByte('}')
return enc.buf, enc.err
}
// AddObject adds an object to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) AddObject(v MarshalerJSONObject) {
enc.Object(v)
}
// AddObjectOmitEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) AddObjectOmitEmpty(v MarshalerJSONObject) {
enc.ObjectOmitEmpty(v)
}
// AddObjectNullEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) AddObjectNullEmpty(v MarshalerJSONObject) {
enc.ObjectNullEmpty(v)
}
// AddObjectKey adds a struct to be encoded, must be used inside an object as it will encode a key
// value must implement MarshalerJSONObject
func (enc *Encoder) AddObjectKey(key string, v MarshalerJSONObject) {
enc.ObjectKey(key, v)
}
// AddObjectKeyOmitEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) AddObjectKeyOmitEmpty(key string, v MarshalerJSONObject) {
enc.ObjectKeyOmitEmpty(key, v)
}
// AddObjectKeyNullEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) AddObjectKeyNullEmpty(key string, v MarshalerJSONObject) {
enc.ObjectKeyNullEmpty(key, v)
}
// Object adds an object to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) Object(v MarshalerJSONObject) {
if v.IsNil() {
enc.grow(2)
r := enc.getPreviousRune()
if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
enc.writeByte('}')
return
}
enc.grow(4)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
var origHasKeys = enc.hasKeys
var origKeys = enc.keys
enc.hasKeys = false
enc.keys = nil
v.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// ObjectWithKeys adds an object to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject. It will only encode the keys in keys.
func (enc *Encoder) ObjectWithKeys(v MarshalerJSONObject, keys []string) {
if v.IsNil() {
enc.grow(2)
r := enc.getPreviousRune()
if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
enc.writeByte('}')
return
}
enc.grow(4)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
var origKeys = enc.keys
var origHasKeys = enc.hasKeys
enc.hasKeys = true
enc.keys = keys
v.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// ObjectOmitEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) ObjectOmitEmpty(v MarshalerJSONObject) {
if v.IsNil() {
return
}
enc.grow(2)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
var origHasKeys = enc.hasKeys
var origKeys = enc.keys
enc.hasKeys = false
enc.keys = nil
v.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// ObjectNullEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) ObjectNullEmpty(v MarshalerJSONObject) {
enc.grow(2)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
if v.IsNil() {
enc.writeBytes(nullBytes)
return
}
enc.writeByte('{')
var origHasKeys = enc.hasKeys
var origKeys = enc.keys
enc.hasKeys = false
enc.keys = nil
v.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// ObjectKey adds a struct to be encoded, must be used inside an object as it will encode a key
// value must implement MarshalerJSONObject
func (enc *Encoder) ObjectKey(key string, v MarshalerJSONObject) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v.IsNil() {
enc.grow(2 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyObj)
enc.writeByte('}')
return
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyObj)
var origHasKeys = enc.hasKeys
var origKeys = enc.keys
enc.hasKeys = false
enc.keys = nil
v.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// ObjectKeyWithKeys adds a struct to be encoded, must be used inside an object as it will encode a key.
// Value must implement MarshalerJSONObject. It will only encode the keys in keys.
func (enc *Encoder) ObjectKeyWithKeys(key string, value MarshalerJSONObject, keys []string) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if value.IsNil() {
enc.grow(2 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyObj)
enc.writeByte('}')
return
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyObj)
var origKeys = enc.keys
var origHasKeys = enc.hasKeys
enc.hasKeys = true
enc.keys = keys
value.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// ObjectKeyOmitEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) ObjectKeyOmitEmpty(key string, v MarshalerJSONObject) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v.IsNil() {
return
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKeyObj)
var origHasKeys = enc.hasKeys
var origKeys = enc.keys
enc.hasKeys = false
enc.keys = nil
v.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// ObjectKeyNullEmpty adds an object to be encoded or skips it if IsNil returns true.
// Must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerJSONObject
func (enc *Encoder) ObjectKeyNullEmpty(key string, v MarshalerJSONObject) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(5 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v.IsNil() {
enc.writeBytes(nullBytes)
return
}
enc.writeByte('{')
var origHasKeys = enc.hasKeys
var origKeys = enc.keys
enc.hasKeys = false
enc.keys = nil
v.MarshalJSONObject(enc)
enc.hasKeys = origHasKeys
enc.keys = origKeys
enc.writeByte('}')
}
// EncodeObjectFunc is a custom func type implementing MarshaleObject.
// Use it to cast a func(*Encoder) to Marshal an object.
//
// enc := gojay.NewEncoder(io.Writer)
// enc.EncodeObject(gojay.EncodeObjectFunc(func(enc *gojay.Encoder) {
// enc.AddStringKey("hello", "world")
// }))
type EncodeObjectFunc func(*Encoder)
// MarshalJSONObject implements MarshalerJSONObject.
func (f EncodeObjectFunc) MarshalJSONObject(enc *Encoder) {
f(enc)
}
// IsNil implements MarshalerJSONObject.
func (f EncodeObjectFunc) IsNil() bool {
return f == nil
}
func (enc *Encoder) keyExists(k string) bool {
if enc.keys == nil {
return false
}
for _, key := range enc.keys {
if key == k {
return true
}
}
return false
}
golang-github-francoispqt-gojay-1.2.13/encode_object_test.go 0000664 0000000 0000000 00000056574 13653316651 0024166 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type testObjectWithUnknownType struct {
unknownType struct{}
}
func (t *testObjectWithUnknownType) IsNil() bool {
return t == nil
}
func (t *testObjectWithUnknownType) MarshalJSONObject(enc *Encoder) {
enc.AddInterfaceKey("unknownType", t.unknownType)
}
type TestEncoding struct {
test string
test2 string
testInt int
testBool bool
testF32 float32
testF64 float64
testInterface interface{}
testArr TestEncodingArr
sub *SubObject
}
func (t *TestEncoding) IsNil() bool {
return t == nil
}
func (t *TestEncoding) MarshalJSONObject(enc *Encoder) {
enc.AddStringKey("test", t.test)
enc.AddStringKey("test2", t.test2)
enc.AddIntKey("testInt", t.testInt)
enc.AddBoolKey("testBool", t.testBool)
enc.AddInterfaceKey("testArr", t.testArr)
enc.AddInterfaceKey("testF64", t.testF64)
enc.AddInterfaceKey("testF32", t.testF32)
enc.AddInterfaceKey("testInterface", t.testInterface)
enc.AddInterfaceKey("sub", t.sub)
}
type SubObject struct {
test1 int
test2 string
test3 float64
testBool bool
sub *SubObject
}
func (t *SubObject) IsNil() bool {
return t == nil
}
func (t *SubObject) MarshalJSONObject(enc *Encoder) {
enc.AddIntKey("test1", t.test1)
enc.AddStringKey("test2", t.test2)
enc.AddFloatKey("test3", t.test3)
enc.AddBoolKey("testBool", t.testBool)
enc.AddObjectKey("sub", t.sub)
}
type testEncodingObjInterfaces struct {
interfaceVal interface{}
}
func (t *testEncodingObjInterfaces) IsNil() bool {
return t == nil
}
func (t *testEncodingObjInterfaces) MarshalJSONObject(enc *Encoder) {
enc.AddInterfaceKey("interfaceVal", t.interfaceVal)
}
func TestEncoderObjectEncodeAPI(t *testing.T) {
t.Run("encode-basic", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeObject(&testObject{
"æ¼¢å—", nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil,
1, nil, 1, nil, 1.1, nil, 1.1, nil, true, nil,
&testObject{}, testSliceInts{}, interface{}("test"),
})
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"testStr":"æ¼¢å—","testInt":1,"testInt64":1,"testInt32":1,"testInt16":1,"testInt8":1,"testUint64":1,"testUint32":1,"testUint16":1,"testUint8":1,"testFloat64":1.1,"testFloat32":1.1,"testBool":true}`,
builder.String(),
"Result of marshalling is different as the one expected",
)
})
}
func TestEncoderObjectMarshalAPI(t *testing.T) {
t.Run("marshal-basic", func(t *testing.T) {
r, err := Marshal(&testObject{
"æ¼¢å—", nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1,
nil, 1, nil, 1, nil, 1.1, nil, 1.1, nil, true, nil,
&testObject{}, testSliceInts{}, []interface{}{"h", "o", "l", "a"},
})
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"testStr":"æ¼¢å—","testInt":1,"testInt64":1,"testInt32":1,"testInt16":1,"testInt8":1,"testUint64":1,"testUint32":1,"testUint16":1,"testUint8":1,"testFloat64":1.1,"testFloat32":1.1,"testBool":true}`,
string(r),
"Result of marshalling is different as the one expected",
)
})
t.Run("marshal-complex", func(t *testing.T) {
v := &TestEncoding{
test: "hello world",
test2: "foobar",
testInt: 1,
testBool: true,
testF32: 120.53,
testF64: 120.15,
testInterface: true,
testArr: TestEncodingArr{
&TestEncoding{
test: "1",
},
},
sub: &SubObject{
test1: 10,
test2: "hello world",
test3: 1.23543,
testBool: true,
sub: &SubObject{
test1: 10,
testBool: false,
test2: "hello world",
},
},
}
r, err := MarshalJSONObject(v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"test":"hello world","test2":"foobar","testInt":1,"testBool":true,"testArr":[{"test":"1","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}],"testF64":120.15,"testF32":120.53,"testInterface":true,"sub":{"test1":10,"test2":"hello world","test3":1.23543,"testBool":true,"sub":{"test1":10,"test2":"hello world","test3":0,"testBool":false,"sub":{}}}}`,
string(r),
"Result of marshalling is different as the one expected",
)
})
t.Run("marshal-interface-string", func(t *testing.T) {
v := testEncodingObjInterfaces{"string"}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":"string"}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-int", func(t *testing.T) {
v := testEncodingObjInterfaces{1}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-int64", func(t *testing.T) {
v := testEncodingObjInterfaces{int64(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-int32", func(t *testing.T) {
v := testEncodingObjInterfaces{int32(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-int16", func(t *testing.T) {
v := testEncodingObjInterfaces{int16(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-int8", func(t *testing.T) {
v := testEncodingObjInterfaces{int8(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-uint64", func(t *testing.T) {
v := testEncodingObjInterfaces{uint64(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-uint32", func(t *testing.T) {
v := testEncodingObjInterfaces{uint32(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-uint16", func(t *testing.T) {
v := testEncodingObjInterfaces{uint16(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-uint8", func(t *testing.T) {
v := testEncodingObjInterfaces{uint8(1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-float64", func(t *testing.T) {
v := testEncodingObjInterfaces{float64(1.1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1.1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-interface-float32", func(t *testing.T) {
v := testEncodingObjInterfaces{float32(1.1)}
r, err := Marshal(&v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"interfaceVal":1.1}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-object-func", func(t *testing.T) {
f := EncodeObjectFunc(func(enc *Encoder) {
enc.AddStringKeyOmitEmpty("test", "test")
})
r, err := Marshal(f)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"test":"test"}`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("marshal-any-object", func(t *testing.T) {
test := struct {
Foo string
Bar int
}{
"test",
100,
}
r, err := MarshalAny(test)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"Foo":"test","Bar":100}`,
string(r),
"Result of marshalling is different as the one expected")
})
}
type TestObectOmitEmpty struct {
nonNiler int
testInt int
testFloat float64
testFloat32 float32
testString string
testBool bool
testObectOmitEmpty *TestObectOmitEmpty
testObect *TestObectOmitEmpty
}
func (t *TestObectOmitEmpty) IsNil() bool {
return t == nil
}
func (t *TestObectOmitEmpty) MarshalJSONObject(enc *Encoder) {
enc.AddIntKeyOmitEmpty("testInt", t.testInt)
enc.AddIntKeyOmitEmpty("testIntNotEmpty", 1)
enc.AddFloatKeyOmitEmpty("testFloat", t.testFloat)
enc.AddFloatKeyOmitEmpty("testFloatNotEmpty", 1.1)
enc.AddFloat32KeyOmitEmpty("testFloat32", t.testFloat32)
enc.AddFloat32KeyOmitEmpty("testFloat32NotEmpty", 1.1)
enc.AddStringKeyOmitEmpty("testString", t.testString)
enc.AddStringKeyOmitEmpty("testStringNotEmpty", "foo")
enc.AddBoolKeyOmitEmpty("testBool", t.testBool)
enc.AddBoolKeyOmitEmpty("testBoolNotEmpty", true)
enc.AddObjectKeyOmitEmpty("testObect", t.testObect)
enc.AddObjectKeyOmitEmpty("testObectOmitEmpty", t.testObectOmitEmpty)
enc.AddArrayKeyOmitEmpty("testArrayOmitEmpty", TestEncodingArrStrings{})
enc.AddArrayKeyOmitEmpty("testArray", TestEncodingArrStrings{"foo"})
}
type TestObectOmitEmptyInterface struct{}
func (t *TestObectOmitEmptyInterface) IsNil() bool {
return t == nil
}
func (t *TestObectOmitEmptyInterface) MarshalJSONObject(enc *Encoder) {
enc.AddInterfaceKeyOmitEmpty("testInt", 0)
enc.AddInterfaceKeyOmitEmpty("testInt64", int64(0))
enc.AddInterfaceKeyOmitEmpty("testInt32", int32(0))
enc.AddInterfaceKeyOmitEmpty("testInt16", int16(0))
enc.AddInterfaceKeyOmitEmpty("testInt8", int8(0))
enc.AddInterfaceKeyOmitEmpty("testUint8", uint8(0))
enc.AddInterfaceKeyOmitEmpty("testUint16", uint16(0))
enc.AddInterfaceKeyOmitEmpty("testUint32", uint32(0))
enc.AddInterfaceKeyOmitEmpty("testUint64", uint64(0))
enc.AddInterfaceKeyOmitEmpty("testIntNotEmpty", 1)
enc.AddInterfaceKeyOmitEmpty("testFloat", 0)
enc.AddInterfaceKeyOmitEmpty("testFloatNotEmpty", 1.1)
enc.AddInterfaceKeyOmitEmpty("testFloat32", float32(0))
enc.AddInterfaceKeyOmitEmpty("testFloat32NotEmpty", float32(1.1))
enc.AddInterfaceKeyOmitEmpty("testString", "")
enc.AddInterfaceKeyOmitEmpty("testStringNotEmpty", "foo")
enc.AddInterfaceKeyOmitEmpty("testBool", false)
enc.AddInterfaceKeyOmitEmpty("testBoolNotEmpty", true)
enc.AddInterfaceKeyOmitEmpty("testObectOmitEmpty", nil)
enc.AddInterfaceKeyOmitEmpty("testObect", &TestEncoding{})
enc.AddInterfaceKeyOmitEmpty("testArr", &TestEncodingArrStrings{})
}
func TestEncoderObjectOmitEmpty(t *testing.T) {
t.Run("encoder-omit-empty-all-types", func(t *testing.T) {
v := &TestObectOmitEmpty{
nonNiler: 1,
testInt: 0,
testObect: &TestObectOmitEmpty{testInt: 1},
}
r, err := MarshalJSONObject(v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"testIntNotEmpty":1,"testFloatNotEmpty":1.1,"testFloat32NotEmpty":1.1,"testStringNotEmpty":"foo","testBoolNotEmpty":true,"testObect":{"testInt":1,"testIntNotEmpty":1,"testFloatNotEmpty":1.1,"testFloat32NotEmpty":1.1,"testStringNotEmpty":"foo","testBoolNotEmpty":true,"testArray":["foo"]},"testArray":["foo"]}`,
string(r),
"Result of marshalling is different as the one expected",
)
})
t.Run("encoder-omit-empty-interface", func(t *testing.T) {
v := &TestObectOmitEmptyInterface{}
r, err := MarshalJSONObject(v)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`{"testIntNotEmpty":1,"testFloatNotEmpty":1.1,"testFloat32NotEmpty":1.1,"testStringNotEmpty":"foo","testBoolNotEmpty":true,"testObect":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}}`,
string(r),
"Result of marshalling is different as the one expected",
)
})
}
func TestEncoderObjectEncodeAPIError(t *testing.T) {
t.Run("interface-key-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeObject(&testObjectWithUnknownType{struct{}{}})
assert.NotNil(t, err, "Error should not be nil")
assert.Equal(t, "Invalid type struct {} provided to Marshal", err.Error(), "err.Error() should be 'Invalid type struct {} provided to Marshal'")
})
t.Run("write-error", func(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
err := enc.EncodeObject(&testObject{})
assert.NotNil(t, err, "Error should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err.Error() should be 'Test Error'")
})
t.Run("interface-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.AddInterfaceKeyOmitEmpty("test", struct{}{})
assert.NotNil(t, enc.err, "enc.Err() should not be nil")
})
t.Run("pool-error", func(t *testing.T) {
v := &TestEncoding{}
enc := BorrowEncoder(nil)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
_ = enc.EncodeObject(v)
assert.True(t, false, "should not be called as it should have panicked")
})
}
func TestEncoderObjectKeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddObjectKeyNullEmpty("foo", (*TestEncoding)(nil))
enc.ObjectKeyNullEmpty("bar", &TestEncoding{})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderObjectNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddObjectNullEmpty((*TestEncoding)(nil))
enc.ObjectNullEmpty(&TestEncoding{})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
type ObjectWithKeys struct {
Str string
Int int
Int64 int64
Int32 int32
Int16 int16
Int8 int8
Uint64 uint64
Uint32 uint32
Uint16 uint16
Uint8 uint8
Float64 float64
Float32 float32
Bool bool
Obj *ObjectWithKeys
Slice TestEncodingArrStrings
Time *time.Time
EmbeddedJSON *EmbeddedJSON
}
func (o *ObjectWithKeys) MarshalJSONObject(enc *Encoder) {
enc.StringKey("string", o.Str)
enc.StringKeyOmitEmpty("string", o.Str)
enc.StringKeyNullEmpty("string", o.Str)
enc.IntKey("int", o.Int)
enc.IntKeyOmitEmpty("int", o.Int)
enc.IntKeyNullEmpty("int", o.Int)
enc.Int64Key("int64", o.Int64)
enc.Int64KeyOmitEmpty("int64", o.Int64)
enc.Int64KeyNullEmpty("int64", o.Int64)
enc.Int32Key("int32", o.Int32)
enc.Int32KeyOmitEmpty("int32", o.Int32)
enc.Int32KeyNullEmpty("int32", o.Int32)
enc.Int16Key("int16", o.Int16)
enc.Int16KeyOmitEmpty("int16", o.Int16)
enc.Int16KeyNullEmpty("int16", o.Int16)
enc.Int8Key("int8", o.Int8)
enc.Int8KeyOmitEmpty("int8", o.Int8)
enc.Int8KeyNullEmpty("int8", o.Int8)
enc.Uint64KeyOmitEmpty("uint64", o.Uint64)
enc.Uint64KeyNullEmpty("uint64", o.Uint64)
enc.Uint64Key("uint64", o.Uint64)
enc.Uint32Key("uint32", o.Uint32)
enc.Uint32KeyOmitEmpty("uint32", o.Uint32)
enc.Uint32KeyNullEmpty("uint32", o.Uint32)
enc.Uint16KeyOmitEmpty("uint16", o.Uint16)
enc.Uint16KeyNullEmpty("uint16", o.Uint16)
enc.Uint16Key("uint16", o.Uint16)
enc.Uint8Key("uint8", o.Uint8)
enc.Uint8KeyOmitEmpty("uint8", o.Uint8)
enc.Uint8KeyNullEmpty("uint8", o.Uint8)
enc.Float64Key("float64", o.Float64)
enc.Float64KeyOmitEmpty("float64", o.Float64)
enc.Float64KeyNullEmpty("float64", o.Float64)
enc.Float32Key("float32", o.Float32)
enc.Float32KeyOmitEmpty("float32", o.Float32)
enc.Float32KeyNullEmpty("float32", o.Float32)
enc.BoolKey("bool", o.Bool)
enc.BoolKeyOmitEmpty("bool", o.Bool)
enc.BoolKeyNullEmpty("bool", o.Bool)
enc.ObjectKeyOmitEmpty("object", o.Obj)
enc.ObjectKeyNullEmpty("object", o.Obj)
enc.ObjectKey("object", o.Obj)
enc.ArrayKey("array", o.Slice)
enc.ArrayKeyOmitEmpty("array", o.Slice)
enc.ArrayKeyNullEmpty("array", o.Slice)
enc.TimeKey("time", o.Time, time.RFC3339)
enc.AddEmbeddedJSONKey("ejson", o.EmbeddedJSON)
enc.AddEmbeddedJSONKeyOmitEmpty("ejson", o.EmbeddedJSON)
enc.NullKey("null")
}
func (o *ObjectWithKeys) IsNil() bool {
return o == nil
}
type NilObject struct{}
func (n *NilObject) MarshalJSONObject(enc *Encoder) {}
func (n *NilObject) IsNil() bool { return true }
func TestEncodeObjectWithKeys(t *testing.T) {
t.Run(
"should not encode any key",
func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
var o = &ObjectWithKeys{}
var err = enc.EncodeObjectKeys(o, []string{})
assert.Nil(t, err)
assert.Equal(t, `{}`, b.String())
},
)
t.Run(
"should encode some keys",
func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
var o = &ObjectWithKeys{Str: "hello", Int: 420}
var err = enc.EncodeObjectKeys(o, []string{"string", "int"})
assert.Nil(t, err)
assert.Equal(
t,
`{"string":"hello","string":"hello","string":"hello","int":420,"int":420,"int":420}`,
b.String(),
)
},
)
t.Run("write-error", func(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
o := &ObjectWithKeys{Str: "hello", Int: 420}
err := enc.EncodeObjectKeys(o, []string{"string", "int"})
assert.NotNil(t, err, "Error should not be nil")
assert.Equal(t, "Test Error", err.Error(), "err.Error() should be 'Test Error'")
})
t.Run("pool-error", func(t *testing.T) {
v := &TestEncoding{}
enc := BorrowEncoder(nil)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
_ = enc.EncodeObjectKeys(v, []string{})
assert.True(t, false, "should not be called as it should have panicked")
})
t.Run("interface-key-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeObjectKeys(&testObjectWithUnknownType{struct{}{}}, []string{})
assert.NotNil(t, err, "Error should not be nil")
assert.Equal(t, "Invalid type struct {} provided to Marshal", err.Error(), "err.Error() should be 'Invalid type struct {} provided to Marshal'")
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeObjectKeys(EncodeObjectFunc(func(enc *Encoder) {
enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
enc.StringKey("test", "hello")
enc.StringKey("test2", "hello")
}), []string{"test"})
}), []string{})
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `{}`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
enc.keys = nil
enc.StringKey("test", "hello")
enc.StringKey("test2", "hello")
}), []string{"test"})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `{"test":{}}`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
enc.StringKey("test", "hello")
enc.StringKey("test2", "hello")
}), []string{"test"})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `{"test":{"test":"hello"}}`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
enc.writeByte(' ')
enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
enc.StringKey("test", "hello")
enc.StringKey("test2", "hello")
}), []string{"test"})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `{ ,"test":{"test":"hello"}}`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
enc.writeByte(' ')
enc.ObjectKeyWithKeys("test", &NilObject{}, []string{})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `{ ,"test":{}}`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
enc.ObjectWithKeys(EncodeObjectFunc(func(enc *Encoder) {
enc.StringKey("test", "hello")
enc.StringKey("test2", "hello")
}), []string{"test"})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `[{"test":"hello"}]`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
enc.writeByte(' ')
enc.ObjectWithKeys(EncodeObjectFunc(func(enc *Encoder) {
enc.StringKey("test", "hello")
enc.StringKey("test2", "hello")
}), []string{"test"})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `[ ,{"test":"hello"}]`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
enc.ObjectWithKeys(&NilObject{}, []string{})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `[{}]`, b.String())
})
t.Run("encode-object-with-keys", func(t *testing.T) {
b := &strings.Builder{}
enc := NewEncoder(b)
err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
enc.writeByte(' ')
enc.ObjectWithKeys(&NilObject{}, []string{})
}))
assert.Nil(t, err, "Error should not be nil")
assert.Equal(t, `[ ,{}]`, b.String())
})
}
golang-github-francoispqt-gojay-1.2.13/encode_pool.go 0000664 0000000 0000000 00000001542 13653316651 0022613 0 ustar 00root root 0000000 0000000 package gojay
import (
"io"
"sync"
)
var encPool = sync.Pool{
New: func() interface{} {
return NewEncoder(nil)
},
}
var streamEncPool = sync.Pool{
New: func() interface{} {
return Stream.NewEncoder(nil)
},
}
func init() {
for i := 0; i < 32; i++ {
encPool.Put(NewEncoder(nil))
}
for i := 0; i < 32; i++ {
streamEncPool.Put(Stream.NewEncoder(nil))
}
}
// NewEncoder returns a new encoder or borrows one from the pool
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w}
}
// BorrowEncoder borrows an Encoder from the pool.
func BorrowEncoder(w io.Writer) *Encoder {
enc := encPool.Get().(*Encoder)
enc.w = w
enc.buf = enc.buf[:0]
enc.isPooled = 0
enc.err = nil
enc.hasKeys = false
enc.keys = nil
return enc
}
// Release sends back a Encoder to the pool.
func (enc *Encoder) Release() {
enc.isPooled = 1
encPool.Put(enc)
}
golang-github-francoispqt-gojay-1.2.13/encode_pool_test.go 0000664 0000000 0000000 00000000716 13653316651 0023654 0 ustar 00root root 0000000 0000000 package gojay
import (
"fmt"
"log"
"strconv"
"testing"
"time"
)
func TestConcurrencyMarshal(t *testing.T) {
var f = func(num int, t *testing.T) {
for {
b, err := Marshal(num)
if err != nil {
log.Fatal(err)
}
s := string(b)
if n, err := strconv.Atoi(s); err != nil || n != num {
t.Error(fmt.Errorf(
"caught race: %v %v", s, num,
))
}
}
}
for i := 0; i < 100; i++ {
go f(i, t)
}
time.Sleep(2 * time.Second)
}
golang-github-francoispqt-gojay-1.2.13/encode_slice.go 0000664 0000000 0000000 00000005066 13653316651 0022746 0 ustar 00root root 0000000 0000000 package gojay
// AddSliceString marshals the given []string s
func (enc *Encoder) AddSliceString(s []string) {
enc.SliceString(s)
}
// SliceString marshals the given []string s
func (enc *Encoder) SliceString(s []string) {
enc.Array(EncodeArrayFunc(func(enc *Encoder) {
for _, str := range s {
enc.String(str)
}
}))
}
// AddSliceStringKey marshals the given []string s
func (enc *Encoder) AddSliceStringKey(k string, s []string) {
enc.SliceStringKey(k, s)
}
// SliceStringKey marshals the given []string s
func (enc *Encoder) SliceStringKey(k string, s []string) {
enc.ArrayKey(k, EncodeArrayFunc(func(enc *Encoder) {
for _, str := range s {
enc.String(str)
}
}))
}
// AddSliceInt marshals the given []int s
func (enc *Encoder) AddSliceInt(s []int) {
enc.SliceInt(s)
}
// SliceInt marshals the given []int s
func (enc *Encoder) SliceInt(s []int) {
enc.Array(EncodeArrayFunc(func(enc *Encoder) {
for _, i := range s {
enc.Int(i)
}
}))
}
// AddSliceIntKey marshals the given []int s
func (enc *Encoder) AddSliceIntKey(k string, s []int) {
enc.SliceIntKey(k, s)
}
// SliceIntKey marshals the given []int s
func (enc *Encoder) SliceIntKey(k string, s []int) {
enc.ArrayKey(k, EncodeArrayFunc(func(enc *Encoder) {
for _, i := range s {
enc.Int(i)
}
}))
}
// AddSliceFloat64 marshals the given []float64 s
func (enc *Encoder) AddSliceFloat64(s []float64) {
enc.SliceFloat64(s)
}
// SliceFloat64 marshals the given []float64 s
func (enc *Encoder) SliceFloat64(s []float64) {
enc.Array(EncodeArrayFunc(func(enc *Encoder) {
for _, i := range s {
enc.Float64(i)
}
}))
}
// AddSliceFloat64Key marshals the given []float64 s
func (enc *Encoder) AddSliceFloat64Key(k string, s []float64) {
enc.SliceFloat64Key(k, s)
}
// SliceFloat64Key marshals the given []float64 s
func (enc *Encoder) SliceFloat64Key(k string, s []float64) {
enc.ArrayKey(k, EncodeArrayFunc(func(enc *Encoder) {
for _, i := range s {
enc.Float64(i)
}
}))
}
// AddSliceBool marshals the given []bool s
func (enc *Encoder) AddSliceBool(s []bool) {
enc.SliceBool(s)
}
// SliceBool marshals the given []bool s
func (enc *Encoder) SliceBool(s []bool) {
enc.Array(EncodeArrayFunc(func(enc *Encoder) {
for _, i := range s {
enc.Bool(i)
}
}))
}
// AddSliceBoolKey marshals the given []bool s
func (enc *Encoder) AddSliceBoolKey(k string, s []bool) {
enc.SliceBoolKey(k, s)
}
// SliceBoolKey marshals the given []bool s
func (enc *Encoder) SliceBoolKey(k string, s []bool) {
enc.ArrayKey(k, EncodeArrayFunc(func(enc *Encoder) {
for _, i := range s {
enc.Bool(i)
}
}))
}
golang-github-francoispqt-gojay-1.2.13/encode_slice_test.go 0000664 0000000 0000000 00000006616 13653316651 0024007 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func (s *slicesTestObject) MarshalJSONObject(enc *Encoder) {
enc.AddSliceStringKey("sliceString", s.sliceString)
enc.AddSliceIntKey("sliceInt", s.sliceInt)
enc.AddSliceFloat64Key("sliceFloat64", s.sliceFloat64)
enc.AddSliceBoolKey("sliceBool", s.sliceBool)
}
func (s *slicesTestObject) IsNil() bool {
return s == nil
}
func TestEncodeSlices(t *testing.T) {
testCases := []struct {
name string
json string
obj slicesTestObject
}{
{
name: "basic slice string",
json: `{
"sliceString": ["foo","bar"],
"sliceInt": [],
"sliceFloat64": [],
"sliceBool": []
}`,
obj: slicesTestObject{
sliceString: []string{"foo", "bar"},
},
},
{
name: "basic slice bool",
json: `{
"sliceString": [],
"sliceInt": [],
"sliceFloat64": [],
"sliceBool": [true,false]
}`,
obj: slicesTestObject{
sliceBool: []bool{true, false},
},
},
{
name: "basic slice int",
json: `{
"sliceString": [],
"sliceFloat64": [],
"sliceInt": [1,2,3],
"sliceBool": []
}`,
obj: slicesTestObject{
sliceInt: []int{1, 2, 3},
},
},
{
name: "basic slice float64",
json: `{
"sliceString": [],
"sliceFloat64": [1.3,2.4,3.1],
"sliceInt": [],
"sliceBool": []
}`,
obj: slicesTestObject{
sliceFloat64: []float64{1.3, 2.4, 3.1},
},
},
}
for _, testCase := range testCases {
t.Run(
testCase.name,
func(t *testing.T) {
b := strings.Builder{}
enc := BorrowEncoder(&b)
err := enc.Encode(&testCase.obj)
require.Nil(t, err, "err should be nil")
require.JSONEq(t, testCase.json, b.String())
},
)
}
}
type testSliceSliceString [][]string
func (t testSliceSliceString) MarshalJSONArray(enc *Encoder) {
for _, s := range t {
enc.AddSliceString(s)
}
}
func (t testSliceSliceString) IsNil() bool {
return t == nil
}
type testSliceSliceBool [][]bool
func (t testSliceSliceBool) MarshalJSONArray(enc *Encoder) {
for _, s := range t {
enc.AddSliceBool(s)
}
}
func (t testSliceSliceBool) IsNil() bool {
return t == nil
}
type testSliceSliceInt [][]int
func (t testSliceSliceInt) MarshalJSONArray(enc *Encoder) {
for _, s := range t {
enc.AddSliceInt(s)
}
}
func (t testSliceSliceInt) IsNil() bool {
return t == nil
}
type testSliceSliceFloat64 [][]float64
func (t testSliceSliceFloat64) MarshalJSONArray(enc *Encoder) {
for _, s := range t {
enc.AddSliceFloat64(s)
}
}
func (t testSliceSliceFloat64) IsNil() bool {
return t == nil
}
func TestEncodeSliceSlices(t *testing.T) {
testCases := []struct {
name string
s MarshalerJSONArray
json string
}{
{
name: "slice of strings",
s: testSliceSliceString{
[]string{"foo", "bar"},
},
json: `[["foo","bar"]]`,
},
{
name: "slice of ints",
s: testSliceSliceInt{
[]int{1, 2},
},
json: `[[1,2]]`,
},
{
name: "slice of float",
s: testSliceSliceFloat64{
[]float64{1.1, 1.2},
},
json: `[[1.1,1.2]]`,
},
{
name: "slice of bool",
s: testSliceSliceBool{
[]bool{true, false},
},
json: `[[true,false]]`,
},
}
for _, testCase := range testCases {
t.Run(
testCase.name,
func(t *testing.T) {
b := strings.Builder{}
enc := BorrowEncoder(&b)
err := enc.Encode(testCase.s)
require.Nil(t, err, "err should be nil")
require.JSONEq(t, testCase.json, b.String())
},
)
}
}
golang-github-francoispqt-gojay-1.2.13/encode_sqlnull.go 0000664 0000000 0000000 00000031630 13653316651 0023335 0 ustar 00root root 0000000 0000000 package gojay
import "database/sql"
// EncodeSQLNullString encodes a string to
func (enc *Encoder) EncodeSQLNullString(v *sql.NullString) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeString(v.String)
_, err := enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
// AddSQLNullString adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullString(v *sql.NullString) {
enc.String(v.String)
}
// AddSQLNullStringOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullStringOmitEmpty(v *sql.NullString) {
if v != nil && v.Valid && v.String != "" {
enc.StringOmitEmpty(v.String)
}
}
// AddSQLNullStringNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullStringNullEmpty(v *sql.NullString) {
if v != nil && v.Valid {
enc.StringNullEmpty(v.String)
}
}
// AddSQLNullStringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullStringKey(key string, v *sql.NullString) {
enc.StringKey(key, v.String)
}
// AddSQLNullStringKeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullStringKeyOmitEmpty(key string, v *sql.NullString) {
if v != nil && v.Valid && v.String != "" {
enc.StringKeyOmitEmpty(key, v.String)
}
}
// SQLNullString adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullString(v *sql.NullString) {
enc.String(v.String)
}
// SQLNullStringOmitEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullStringOmitEmpty(v *sql.NullString) {
if v != nil && v.Valid && v.String != "" {
enc.String(v.String)
}
}
// SQLNullStringNullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullStringNullEmpty(v *sql.NullString) {
if v != nil && v.Valid {
enc.StringNullEmpty(v.String)
}
}
// SQLNullStringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullStringKey(key string, v *sql.NullString) {
enc.StringKey(key, v.String)
}
// SQLNullStringKeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullStringKeyOmitEmpty(key string, v *sql.NullString) {
if v != nil && v.Valid && v.String != "" {
enc.StringKeyOmitEmpty(key, v.String)
}
}
// SQLNullStringKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullStringKeyNullEmpty(key string, v *sql.NullString) {
if v != nil && v.Valid {
enc.StringKeyNullEmpty(key, v.String)
}
}
// NullInt64
// EncodeSQLNullInt64 encodes a string to
func (enc *Encoder) EncodeSQLNullInt64(v *sql.NullInt64) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeInt64(v.Int64)
_, err := enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
// AddSQLNullInt64 adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullInt64(v *sql.NullInt64) {
enc.Int64(v.Int64)
}
// AddSQLNullInt64OmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullInt64OmitEmpty(v *sql.NullInt64) {
if v != nil && v.Valid && v.Int64 != 0 {
enc.Int64OmitEmpty(v.Int64)
}
}
// AddSQLNullInt64NullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullInt64NullEmpty(v *sql.NullInt64) {
if v != nil && v.Valid {
enc.Int64NullEmpty(v.Int64)
}
}
// AddSQLNullInt64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullInt64Key(key string, v *sql.NullInt64) {
enc.Int64Key(key, v.Int64)
}
// AddSQLNullInt64KeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullInt64KeyOmitEmpty(key string, v *sql.NullInt64) {
if v != nil && v.Valid && v.Int64 != 0 {
enc.Int64KeyOmitEmpty(key, v.Int64)
}
}
// AddSQLNullInt64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullInt64KeyNullEmpty(key string, v *sql.NullInt64) {
if v != nil && v.Valid {
enc.Int64KeyNullEmpty(key, v.Int64)
}
}
// SQLNullInt64 adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64(v *sql.NullInt64) {
enc.Int64(v.Int64)
}
// SQLNullInt64OmitEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64OmitEmpty(v *sql.NullInt64) {
if v != nil && v.Valid && v.Int64 != 0 {
enc.Int64(v.Int64)
}
}
// SQLNullInt64NullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64NullEmpty(v *sql.NullInt64) {
if v != nil && v.Valid {
enc.Int64NullEmpty(v.Int64)
}
}
// SQLNullInt64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64Key(key string, v *sql.NullInt64) {
enc.Int64Key(key, v.Int64)
}
// SQLNullInt64KeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64KeyOmitEmpty(key string, v *sql.NullInt64) {
if v != nil && v.Valid && v.Int64 != 0 {
enc.Int64KeyOmitEmpty(key, v.Int64)
}
}
// SQLNullInt64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullInt64KeyNullEmpty(key string, v *sql.NullInt64) {
if v != nil && v.Valid {
enc.Int64KeyNullEmpty(key, v.Int64)
}
}
// NullFloat64
// EncodeSQLNullFloat64 encodes a string to
func (enc *Encoder) EncodeSQLNullFloat64(v *sql.NullFloat64) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeFloat(v.Float64)
_, err := enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
// AddSQLNullFloat64 adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullFloat64(v *sql.NullFloat64) {
enc.Float64(v.Float64)
}
// AddSQLNullFloat64OmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullFloat64OmitEmpty(v *sql.NullFloat64) {
if v != nil && v.Valid && v.Float64 != 0 {
enc.Float64OmitEmpty(v.Float64)
}
}
// AddSQLNullFloat64NullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullFloat64NullEmpty(v *sql.NullFloat64) {
if v != nil && v.Valid {
enc.Float64NullEmpty(v.Float64)
}
}
// AddSQLNullFloat64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullFloat64Key(key string, v *sql.NullFloat64) {
enc.Float64Key(key, v.Float64)
}
// AddSQLNullFloat64KeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullFloat64KeyOmitEmpty(key string, v *sql.NullFloat64) {
if v != nil && v.Valid && v.Float64 != 0 {
enc.Float64KeyOmitEmpty(key, v.Float64)
}
}
// AddSQLNullFloat64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullFloat64KeyNullEmpty(key string, v *sql.NullFloat64) {
if v != nil && v.Valid {
enc.Float64KeyNullEmpty(key, v.Float64)
}
}
// SQLNullFloat64 adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64(v *sql.NullFloat64) {
enc.Float64(v.Float64)
}
// SQLNullFloat64OmitEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64OmitEmpty(v *sql.NullFloat64) {
if v != nil && v.Valid && v.Float64 != 0 {
enc.Float64(v.Float64)
}
}
// SQLNullFloat64NullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64NullEmpty(v *sql.NullFloat64) {
if v != nil && v.Valid {
enc.Float64NullEmpty(v.Float64)
}
}
// SQLNullFloat64Key adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64Key(key string, v *sql.NullFloat64) {
enc.Float64Key(key, v.Float64)
}
// SQLNullFloat64KeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64KeyOmitEmpty(key string, v *sql.NullFloat64) {
if v != nil && v.Valid && v.Float64 != 0 {
enc.Float64KeyOmitEmpty(key, v.Float64)
}
}
// SQLNullFloat64KeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullFloat64KeyNullEmpty(key string, v *sql.NullFloat64) {
if v != nil && v.Valid {
enc.Float64KeyNullEmpty(key, v.Float64)
}
}
// NullBool
// EncodeSQLNullBool encodes a string to
func (enc *Encoder) EncodeSQLNullBool(v *sql.NullBool) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeBool(v.Bool)
_, err := enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
// AddSQLNullBool adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullBool(v *sql.NullBool) {
enc.Bool(v.Bool)
}
// AddSQLNullBoolOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddSQLNullBoolOmitEmpty(v *sql.NullBool) {
if v != nil && v.Valid && v.Bool != false {
enc.BoolOmitEmpty(v.Bool)
}
}
// AddSQLNullBoolKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullBoolKey(key string, v *sql.NullBool) {
enc.BoolKey(key, v.Bool)
}
// AddSQLNullBoolKeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullBoolKeyOmitEmpty(key string, v *sql.NullBool) {
if v != nil && v.Valid && v.Bool != false {
enc.BoolKeyOmitEmpty(key, v.Bool)
}
}
// AddSQLNullBoolKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddSQLNullBoolKeyNullEmpty(key string, v *sql.NullBool) {
if v != nil && v.Valid {
enc.BoolKeyNullEmpty(key, v.Bool)
}
}
// SQLNullBool adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBool(v *sql.NullBool) {
enc.Bool(v.Bool)
}
// SQLNullBoolOmitEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBoolOmitEmpty(v *sql.NullBool) {
if v != nil && v.Valid && v.Bool != false {
enc.Bool(v.Bool)
}
}
// SQLNullBoolNullEmpty adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBoolNullEmpty(v *sql.NullBool) {
if v != nil && v.Valid {
enc.BoolNullEmpty(v.Bool)
}
}
// SQLNullBoolKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBoolKey(key string, v *sql.NullBool) {
enc.BoolKey(key, v.Bool)
}
// SQLNullBoolKeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBoolKeyOmitEmpty(key string, v *sql.NullBool) {
if v != nil && v.Valid && v.Bool != false {
enc.BoolKeyOmitEmpty(key, v.Bool)
}
}
// SQLNullBoolKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) SQLNullBoolKeyNullEmpty(key string, v *sql.NullBool) {
if v != nil && v.Valid {
enc.BoolKeyNullEmpty(key, v.Bool)
}
}
golang-github-francoispqt-gojay-1.2.13/encode_sqlnull_test.go 0000664 0000000 0000000 00000101444 13653316651 0024375 0 ustar 00root root 0000000 0000000 package gojay
import (
"database/sql"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
// Null String
func TestEncoceSQLNullString(t *testing.T) {
testCases := []struct {
name string
sqlNullString sql.NullString
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo bar",
},
expectedResult: `"foo bar"`,
},
{
name: "it should return an err as the string is invalid",
sqlNullString: sql.NullString{
String: "foo \t bar",
},
expectedResult: `"foo \t bar"`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
err := enc.EncodeSQLNullString(&testCase.sqlNullString)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedResult, b.String())
}
})
}
t.Run(
"should panic as the encoder is pooled",
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeSQLNullString(&sql.NullString{})
assert.True(t, false, "should not be called as encoder should have panicked")
},
)
t.Run(
"should return an error as the writer encounters an error",
func(t *testing.T) {
builder := TestWriterError("")
enc := NewEncoder(builder)
err := enc.EncodeSQLNullString(&sql.NullString{})
assert.NotNil(t, err)
},
)
}
func TestAddSQLNullStringKey(t *testing.T) {
t.Run(
"AddSQLNullStringKey",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullString sql.NullString
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo bar",
},
baseJSON: "{",
expectedResult: `{"foo":"foo bar"`,
},
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo \t bar",
},
baseJSON: "{",
expectedResult: `{"foo":"foo \t bar"`,
},
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo \t bar",
},
baseJSON: "{",
expectedResult: `{"foo":"foo \t bar"`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullStringKey("foo", &testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullStringKey("foo", &testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullStringKeyOmitEmpty, is should encode a sql.NullString",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullString sql.NullString
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo bar",
Valid: true,
},
baseJSON: "{",
expectedResult: `{"foo":"foo bar"`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullString: sql.NullString{
String: "foo \t bar",
Valid: false,
},
baseJSON: "{",
expectedResult: `{`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullStringKeyOmitEmpty("foo", &testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullStringKeyOmitEmpty("foo", &testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
func TestAddSQLNullString(t *testing.T) {
t.Run(
"AddSQLNullString",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullString sql.NullString
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo bar",
},
baseJSON: "[",
expectedResult: `["foo bar"`,
},
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo \t bar",
},
baseJSON: "[",
expectedResult: `["foo \t bar"`,
},
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo \t bar",
},
baseJSON: "[",
expectedResult: `["foo \t bar"`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullString(&testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullString(&testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullStringKeyOmitEmpty, is should encode a sql.NullString",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullString sql.NullString
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullString: sql.NullString{
String: "foo bar",
Valid: true,
},
baseJSON: "[",
expectedResult: `["foo bar"`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullString: sql.NullString{
String: "foo \t bar",
Valid: false,
},
baseJSON: "[",
expectedResult: `[`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullStringOmitEmpty(&testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullStringOmitEmpty(&testCase.sqlNullString)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
// NullInt64
func TestEncoceSQLNullInt64(t *testing.T) {
testCases := []struct {
name string
sqlNullInt64 sql.NullInt64
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: int64(1),
},
expectedResult: `1`,
},
{
name: "it should return an err as the string is invalid",
sqlNullInt64: sql.NullInt64{
Int64: int64(2),
},
expectedResult: `2`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
err := enc.EncodeSQLNullInt64(&testCase.sqlNullInt64)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedResult, b.String())
}
})
}
t.Run(
"should panic as the encoder is pooled",
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeSQLNullInt64(&sql.NullInt64{})
assert.True(t, false, "should not be called as encoder should have panicked")
},
)
t.Run(
"should return an error as the writer encounters an error",
func(t *testing.T) {
builder := TestWriterError("")
enc := NewEncoder(builder)
err := enc.EncodeSQLNullInt64(&sql.NullInt64{})
assert.NotNil(t, err)
},
)
}
func TestAddSQLNullInt64Key(t *testing.T) {
t.Run(
"AddSQLNullInt64Key",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullInt64 sql.NullInt64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 1,
},
baseJSON: "{",
expectedResult: `{"foo":1`,
},
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 2,
},
baseJSON: "{",
expectedResult: `{"foo":2`,
},
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 2,
},
baseJSON: "{",
expectedResult: `{"foo":2`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullInt64Key("foo", &testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullInt64Key("foo", &testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullInt64KeyOmitEmpty, is should encode a sql.NullInt64",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullInt64 sql.NullInt64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 1,
Valid: true,
},
baseJSON: "{",
expectedResult: `{"foo":1`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullInt64: sql.NullInt64{
Int64: 2,
Valid: false,
},
baseJSON: "{",
expectedResult: `{`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullInt64KeyOmitEmpty("foo", &testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullInt64KeyOmitEmpty("foo", &testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
func TestAddSQLNullInt64(t *testing.T) {
t.Run(
"AddSQLNullInt64",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullInt64 sql.NullInt64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 1,
},
baseJSON: "[",
expectedResult: `[1`,
},
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 2,
},
baseJSON: "[",
expectedResult: `[2`,
},
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 2,
},
baseJSON: "[",
expectedResult: `[2`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullInt64(&testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullInt64(&testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullInt64KeyOmitEmpty, is should encode a sql.NullInt64",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullInt64 sql.NullInt64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullInt64: sql.NullInt64{
Int64: 2,
Valid: true,
},
baseJSON: "[",
expectedResult: `[2`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullInt64: sql.NullInt64{
Int64: 2,
Valid: false,
},
baseJSON: "[",
expectedResult: `[`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullInt64OmitEmpty(&testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullInt64OmitEmpty(&testCase.sqlNullInt64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
// NullFloat64
func TestEncoceSQLNullFloat64(t *testing.T) {
testCases := []struct {
name string
sqlNullFloat64 sql.NullFloat64
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: float64(1),
},
expectedResult: `1`,
},
{
name: "it should return an err as the string is invalid",
sqlNullFloat64: sql.NullFloat64{
Float64: float64(2),
},
expectedResult: `2`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
err := enc.EncodeSQLNullFloat64(&testCase.sqlNullFloat64)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedResult, b.String())
}
})
}
t.Run(
"should panic as the encoder is pooled",
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeSQLNullFloat64(&sql.NullFloat64{})
assert.True(t, false, "should not be called as encoder should have panicked")
},
)
t.Run(
"should return an error as the writer encounters an error",
func(t *testing.T) {
builder := TestWriterError("")
enc := NewEncoder(builder)
err := enc.EncodeSQLNullFloat64(&sql.NullFloat64{})
assert.NotNil(t, err)
},
)
}
func TestAddSQLNullFloat64Key(t *testing.T) {
t.Run(
"AddSQLNullFloat64Key",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullFloat64 sql.NullFloat64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 1,
},
baseJSON: "{",
expectedResult: `{"foo":1`,
},
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 2,
},
baseJSON: "{",
expectedResult: `{"foo":2`,
},
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 2,
},
baseJSON: "{",
expectedResult: `{"foo":2`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullFloat64Key("foo", &testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullFloat64Key("foo", &testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullFloat64KeyOmitEmpty, is should encode a sql.NullFloat64",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullFloat64 sql.NullFloat64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 1,
Valid: true,
},
baseJSON: "{",
expectedResult: `{"foo":1`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullFloat64: sql.NullFloat64{
Float64: 2,
Valid: false,
},
baseJSON: "{",
expectedResult: `{`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullFloat64KeyOmitEmpty("foo", &testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullFloat64KeyOmitEmpty("foo", &testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
func TestAddSQLNullFloat64(t *testing.T) {
t.Run(
"AddSQLNullFloat64",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullFloat64 sql.NullFloat64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 1,
},
baseJSON: "[",
expectedResult: `[1`,
},
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 2,
},
baseJSON: "[",
expectedResult: `[2`,
},
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 2,
},
baseJSON: "[",
expectedResult: `[2`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullFloat64(&testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullFloat64(&testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullFloat64KeyOmitEmpty, is should encode a sql.NullFloat64",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullFloat64 sql.NullFloat64
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullFloat64: sql.NullFloat64{
Float64: 2,
Valid: true,
},
baseJSON: "[",
expectedResult: `[2`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullFloat64: sql.NullFloat64{
Float64: 2,
Valid: false,
},
baseJSON: "[",
expectedResult: `[`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullFloat64OmitEmpty(&testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullFloat64OmitEmpty(&testCase.sqlNullFloat64)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
// NullBool
func TestEncoceSQLNullBool(t *testing.T) {
testCases := []struct {
name string
sqlNullBool sql.NullBool
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: true,
},
expectedResult: `true`,
},
{
name: "it should return an err as the string is invalid",
sqlNullBool: sql.NullBool{
Bool: false,
},
expectedResult: `false`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
err := enc.EncodeSQLNullBool(&testCase.sqlNullBool)
if testCase.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedResult, b.String())
}
})
}
t.Run(
"should panic as the encoder is pooled",
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeSQLNullBool(&sql.NullBool{})
assert.True(t, false, "should not be called as encoder should have panicked")
},
)
t.Run(
"should return an error as the writer encounters an error",
func(t *testing.T) {
builder := TestWriterError("")
enc := NewEncoder(builder)
err := enc.EncodeSQLNullBool(&sql.NullBool{})
assert.NotNil(t, err)
},
)
}
func TestAddSQLNullBoolKey(t *testing.T) {
t.Run(
"AddSQLNullBoolKey",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullBool sql.NullBool
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: true,
},
baseJSON: "{",
expectedResult: `{"foo":true`,
},
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: false,
},
baseJSON: "{",
expectedResult: `{"foo":false`,
},
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: true,
},
baseJSON: "{",
expectedResult: `{"foo":true`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullBoolKey("foo", &testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullBoolKey("foo", &testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullBoolKeyOmitEmpty, is should encode a sql.NullBool",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullBool sql.NullBool
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: true,
Valid: true,
},
baseJSON: "{",
expectedResult: `{"foo":true`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullBool: sql.NullBool{
Bool: true,
Valid: false,
},
baseJSON: "{",
expectedResult: `{`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullBoolKeyOmitEmpty("foo", &testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullBoolKeyOmitEmpty("foo", &testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
func TestAddSQLNullBool(t *testing.T) {
t.Run(
"AddSQLNullBool",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullBool sql.NullBool
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: true,
},
baseJSON: "[",
expectedResult: `[true`,
},
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: true,
},
baseJSON: "[",
expectedResult: `[true`,
},
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: false,
},
baseJSON: "[",
expectedResult: `[false`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullBool(&testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullBool(&testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
t.Run(
"AddSQLNullBoolKeyOmitEmpty, is should encode a sql.NullBool",
func(t *testing.T) {
testCases := []struct {
name string
sqlNullBool sql.NullBool
baseJSON string
expectedResult string
err bool
}{
{
name: "it should encode a null string",
sqlNullBool: sql.NullBool{
Bool: true,
Valid: true,
},
baseJSON: "[",
expectedResult: `[true`,
},
{
name: "it should not encode anything as null string is invalid",
sqlNullBool: sql.NullBool{
Bool: true,
Valid: false,
},
baseJSON: "[",
expectedResult: `[`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullBoolOmitEmpty(&testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b.String())
var b2 strings.Builder
enc = NewEncoder(&b2)
enc.writeString(testCase.baseJSON)
enc.SQLNullBoolOmitEmpty(&testCase.sqlNullBool)
enc.Write()
assert.Equal(t, testCase.expectedResult, b2.String())
})
}
},
)
}
func TestEncoderSQLNullStringEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,"bar"`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,"bar"`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullStringNullEmpty(&sql.NullString{"", true})
enc.SQLNullStringNullEmpty(&sql.NullString{"bar", true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderSQLNullStringKeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":"bar"`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":"bar"`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.SQLNullStringKeyNullEmpty("foo", &sql.NullString{"", true})
enc.SQLNullStringKeyNullEmpty("bar", &sql.NullString{"bar", true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderSQLNullBoolEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,true`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,true`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.SQLNullBoolNullEmpty(&sql.NullBool{false, true})
enc.SQLNullBoolNullEmpty(&sql.NullBool{true, true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderSQLNullBoolKeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":true`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":true`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullBoolKeyNullEmpty("foo", &sql.NullBool{false, true})
enc.SQLNullBoolKeyNullEmpty("bar", &sql.NullBool{true, true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderSQLNullInt64Empty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullInt64NullEmpty(&sql.NullInt64{0, true})
enc.SQLNullInt64NullEmpty(&sql.NullInt64{1, true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderSQLNullInt64KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullInt64KeyNullEmpty("foo", &sql.NullInt64{0, true})
enc.SQLNullInt64KeyNullEmpty("bar", &sql.NullInt64{1, true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderSQLNullFloat64Empty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,1`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullFloat64NullEmpty(&sql.NullFloat64{0, true})
enc.SQLNullFloat64NullEmpty(&sql.NullFloat64{1, true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderSQLNullFloat64KeyNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":1`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":1`,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddSQLNullFloat64KeyNullEmpty("foo", &sql.NullFloat64{0, true})
enc.SQLNullFloat64KeyNullEmpty("bar", &sql.NullFloat64{1, true})
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_stream.go 0000664 0000000 0000000 00000012012 13653316651 0023127 0 ustar 00root root 0000000 0000000 package gojay
import (
"strconv"
"sync"
"time"
)
// MarshalerStream is the interface to implement
// to continuously encode of stream of data.
type MarshalerStream interface {
MarshalStream(enc *StreamEncoder)
}
// A StreamEncoder reads and encodes values to JSON from an input stream.
//
// It implements conext.Context and provide a channel to notify interruption.
type StreamEncoder struct {
mux *sync.RWMutex
*Encoder
nConsumer int
delimiter byte
deadline *time.Time
done chan struct{}
}
// EncodeStream spins up a defined number of non blocking consumers of the MarshalerStream m.
//
// m must implement MarshalerStream. Ideally m is a channel. See example for implementation.
//
// See the documentation for Marshal for details about the conversion of Go value to JSON.
func (s *StreamEncoder) EncodeStream(m MarshalerStream) {
// if a single consumer, just use this encoder
if s.nConsumer == 1 {
go consume(s, s, m)
return
}
// else use this Encoder only for first consumer
// and use new encoders for other consumers
// this is to avoid concurrent writing to same buffer
// resulting in a weird JSON
go consume(s, s, m)
for i := 1; i < s.nConsumer; i++ {
s.mux.RLock()
select {
case <-s.done:
default:
ss := Stream.borrowEncoder(s.w)
ss.mux.Lock()
ss.done = s.done
ss.buf = make([]byte, 0, 512)
ss.delimiter = s.delimiter
go consume(s, ss, m)
ss.mux.Unlock()
}
s.mux.RUnlock()
}
return
}
// LineDelimited sets the delimiter to a new line character.
//
// It will add a new line after each JSON marshaled by the MarshalerStream
func (s *StreamEncoder) LineDelimited() *StreamEncoder {
s.delimiter = '\n'
return s
}
// CommaDelimited sets the delimiter to a comma.
//
// It will add a new line after each JSON marshaled by the MarshalerStream
func (s *StreamEncoder) CommaDelimited() *StreamEncoder {
s.delimiter = ','
return s
}
// NConsumer sets the number of non blocking go routine to consume the stream.
func (s *StreamEncoder) NConsumer(n int) *StreamEncoder {
s.nConsumer = n
return s
}
// Release sends back a Decoder to the pool.
// If a decoder is used after calling Release
// a panic will be raised with an InvalidUsagePooledDecoderError error.
func (s *StreamEncoder) Release() {
s.isPooled = 1
streamEncPool.Put(s)
}
// Done returns a channel that's closed when work is done.
// It implements context.Context
func (s *StreamEncoder) Done() <-chan struct{} {
return s.done
}
// Err returns nil if Done is not yet closed.
// If Done is closed, Err returns a non-nil error explaining why.
// It implements context.Context
func (s *StreamEncoder) Err() error {
return s.err
}
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
func (s *StreamEncoder) Deadline() (time.Time, bool) {
if s.deadline != nil {
return *s.deadline, true
}
return time.Time{}, false
}
// SetDeadline sets the deadline
func (s *StreamEncoder) SetDeadline(t time.Time) {
s.deadline = &t
}
// Value implements context.Context
func (s *StreamEncoder) Value(key interface{}) interface{} {
return nil
}
// Cancel cancels the consumers of the stream, interrupting the stream encoding.
//
// After calling cancel, Done() will return a closed channel.
func (s *StreamEncoder) Cancel(err error) {
s.mux.Lock()
defer s.mux.Unlock()
select {
case <-s.done:
default:
s.err = err
close(s.done)
}
}
// AddObject adds an object to be encoded.
// value must implement MarshalerJSONObject.
func (s *StreamEncoder) AddObject(v MarshalerJSONObject) {
if v.IsNil() {
return
}
s.Encoder.writeByte('{')
v.MarshalJSONObject(s.Encoder)
s.Encoder.writeByte('}')
s.Encoder.writeByte(s.delimiter)
}
// AddString adds a string to be encoded.
func (s *StreamEncoder) AddString(v string) {
s.Encoder.writeByte('"')
s.Encoder.writeString(v)
s.Encoder.writeByte('"')
s.Encoder.writeByte(s.delimiter)
}
// AddArray adds an implementation of MarshalerJSONArray to be encoded.
func (s *StreamEncoder) AddArray(v MarshalerJSONArray) {
s.Encoder.writeByte('[')
v.MarshalJSONArray(s.Encoder)
s.Encoder.writeByte(']')
s.Encoder.writeByte(s.delimiter)
}
// AddInt adds an int to be encoded.
func (s *StreamEncoder) AddInt(value int) {
s.buf = strconv.AppendInt(s.buf, int64(value), 10)
s.Encoder.writeByte(s.delimiter)
}
// AddFloat64 adds a float64 to be encoded.
func (s *StreamEncoder) AddFloat64(value float64) {
s.buf = strconv.AppendFloat(s.buf, value, 'f', -1, 64)
s.Encoder.writeByte(s.delimiter)
}
// AddFloat adds a float64 to be encoded.
func (s *StreamEncoder) AddFloat(value float64) {
s.AddFloat64(value)
}
// Non exposed
func consume(init *StreamEncoder, s *StreamEncoder, m MarshalerStream) {
defer s.Release()
for {
select {
case <-init.Done():
return
default:
m.MarshalStream(s)
if s.Encoder.err != nil {
init.Cancel(s.Encoder.err)
return
}
i, err := s.Encoder.Write()
if err != nil || i == 0 {
init.Cancel(err)
return
}
}
}
}
golang-github-francoispqt-gojay-1.2.13/encode_stream_pool.go 0000664 0000000 0000000 00000002155 13653316651 0024167 0 ustar 00root root 0000000 0000000 package gojay
import (
"io"
"sync"
)
// NewEncoder returns a new StreamEncoder.
// It takes an io.Writer implementation to output data.
// It initiates the done channel returned by Done().
func (s stream) NewEncoder(w io.Writer) *StreamEncoder {
enc := BorrowEncoder(w)
return &StreamEncoder{Encoder: enc, nConsumer: 1, done: make(chan struct{}, 1), mux: &sync.RWMutex{}}
}
// BorrowEncoder borrows a StreamEncoder from the pool.
// It takes an io.Writer implementation to output data.
// It initiates the done channel returned by Done().
//
// If no StreamEncoder is available in the pool, it returns a fresh one
func (s stream) BorrowEncoder(w io.Writer) *StreamEncoder {
streamEnc := streamEncPool.Get().(*StreamEncoder)
streamEnc.w = w
streamEnc.Encoder.err = nil
streamEnc.done = make(chan struct{}, 1)
streamEnc.Encoder.buf = streamEnc.buf[:0]
streamEnc.nConsumer = 1
streamEnc.isPooled = 0
return streamEnc
}
func (s stream) borrowEncoder(w io.Writer) *StreamEncoder {
streamEnc := streamEncPool.Get().(*StreamEncoder)
streamEnc.isPooled = 0
streamEnc.w = w
streamEnc.Encoder.err = nil
return streamEnc
}
golang-github-francoispqt-gojay-1.2.13/encode_stream_test.go 0000664 0000000 0000000 00000022050 13653316651 0024171 0 ustar 00root root 0000000 0000000 package gojay
import (
"os"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type StreamChanObject chan *testObject
func (s StreamChanObject) MarshalStream(enc *StreamEncoder) {
select {
case <-enc.Done():
return
case o := <-s:
enc.AddObject(o)
}
}
type StreamChanSlice chan *TestEncodingArrStrings
func (s StreamChanSlice) MarshalStream(enc *StreamEncoder) {
select {
case <-enc.Done():
return
case o := <-s:
enc.AddArray(o)
}
}
type StreamChanString chan string
func (s StreamChanString) MarshalStream(enc *StreamEncoder) {
select {
case <-enc.Done():
return
case o := <-s:
enc.AddString(o)
}
}
type StreamChanInt chan int
func (s StreamChanInt) MarshalStream(enc *StreamEncoder) {
select {
case <-enc.Done():
return
case o := <-s:
enc.AddInt(o)
}
}
type StreamChanFloat chan float64
func (s StreamChanFloat) MarshalStream(enc *StreamEncoder) {
select {
case <-enc.Done():
return
case o := <-s:
enc.AddFloat(o)
}
}
type StreamChanError chan *testObject
func (s StreamChanError) MarshalStream(enc *StreamEncoder) {
select {
case <-enc.Done():
return
case <-s:
enc.AddInterface(struct{}{})
}
}
// TestWriter to assert result
type TestWriter struct {
nWrite *int
target int
enc *StreamEncoder
result [][]byte
mux *sync.RWMutex
}
func (w *TestWriter) Write(b []byte) (int, error) {
if len(b) > 0 {
w.mux.Lock()
w.result = append(w.result, b)
if len(w.result) == w.target {
w.enc.Cancel(nil)
}
w.mux.Unlock()
}
return len(b), nil
}
func feedStreamNil(s chan *testObject, target int) {
for i := 0; i < target; i++ {
s <- nil
}
}
func feedStream(s chan *testObject, target int) {
for i := 0; i < target; i++ {
s <- &testObject{}
}
}
func feedStreamSlices(s chan *TestEncodingArrStrings, target int) {
for i := 0; i < target; i++ {
s <- &TestEncodingArrStrings{"test", "test2"}
}
}
func feedStreamStrings(s chan string, target int) {
for i := 0; i < target; i++ {
s <- "hello"
}
}
func feedStreamInt(s chan int, target int) {
for i := 0; i < target; i++ {
s <- i
}
}
func feedStreamFloat(s chan float64, target int) {
for i := 0; i < target; i++ {
s <- float64(i)
}
}
func TestEncodeStream(t *testing.T) {
t.Run("single-consumer-object", func(t *testing.T) {
expectedStr :=
`{"testStr":"","testInt":0,"testInt64":0,"testInt32":0,"testInt16":0,"testInt8":0,"testUint64":0,"testUint32":0,"testUint16":0,"testUint8":0,"testFloat64":0,"testFloat32":0,"testBool":false}
`
// create our writer
w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
go enc.EncodeStream(s)
go feedStream(s, 100)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 100, "w.result should be 100")
for _, b := range w.result {
assert.Equal(t, expectedStr, string(b), "every byte buffer should be equal to expected string")
}
}
})
t.Run("single-consumer-slice", func(t *testing.T) {
expectedStr :=
`["test","test2"]
`
// create our writer
w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanSlice(make(chan *TestEncodingArrStrings))
go enc.EncodeStream(s)
go feedStreamSlices(s, 100)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 100, "w.result should be 100")
for _, b := range w.result {
assert.Equal(t, expectedStr, string(b), "every byte buffer should be equal to expected string")
}
}
})
t.Run("single-consumer-string", func(t *testing.T) {
expectedStr :=
`"hello"
`
// create our writer
w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanString(make(chan string))
go enc.EncodeStream(s)
go feedStreamStrings(s, 100)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 100, "w.result should be 100")
for _, b := range w.result {
assert.Equal(t, expectedStr, string(b), "every byte buffer should be equal to expected string")
}
}
})
t.Run("single-consumer-object-nil-value", func(t *testing.T) {
expectedStr := ``
// create our writer
w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
go enc.EncodeStream(s)
go feedStreamNil(s, 100)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Nil(t, enc.Err(), "enc.Err() should not be nil")
for _, b := range w.result {
assert.Equal(t, expectedStr, string(b), "every byte buffer should be equal to expected string")
}
}
})
t.Run("single-consumer-int", func(t *testing.T) {
// create our writer
w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanInt(make(chan int))
go enc.EncodeStream(s)
go feedStreamInt(s, 100)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 100, "w.result should be 100")
}
})
t.Run("single-consumer-float", func(t *testing.T) {
// create our writer
w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanFloat(make(chan float64))
go enc.EncodeStream(s)
go feedStreamFloat(s, 100)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 100, "w.result should be 100")
}
})
t.Run("single-consumer-marshal-error", func(t *testing.T) {
// create our writer
w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanError(make(chan *testObject))
go enc.EncodeStream(s)
go feedStream(s, 100)
select {
case <-enc.Done():
assert.NotNil(t, enc.Err(), "enc.Err() should not be nil")
}
})
t.Run("single-consumer-write-error", func(t *testing.T) {
// create our writer
w := TestWriterError("")
enc := Stream.NewEncoder(w).LineDelimited()
s := StreamChanObject(make(chan *testObject))
go enc.EncodeStream(s)
go feedStream(s, 100)
select {
case <-enc.Done():
assert.NotNil(t, enc.Err(), "enc.Err() should not be nil")
}
})
t.Run("multiple-consumer-object-comma-delimited", func(t *testing.T) {
expectedStr :=
`{"testStr":"","testInt":0,"testInt64":0,"testInt32":0,"testInt16":0,"testInt8":0,"testUint64":0,"testUint32":0,"testUint16":0,"testUint8":0,"testFloat64":0,"testFloat32":0,"testBool":false},`
// create our writer
w := &TestWriter{target: 5000, mux: &sync.RWMutex{}}
enc := Stream.BorrowEncoder(w).NConsumer(50).CommaDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
go enc.EncodeStream(s)
go feedStream(s, 5000)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 5000, "w.result should be 100")
for _, b := range w.result {
assert.Equal(t, expectedStr, string(b), "every byte buffer should be equal to expected string")
}
}
})
t.Run("multiple-consumer-object-line-delimited", func(t *testing.T) {
expectedStr :=
`{"testStr":"","testInt":0,"testInt64":0,"testInt32":0,"testInt16":0,"testInt8":0,"testUint64":0,"testUint32":0,"testUint16":0,"testUint8":0,"testFloat64":0,"testFloat32":0,"testBool":false}
`
// create our writer
w := &TestWriter{target: 5000, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).NConsumer(50).LineDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
go feedStream(s, 5000)
go enc.EncodeStream(s)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 5000, "w.result should be 100")
for _, b := range w.result {
assert.Equal(t, expectedStr, string(b), "every byte buffer should be equal to expected string")
}
}
})
t.Run("multiple-consumer-object-chan-closed", func(t *testing.T) {
// create our writer
w := &TestWriter{target: 5000, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).NConsumer(50).LineDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
close(enc.done)
go feedStream(s, 5000)
go enc.EncodeStream(s)
select {
case <-enc.Done():
assert.Nil(t, enc.Err(), "enc.Err() should be nil")
assert.Len(t, w.result, 0, "w.result should be 0")
}
})
t.Run("encoder-deadline", func(t *testing.T) {
enc := Stream.NewEncoder(os.Stdout)
now := time.Now()
enc.SetDeadline(now)
d, _ := enc.Deadline()
assert.Equal(t, now, d, "deadline should be the one just set")
})
t.Run("encoder-deadline-unset", func(t *testing.T) {
enc := Stream.NewEncoder(os.Stdout)
d, _ := enc.Deadline()
assert.Equal(t, time.Time{}, d, "deadline should be the one just set")
})
// just for coverage
t.Run("encoder-context-value", func(t *testing.T) {
enc := Stream.NewEncoder(os.Stdout)
assert.Nil(t, enc.Value(""), "enc.Value should be nil")
})
}
golang-github-francoispqt-gojay-1.2.13/encode_string.go 0000664 0000000 0000000 00000011172 13653316651 0023150 0 ustar 00root root 0000000 0000000 package gojay
// EncodeString encodes a string to
func (enc *Encoder) EncodeString(s string) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeString(s)
_, err := enc.Write()
if err != nil {
enc.err = err
return err
}
return nil
}
// encodeString encodes a string to
func (enc *Encoder) encodeString(v string) ([]byte, error) {
enc.writeByte('"')
enc.writeStringEscape(v)
enc.writeByte('"')
return enc.buf, nil
}
// AppendString appends a string to the buffer
func (enc *Encoder) AppendString(v string) {
enc.grow(len(v) + 2)
enc.writeByte('"')
enc.writeStringEscape(v)
enc.writeByte('"')
}
// AddString adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddString(v string) {
enc.String(v)
}
// AddStringOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddStringOmitEmpty(v string) {
enc.StringOmitEmpty(v)
}
// AddStringNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddStringNullEmpty(v string) {
enc.StringNullEmpty(v)
}
// AddStringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddStringKey(key, v string) {
enc.StringKey(key, v)
}
// AddStringKeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddStringKeyOmitEmpty(key, v string) {
enc.StringKeyOmitEmpty(key, v)
}
// AddStringKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) AddStringKeyNullEmpty(key, v string) {
enc.StringKeyNullEmpty(key, v)
}
// String adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) String(v string) {
enc.grow(len(v) + 4)
r := enc.getPreviousRune()
if r != '[' {
enc.writeTwoBytes(',', '"')
} else {
enc.writeByte('"')
}
enc.writeStringEscape(v)
enc.writeByte('"')
}
// StringOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) StringOmitEmpty(v string) {
if v == "" {
return
}
r := enc.getPreviousRune()
if r != '[' {
enc.writeTwoBytes(',', '"')
} else {
enc.writeByte('"')
}
enc.writeStringEscape(v)
enc.writeByte('"')
}
// StringNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) StringNullEmpty(v string) {
r := enc.getPreviousRune()
if v == "" {
if r != '[' {
enc.writeByte(',')
enc.writeBytes(nullBytes)
} else {
enc.writeBytes(nullBytes)
}
return
}
if r != '[' {
enc.writeTwoBytes(',', '"')
} else {
enc.writeByte('"')
}
enc.writeStringEscape(v)
enc.writeByte('"')
}
// StringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) StringKey(key, v string) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(len(key) + len(v) + 5)
r := enc.getPreviousRune()
if r != '{' {
enc.writeTwoBytes(',', '"')
} else {
enc.writeByte('"')
}
enc.writeStringEscape(key)
enc.writeBytes(objKeyStr)
enc.writeStringEscape(v)
enc.writeByte('"')
}
// StringKeyOmitEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) StringKeyOmitEmpty(key, v string) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
if v == "" {
return
}
enc.grow(len(key) + len(v) + 5)
r := enc.getPreviousRune()
if r != '{' {
enc.writeTwoBytes(',', '"')
} else {
enc.writeByte('"')
}
enc.writeStringEscape(key)
enc.writeBytes(objKeyStr)
enc.writeStringEscape(v)
enc.writeByte('"')
}
// StringKeyNullEmpty adds a string to be encoded or skips it if it is zero value.
// Must be used inside an object as it will encode a key
func (enc *Encoder) StringKeyNullEmpty(key, v string) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(len(key) + len(v) + 5)
r := enc.getPreviousRune()
if r != '{' {
enc.writeTwoBytes(',', '"')
} else {
enc.writeByte('"')
}
enc.writeStringEscape(key)
enc.writeBytes(objKey)
if v == "" {
enc.writeBytes(nullBytes)
return
}
enc.writeByte('"')
enc.writeStringEscape(v)
enc.writeByte('"')
}
golang-github-francoispqt-gojay-1.2.13/encode_string_test.go 0000664 0000000 0000000 00000015155 13653316651 0024214 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEncoderStringEncodeAPI(t *testing.T) {
t.Run("basic", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString("hello world")
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"hello world"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("utf8", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString("æ¼¢å—𩸽")
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"æ¼¢å—𩸽"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("utf8-multibyte", func(t *testing.T) {
str := "テュールスト マーティン ヤコブ ðŸ˜"
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString(str)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"テュールスト マーティン ヤコブ ðŸ˜"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("escaped-sequence1", func(t *testing.T) {
str := `テュールスト マ\ーテ
ィン ヤコブ ðŸ˜`
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString(str)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"テュールスト マ\\ーテ\nィン ヤコブ ðŸ˜"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("escaped-sequence2", func(t *testing.T) {
str := `テュールスト マ\ーテ
ィン ヤコブ 😠`
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString(str)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"テュールスト マ\\ーテ\nィン ヤコブ ðŸ˜\t"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("escaped-sequence3", func(t *testing.T) {
str := "hello \r world ð„ž"
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString(str)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"hello \r world ð„ž"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("escaped-sequence3", func(t *testing.T) {
str := "hello \b world ð„ž"
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString(str)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"hello \b world ð„ž"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("escaped-control-char", func(t *testing.T) {
str := "\u001b"
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString(str)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"\u001b"`,
builder.String(),
"Result of marshalling is different as the one expected")
})
t.Run("escaped-sequence3", func(t *testing.T) {
str := "hello \f world ð„ž"
builder := &strings.Builder{}
enc := NewEncoder(builder)
err := enc.EncodeString(str)
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
"\"hello \\f world ð„ž\"",
builder.String(),
"Result of marshalling is different as the one expected")
})
}
func TestEncoderStringEncodeAPIErrors(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
v := ""
enc := BorrowEncoder(nil)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
_ = enc.EncodeString(v)
assert.True(t, false, "should not be called as it should have panicked")
})
t.Run("write-error", func(t *testing.T) {
v := "test"
w := TestWriterError("")
enc := BorrowEncoder(w)
defer enc.Release()
err := enc.EncodeString(v)
assert.NotNil(t, err, "err should not be nil")
})
}
func TestEncoderStringMarshalAPI(t *testing.T) {
t.Run("basic", func(t *testing.T) {
r, err := Marshal("string")
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"string"`,
string(r),
"Result of marshalling is different as the one expected")
})
t.Run("utf8", func(t *testing.T) {
r, err := Marshal("æ¼¢å—")
assert.Nil(t, err, "Error should be nil")
assert.Equal(
t,
`"æ¼¢å—"`,
string(r),
"Result of marshalling is different as the one expected")
})
}
func TestEncoderStringNullEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `[null,"true"`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,"true"`,
},
{
name: "basic 2nd elem",
baseJSON: `["test"`,
expectedJSON: `["test",null,"true"`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.StringNullEmpty("")
enc.AddStringNullEmpty("true")
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderStringNullEmpty2(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "[",
expectedJSON: `["test"`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.StringNullEmpty("test")
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
func TestEncoderStringNullKeyEmpty(t *testing.T) {
var testCases = []struct {
name string
baseJSON string
expectedJSON string
}{
{
name: "basic 1st elem",
baseJSON: "{",
expectedJSON: `{"foo":null,"bar":"true"`,
},
{
name: "basic 2nd elem",
baseJSON: `{"test":"test"`,
expectedJSON: `{"test":"test","foo":null,"bar":"true"`,
},
}
for _, testCase := range testCases {
t.Run("true", func(t *testing.T) {
var b strings.Builder
var enc = NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.StringKeyNullEmpty("foo", "")
enc.AddStringKeyNullEmpty("bar", "true")
enc.Write()
assert.Equal(t, testCase.expectedJSON, b.String())
})
}
}
golang-github-francoispqt-gojay-1.2.13/encode_test.go 0000664 0000000 0000000 00000001673 13653316651 0022626 0 ustar 00root root 0000000 0000000 package gojay
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
type TestWriterError string
func (t TestWriterError) Write(b []byte) (int, error) {
return 0, errors.New("Test Error")
}
func TestAppendBytes(t *testing.T) {
b := []byte(``)
enc := NewEncoder(nil)
enc.buf = b
enc.AppendBytes([]byte(`true`))
assert.Equal(t, string(enc.buf), `true`, "string(enc.buf) should equal to true")
}
func TestAppendByte(t *testing.T) {
b := []byte(``)
enc := NewEncoder(nil)
enc.buf = b
enc.AppendByte(1)
assert.Equal(t, enc.buf[0], uint8(0x1), "b[0] should equal to 1")
}
func TestAppendString(t *testing.T) {
b := []byte(``)
enc := NewEncoder(nil)
enc.buf = b
enc.AppendString("true")
assert.Equal(t, string(enc.buf), `"true"`, "string(enc.buf) should equal to true")
}
func TestBuf(t *testing.T) {
b := []byte(`test`)
enc := NewEncoder(nil)
enc.buf = b
assert.Equal(t, b, enc.Buf(), "enc.Buf() should equal to b")
}
golang-github-francoispqt-gojay-1.2.13/encode_time.go 0000664 0000000 0000000 00000003565 13653316651 0022607 0 ustar 00root root 0000000 0000000 package gojay
import (
"time"
)
// EncodeTime encodes a *time.Time to JSON with the given format
func (enc *Encoder) EncodeTime(t *time.Time, format string) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeTime(t, format)
_, err := enc.Write()
if err != nil {
return err
}
return nil
}
// encodeInt encodes an int to JSON
func (enc *Encoder) encodeTime(t *time.Time, format string) ([]byte, error) {
enc.writeByte('"')
enc.buf = t.AppendFormat(enc.buf, format)
enc.writeByte('"')
return enc.buf, nil
}
// AddTimeKey adds an *time.Time to be encoded with the given format, must be used inside an object as it will encode a key
func (enc *Encoder) AddTimeKey(key string, t *time.Time, format string) {
enc.TimeKey(key, t, format)
}
// TimeKey adds an *time.Time to be encoded with the given format, must be used inside an object as it will encode a key
func (enc *Encoder) TimeKey(key string, t *time.Time, format string) {
if enc.hasKeys {
if !enc.keyExists(key) {
return
}
}
enc.grow(10 + len(key))
r := enc.getPreviousRune()
if r != '{' {
enc.writeTwoBytes(',', '"')
} else {
enc.writeByte('"')
}
enc.writeStringEscape(key)
enc.writeBytes(objKeyStr)
enc.buf = t.AppendFormat(enc.buf, format)
enc.writeByte('"')
}
// AddTime adds an *time.Time to be encoded with the given format, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddTime(t *time.Time, format string) {
enc.Time(t, format)
}
// Time adds an *time.Time to be encoded with the given format, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Time(t *time.Time, format string) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
enc.buf = t.AppendFormat(enc.buf, format)
enc.writeByte('"')
}
golang-github-francoispqt-gojay-1.2.13/encode_time_test.go 0000664 0000000 0000000 00000007051 13653316651 0023640 0 ustar 00root root 0000000 0000000 package gojay
import (
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestEncodeTime(t *testing.T) {
testCases := []struct {
name string
tt string
format string
expectedJSON string
err bool
}{
{
name: "basic",
tt: "2018-02-01",
format: "2006-01-02",
expectedJSON: `"2018-02-01"`,
err: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
b := strings.Builder{}
tt, err := time.Parse(testCase.format, testCase.tt)
assert.Nil(t, err)
enc := NewEncoder(&b)
err = enc.EncodeTime(&tt, testCase.format)
if !testCase.err {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedJSON, b.String())
}
})
}
t.Run("encode-time-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
}()
_ = enc.EncodeTime(&time.Time{}, "")
assert.True(t, false, "should not be called as encoder should have panicked")
})
t.Run("write-error", func(t *testing.T) {
w := TestWriterError("")
enc := BorrowEncoder(w)
defer enc.Release()
err := enc.EncodeTime(&time.Time{}, "")
assert.NotNil(t, err, "err should not be nil")
})
}
func TestAddTimeKey(t *testing.T) {
testCases := []struct {
name string
tt string
format string
expectedJSON string
baseJSON string
err bool
}{
{
name: "basic",
tt: "2018-02-01",
format: "2006-01-02",
baseJSON: "{",
expectedJSON: `{"test":"2018-02-01"`,
err: false,
},
{
name: "basic",
tt: "2018-02-01",
format: "2006-01-02",
baseJSON: `{""`,
expectedJSON: `{"","test":"2018-02-01"`,
err: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
b := strings.Builder{}
tt, err := time.Parse(testCase.format, testCase.tt)
assert.Nil(t, err)
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddTimeKey("test", &tt, testCase.format)
enc.Write()
if !testCase.err {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedJSON, b.String())
}
})
}
}
func TestAddTime(t *testing.T) {
testCases := []struct {
name string
tt string
format string
expectedJSON string
baseJSON string
err bool
}{
{
name: "basic",
tt: "2018-02-01",
format: "2006-01-02",
baseJSON: "[",
expectedJSON: `["2018-02-01"`,
err: false,
},
{
name: "basic",
tt: "2018-02-01",
format: "2006-01-02",
baseJSON: "[",
expectedJSON: `["2018-02-01"`,
err: false,
},
{
name: "basic",
tt: "2018-02-01",
format: "2006-01-02",
baseJSON: `[""`,
expectedJSON: `["","2018-02-01"`,
err: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
b := strings.Builder{}
tt, err := time.Parse(testCase.format, testCase.tt)
assert.Nil(t, err)
enc := NewEncoder(&b)
enc.writeString(testCase.baseJSON)
enc.AddTime(&tt, testCase.format)
enc.Write()
if !testCase.err {
assert.Nil(t, err)
assert.Equal(t, testCase.expectedJSON, b.String())
}
})
}
}
golang-github-francoispqt-gojay-1.2.13/errors.go 0000664 0000000 0000000 00000004377 13653316651 0021652 0 ustar 00root root 0000000 0000000 package gojay
import (
"errors"
"fmt"
)
const invalidJSONCharErrorMsg = "Invalid JSON, wrong char '%c' found at position %d"
// InvalidJSONError is a type representing an error returned when
// Decoding encounters invalid JSON.
type InvalidJSONError string
func (err InvalidJSONError) Error() string {
return string(err)
}
func (dec *Decoder) raiseInvalidJSONErr(pos int) error {
var c byte
if len(dec.data) > pos {
c = dec.data[pos]
}
dec.err = InvalidJSONError(
fmt.Sprintf(
invalidJSONCharErrorMsg,
c,
pos,
),
)
return dec.err
}
const invalidUnmarshalErrorMsg = "Cannot unmarshal JSON to type '%T'"
// InvalidUnmarshalError is a type representing an error returned when
// Decoding cannot unmarshal JSON to the receiver type for various reasons.
type InvalidUnmarshalError string
func (err InvalidUnmarshalError) Error() string {
return string(err)
}
func (dec *Decoder) makeInvalidUnmarshalErr(v interface{}) error {
return InvalidUnmarshalError(
fmt.Sprintf(
invalidUnmarshalErrorMsg,
v,
),
)
}
const invalidMarshalErrorMsg = "Invalid type %T provided to Marshal"
// InvalidMarshalError is a type representing an error returned when
// Encoding did not find the proper way to encode
type InvalidMarshalError string
func (err InvalidMarshalError) Error() string {
return string(err)
}
// NoReaderError is a type representing an error returned when
// decoding requires a reader and none was given
type NoReaderError string
func (err NoReaderError) Error() string {
return string(err)
}
// InvalidUsagePooledDecoderError is a type representing an error returned
// when decoding is called on a still pooled Decoder
type InvalidUsagePooledDecoderError string
func (err InvalidUsagePooledDecoderError) Error() string {
return string(err)
}
// InvalidUsagePooledEncoderError is a type representing an error returned
// when decoding is called on a still pooled Encoder
type InvalidUsagePooledEncoderError string
func (err InvalidUsagePooledEncoderError) Error() string {
return string(err)
}
// ErrUnmarshalPtrExpected is the error returned when unmarshal expects a pointer value,
// When using `dec.ObjectNull` or `dec.ArrayNull` for example.
var ErrUnmarshalPtrExpected = errors.New("Cannot unmarshal to given value, a pointer is expected")
golang-github-francoispqt-gojay-1.2.13/examples/ 0000775 0000000 0000000 00000000000 13653316651 0021612 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/encode-decode-map/ 0000775 0000000 0000000 00000000000 13653316651 0025043 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/encode-decode-map/main.go 0000664 0000000 0000000 00000003513 13653316651 0026320 0 ustar 00root root 0000000 0000000 package main
import (
"log"
"strings"
"github.com/francoispqt/gojay"
)
// define our custom map type implementing MarshalerJSONObject and UnmarshalerJSONObject
type myMap map[string]string
// Implementing Unmarshaler
func (m myMap) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
str := ""
err := dec.AddString(&str)
if err != nil {
return err
}
m[k] = str
return nil
}
// Her we put the number of keys
// If number of keys is unknown return 0, it will parse all keys
func (m myMap) NKeys() int {
return 0
}
// Implementing Marshaler
func (m myMap) MarshalJSONObject(enc *gojay.Encoder) {
for k, v := range m {
enc.AddStringKey(k, v)
}
}
func (m myMap) IsNil() bool {
return m == nil
}
// Using Marshal / Unmarshal API
func marshalAPI(m myMap) error {
b, err := gojay.Marshal(m)
if err != nil {
return err
}
log.Print(string(b))
nM := myMap(make(map[string]string))
err = gojay.Unmarshal(b, nM)
if err != nil {
return err
}
log.Print(nM)
return nil
}
// Using Encode / Decode API
func encodeAPI(m myMap) error {
// we use strings.Builder as it implements io.Writer
builder := &strings.Builder{}
enc := gojay.BorrowEncoder(builder)
defer enc.Release()
// encode
err := enc.EncodeObject(m)
if err != nil {
return err
}
log.Print(builder.String())
// make our new map which will receive the decoded JSON
nM := myMap(make(map[string]string))
// get our decoder with an io.Reader
dec := gojay.BorrowDecoder(strings.NewReader(builder.String()))
defer dec.Release()
// decode
err = dec.DecodeObject(nM)
if err != nil {
return err
}
log.Print(nM)
return nil
}
func main() {
// make our map to be encoded
m := myMap(map[string]string{
"test": "test",
"test2": "test2",
})
err := marshalAPI(m)
if err != nil {
log.Fatal(err)
}
err = encodeAPI(m)
if err != nil {
log.Fatal(err)
}
}
golang-github-francoispqt-gojay-1.2.13/examples/fuzz/ 0000775 0000000 0000000 00000000000 13653316651 0022610 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/fuzz/Makefile 0000664 0000000 0000000 00000000361 13653316651 0024250 0 ustar 00root root 0000000 0000000 .PHONY: gofuzzbuild
gofuzzbuild:
go-fuzz-build github.com/francoispqt/gojay/examples/fuzz
.PHONY: gofuzz
gofuzz:
go-fuzz -bin=fuzz-fuzz.zip -workdir=.
.PHONY: gofuzzclean
gofuzzclean:
rm -rf corpus crashers suppressions fuzz-fuzz.zip golang-github-francoispqt-gojay-1.2.13/examples/fuzz/main.go 0000664 0000000 0000000 00000001372 13653316651 0024066 0 ustar 00root root 0000000 0000000 package fuzz
import (
"github.com/francoispqt/gojay"
)
type user struct {
id int
created uint64
age float64
name string
email string
friend *user
}
// implement gojay.UnmarshalerJSONObject
func (u *user) UnmarshalJSONObject(dec *gojay.Decoder, key string) error {
switch key {
case "id":
return dec.Int(&u.id)
case "created":
return dec.Uint64(&u.created)
case "age":
return dec.Float(&u.age)
case "name":
return dec.String(&u.name)
case "email":
return dec.String(&u.email)
case "friend":
uu := &user{}
return dec.Object(uu)
}
return nil
}
func (u *user) NKeys() int {
return 3
}
func Fuzz(input []byte) int {
u := &user{}
err := gojay.UnmarshalJSONObject(input, u)
if err != nil {
return 0
}
return 1
}
golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/ 0000775 0000000 0000000 00000000000 13653316651 0024704 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/Makefile 0000664 0000000 0000000 00000000105 13653316651 0026340 0 ustar 00root root 0000000 0000000
.PHONY: bench
bench:
wrk -d 20s -s post.lua http://localhost:3000 golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/README.md 0000664 0000000 0000000 00000002520 13653316651 0026162 0 ustar 00root root 0000000 0000000 # HTTP BENCHMARKS
This package has two different implementation of a basic HTTP server in Go. It just takes a JSON body, unmarshals it and marshals it back to the response.
It required `wrk` benchmarking tool, which you can find here: https://github.com/wg/wrk
## How to run
### gojay
```bash
cd /path/to/package && go run gojay/main.go
```
Then run:
```bash
cd /path/to/package && make bench
```
### standard package (encoding/json)
```bash
cd /path/to/package && go run standard/main.go
```
Then run:
```bash
cd /path/to/package && make bench
```
## Results
Results presented here are ran on a MacBook Pro Mid 2015 2,2 GHz Intel Core i7 with 16G of RAM
**gojay results:**
```
Running 20s test @ http://localhost:3000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 298.77us 341.40us 10.52ms 94.13%
Req/Sec 18.88k 1.89k 21.40k 73.63%
755246 requests in 20.10s, 1.67GB read
Requests/sec: 37573.84
Transfer/sec: 84.85MB
```
**standard results:**
```
Running 20s test @ http://localhost:3000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 613.21us 557.50us 12.65ms 93.88%
Req/Sec 9.18k 423.20 10.10k 80.50%
365404 requests in 20.00s, 811.60MB read
Requests/sec: 18269.66
Transfer/sec: 40.58MB
``` golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/gojay/ 0000775 0000000 0000000 00000000000 13653316651 0026015 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/gojay/main.go 0000664 0000000 0000000 00000005666 13653316651 0027305 0 ustar 00root root 0000000 0000000 package main
import (
"log"
"net/http"
"github.com/francoispqt/gojay"
)
func main() {
log.Println("Listening on port 3000")
log.Fatal(http.ListenAndServe(":3000", http.HandlerFunc(handler)))
}
func handler(w http.ResponseWriter, r *http.Request) {
var body Body
dec := gojay.BorrowDecoder(r.Body)
defer dec.Release()
err := dec.Decode(&body)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
enc := gojay.BorrowEncoder(w)
defer enc.Release()
err = enc.Encode(&body)
if err != nil {
panic(err)
}
}
type Body struct {
Colors *colors `json:"colors"`
}
func (c *Body) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
switch k {
case "colors":
cols := make(colors, 0)
c.Colors = &cols
return dec.Array(c.Colors)
}
return nil
}
func (b *Body) NKeys() int {
return 1
}
func (b *Body) MarshalJSONObject(enc *gojay.Encoder) {
enc.ArrayKey("colors", b.Colors)
}
func (b *Body) IsNil() bool {
return b == nil
}
type colors []*Color
func (b *colors) UnmarshalJSONArray(dec *gojay.Decoder) error {
color := &Color{}
if err := dec.Object(color); err != nil {
return err
}
*b = append(*b, color)
return nil
}
func (b *colors) MarshalJSONArray(enc *gojay.Encoder) {
for _, color := range *b {
enc.Object(color)
}
}
func (b *colors) IsNil() bool {
return len(*b) == 0
}
type Color struct {
Color string `json:"color,omitempty"`
Category string `json:"category,omitempty"`
Type string `json:"type,omitempty"`
Code *Code `json:"code,omitempty"`
}
func (b *Color) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
switch k {
case "color":
return dec.String(&b.Color)
case "category":
return dec.String(&b.Category)
case "type":
return dec.String(&b.Type)
case "code":
b.Code = &Code{}
return dec.Object(b.Code)
}
return nil
}
func (b *Color) NKeys() int {
return 4
}
func (b *Color) MarshalJSONObject(enc *gojay.Encoder) {
enc.ObjectKey("code", b.Code)
enc.StringKey("color", b.Color)
enc.StringKey("category", b.Category)
enc.StringKey("type", b.Type)
}
func (b *Color) IsNil() bool {
return b == nil
}
type Code struct {
RGBA *ints `json:"rgba,omitempty"`
Hex string `json:"hex,omitempty"`
}
func (c *Code) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
switch k {
case "rgba":
rgba := make(ints, 0)
c.RGBA = &rgba
return dec.Array(&rgba)
case "hex":
return dec.String(&c.Hex)
}
return nil
}
func (b *Code) NKeys() int {
return 2
}
func (b *Code) MarshalJSONObject(enc *gojay.Encoder) {
enc.ArrayKey("rgba", b.RGBA)
enc.StringKey("hex", b.Hex)
}
func (b *Code) IsNil() bool {
return b == nil
}
type ints []int
func (v *ints) UnmarshalJSONArray(dec *gojay.Decoder) error {
var i int
if err := dec.Int(&i); err != nil {
return err
}
*v = append(*v, i)
return nil
}
func (v *ints) MarshalJSONArray(enc *gojay.Encoder) {
for _, i := range *v {
enc.Int(i)
}
}
func (v *ints) IsNil() bool {
return v == nil || len(*v) == 0
}
golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/post.lua 0000664 0000000 0000000 00000010403 13653316651 0026372 0 ustar 00root root 0000000 0000000 wrk.method = "POST"
wrk.body = [=[
{
"colors": [
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
},
{
"color": "red",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,0,0,1],
"hex": "#FF0"
}
},
{
"color": "blue",
"category": "hue",
"type": "primary",
"code": {
"rgba": [0,0,255,1],
"hex": "#00F"
}
},
{
"color": "yellow",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,0,1],
"hex": "#FF0"
}
},
{
"color": "green",
"category": "hue",
"type": "secondary",
"code": {
"rgba": [0,255,0,1],
"hex": "#0F0"
}
},
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
},
{
"color": "red",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,0,0,1],
"hex": "#FF0"
}
},
{
"color": "blue",
"category": "hue",
"type": "primary",
"code": {
"rgba": [0,0,255,1],
"hex": "#00F"
}
},
{
"color": "yellow",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,0,1],
"hex": "#FF0"
}
},
{
"color": "green",
"category": "hue",
"type": "secondary",
"code": {
"rgba": [0,255,0,1],
"hex": "#0F0"
}
},
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
},
{
"color": "red",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,0,0,1],
"hex": "#FF0"
}
},
{
"color": "blue",
"category": "hue",
"type": "primary",
"code": {
"rgba": [0,0,255,1],
"hex": "#00F"
}
},
{
"color": "yellow",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,0,1],
"hex": "#FF0"
}
},
{
"color": "green",
"category": "hue",
"type": "secondary",
"code": {
"rgba": [0,255,0,1],
"hex": "#0F0"
}
},
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
},
{
"color": "red",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,0,0,1],
"hex": "#FF0"
}
},
{
"color": "blue",
"category": "hue",
"type": "primary",
"code": {
"rgba": [0,0,255,1],
"hex": "#00F"
}
},
{
"color": "yellow",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,0,1],
"hex": "#FF0"
}
},
{
"color": "green",
"category": "hue",
"type": "secondary",
"code": {
"rgba": [0,255,0,1],
"hex": "#0F0"
}
}
]
}
]=]
wrk.headers["Content-Type"] = "application/json"
golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/standard/ 0000775 0000000 0000000 00000000000 13653316651 0026504 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/http-benchmarks/standard/main.go 0000664 0000000 0000000 00000001443 13653316651 0027761 0 ustar 00root root 0000000 0000000 package main
import (
"encoding/json"
"log"
"net/http"
)
func main() {
log.Println("Listening on port 3000")
log.Fatal(http.ListenAndServe(":3000", http.HandlerFunc(handler)))
}
func handler(w http.ResponseWriter, r *http.Request) {
var body Body
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(body)
if err != nil {
panic(err)
}
}
type Body struct {
Colors []Color `json:"colors"`
}
type Color struct {
Color string `json:"color,omitempty"`
Category string `json:"category,omitempty"`
Type string `json:"type,omitempty"`
Code Code `json:"code,omitempty"`
}
type Code struct {
RGBA []int `json:"rgba,omitempty"`
Hex string `json:"hex,omitempty"`
}
golang-github-francoispqt-gojay-1.2.13/examples/http-json/ 0000775 0000000 0000000 00000000000 13653316651 0023540 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/http-json/main.go 0000664 0000000 0000000 00000002326 13653316651 0025016 0 ustar 00root root 0000000 0000000 package main
import (
"net/http"
"github.com/francoispqt/gojay"
)
type message struct {
foo string
bar string
}
func (m *message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
switch k {
case "foo":
return dec.AddString(&m.foo)
case "bar":
return dec.AddString(&m.bar)
}
return nil
}
func (m *message) NKeys() int {
return 2
}
func (m *message) MarshalJSONObject(dec *gojay.Encoder) {
dec.AddStringKey("foo", m.foo)
dec.AddStringKey("bar", m.bar)
}
func (m *message) IsNil() bool {
return m == nil
}
func home(w http.ResponseWriter, r *http.Request) {
// read body using io.Reader
m := &message{}
dec := gojay.BorrowDecoder(r.Body)
defer dec.Release()
err := dec.DecodeObject(m)
if err != nil {
i, err := w.Write([]byte(err.Error()))
if err != nil || i == 0 {
panic(err)
}
return
}
// just transform response slightly
m.foo += "hey"
// return response using io.Writer
enc := gojay.BorrowEncoder(w)
defer enc.Release()
err = enc.Encode(m)
if err != nil {
i, err := w.Write([]byte(err.Error()))
if err != nil || i == 0 {
panic(err)
}
}
return
}
func main() {
http.HandleFunc("/", home)
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
golang-github-francoispqt-gojay-1.2.13/examples/websocket/ 0000775 0000000 0000000 00000000000 13653316651 0023600 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/websocket/client/ 0000775 0000000 0000000 00000000000 13653316651 0025056 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/websocket/client/client.go 0000664 0000000 0000000 00000000634 13653316651 0026666 0 ustar 00root root 0000000 0000000 package client
import (
"github.com/francoispqt/gojay/examples/websocket/comm"
"golang.org/x/net/websocket"
)
type client struct {
comm.SenderReceiver
id int
}
func NewClient(id int) *client {
c := new(client)
c.id = id
return c
}
func (c *client) Dial(url, origin string) error {
conn, err := websocket.Dial(url, "", origin)
if err != nil {
return err
}
c.Conn = conn
c.Init(10)
return nil
}
golang-github-francoispqt-gojay-1.2.13/examples/websocket/comm/ 0000775 0000000 0000000 00000000000 13653316651 0024533 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/websocket/comm/comm.go 0000664 0000000 0000000 00000004143 13653316651 0026017 0 ustar 00root root 0000000 0000000 package comm
import (
"errors"
"log"
"github.com/francoispqt/gojay"
"golang.org/x/net/websocket"
)
// A basic message for our WebSocket app
type Message struct {
Message string
UserName string
}
func (m *Message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
switch k {
case "message":
return dec.AddString(&m.Message)
case "userName":
return dec.AddString(&m.UserName)
}
return nil
}
func (m *Message) NKeys() int {
return 2
}
func (m *Message) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddStringKey("message", m.Message)
enc.AddStringKey("userName", m.UserName)
}
func (u *Message) IsNil() bool {
return u == nil
}
// Here are defined our communication types
type Sender chan gojay.MarshalerJSONObject
func (s Sender) MarshalStream(enc *gojay.StreamEncoder) {
select {
case <-enc.Done():
return
case m := <-s:
enc.AddObject(m)
}
}
type Receiver chan *Message
func (s Receiver) UnmarshalStream(dec *gojay.StreamDecoder) error {
m := &Message{}
if err := dec.AddObject(m); err != nil {
return err
}
s <- m
return nil
}
type SenderReceiver struct {
Send Sender
Receive Receiver
Dec *gojay.StreamDecoder
Enc *gojay.StreamEncoder
Conn *websocket.Conn
}
func (sc *SenderReceiver) SetReceiver() {
sc.Receive = Receiver(make(chan *Message))
sc.Dec = gojay.Stream.BorrowDecoder(sc.Conn)
go sc.Dec.DecodeStream(sc.Receive)
}
func (sc *SenderReceiver) SetSender(nCons int) {
sc.Send = Sender(make(chan gojay.MarshalerJSONObject))
sc.Enc = gojay.Stream.BorrowEncoder(sc.Conn).NConsumer(nCons).LineDelimited()
go sc.Enc.EncodeStream(sc.Send)
}
func (sc *SenderReceiver) SendMessage(m gojay.MarshalerJSONObject) error {
select {
case <-sc.Enc.Done():
return errors.New("sender closed")
case sc.Send <- m:
log.Print("message sent by client: ", m)
return nil
}
}
func (c *SenderReceiver) OnMessage(f func(*Message)) error {
for {
select {
case <-c.Dec.Done():
return errors.New("receiver closed")
case m := <-c.Receive:
f(m)
}
}
}
func (sc *SenderReceiver) Init(sender int) *SenderReceiver {
sc.SetSender(sender)
sc.SetReceiver()
return sc
}
golang-github-francoispqt-gojay-1.2.13/examples/websocket/main.go 0000664 0000000 0000000 00000004305 13653316651 0025055 0 ustar 00root root 0000000 0000000 // package main simulates a conversation between
// a given set of websocket clients and a server.
//
// It spins up a web socket server.
// On a client's connection it creates a SenderReceiver which handles JSON Stream
// encoding and decoding using gojay's streaming API to abstract JSON communication
// between server and client, only having to handle go values.
//
// To simulate a conversation:
// - the server sends a welcome message to the client
// - when the client receives the message, it sends a message back to the server
// - when the server receives the ack message, it will send a message randomly to a client
// - when the client receives the message, it sends a message back to the server... and so on.
package main
import (
"log"
"strconv"
"github.com/francoispqt/gojay/examples/websocket/client"
"github.com/francoispqt/gojay/examples/websocket/comm"
"github.com/francoispqt/gojay/examples/websocket/server"
)
func createServer(done chan error) {
// create our server, with a done signal
s := server.NewServer()
// set our connection handler
s.OnConnection(func(c *server.Client) {
// send welcome message to initiate the conversation
c.SendMessage(&comm.Message{
UserName: "server",
Message: "Welcome !",
})
// start handling messages
c.OnMessage(func(m *comm.Message) {
log.Print("message received from client: ", m)
s.BroadCastRandom(c, m)
})
})
go s.Listen(":8070", done)
}
func createClient(url, origin string, i int) {
// create our client
c := client.NewClient(i)
// Dial connection to the WS server
err := c.Dial(url, origin)
if err != nil {
panic(err)
}
str := strconv.Itoa(i)
// Init client's sender and receiver
// Set the OnMessage handler
c.OnMessage(func(m *comm.Message) {
log.Print("client "+str+" received from "+m.UserName+" message: ", m)
c.SendMessage(&comm.Message{
UserName: str,
Message: "Responding to: " + m.UserName + " | old message: " + m.Message,
})
})
}
// Our main function
func main() {
done := make(chan error)
createServer(done)
// add our clients connection
for i := 0; i < 100; i++ {
i := i
go createClient("ws://localhost:8070/ws", "http://localhost/", i)
}
// handle server's termination
log.Fatal(<-done)
}
golang-github-francoispqt-gojay-1.2.13/examples/websocket/server/ 0000775 0000000 0000000 00000000000 13653316651 0025106 5 ustar 00root root 0000000 0000000 golang-github-francoispqt-gojay-1.2.13/examples/websocket/server/server.go 0000664 0000000 0000000 00000002722 13653316651 0026746 0 ustar 00root root 0000000 0000000 package server
import (
"log"
"math/rand"
"net/http"
"sync"
"time"
"github.com/francoispqt/gojay/examples/websocket/comm"
"golang.org/x/net/websocket"
)
type server struct {
clients []*Client
mux *sync.RWMutex
handle func(c *Client)
}
type Client struct {
comm.SenderReceiver
server *server
}
func NewClient(s *server, conn *websocket.Conn) *Client {
sC := new(Client)
sC.Conn = conn
sC.server = s
return sC
}
func NewServer() *server {
s := new(server)
s.mux = new(sync.RWMutex)
s.clients = make([]*Client, 0, 100)
return s
}
func (c *Client) Close() {
c.Conn.Close()
}
func (s *server) Handle(conn *websocket.Conn) {
defer func() {
err := conn.Close()
if err != nil {
log.Fatal(err)
}
}()
c := NewClient(s, conn)
// add our server client to the list of clients
s.mux.Lock()
s.clients = append(s.clients, c)
s.mux.Unlock()
// init Client's sender and receiver
c.Init(10)
s.handle(c)
// block until reader is done
<-c.Dec.Done()
}
func (s *server) Listen(port string, done chan error) {
http.Handle("/ws", websocket.Handler(s.Handle))
done <- http.ListenAndServe(port, nil)
}
func (s *server) OnConnection(h func(c *Client)) {
s.handle = h
}
func random(min, max int) int {
rand.Seed(time.Now().Unix())
return rand.Intn(max-min) + min
}
func (s *server) BroadCastRandom(sC *Client, m *comm.Message) {
m.Message = "Random message"
s.mux.RLock()
r := random(0, len(s.clients))
s.clients[r].SendMessage(m)
s.mux.RUnlock()
}
golang-github-francoispqt-gojay-1.2.13/go.mod 0000664 0000000 0000000 00000001702 13653316651 0021102 0 ustar 00root root 0000000 0000000 module github.com/francoispqt/gojay
go 1.12
require (
cloud.google.com/go v0.37.0 // indirect
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23
github.com/go-errors/errors v1.0.1
github.com/golang/protobuf v1.3.1 // indirect
github.com/json-iterator/go v1.1.6
github.com/lunixbochs/vtclean v1.0.0 // indirect
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pkg/errors v0.8.1 // indirect
github.com/stretchr/testify v1.2.2
github.com/viant/assertly v0.4.8
github.com/viant/toolbox v0.24.0
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a // indirect
golang.org/x/net v0.0.0-20190313220215-9f648a60d977
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 // indirect
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
)
golang-github-francoispqt-gojay-1.2.13/go.sum 0000664 0000000 0000000 00000044571 13653316651 0021142 0 ustar 00root root 0000000 0000000 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0 h1:69FNAINiZfsEuwH3fKq8QrAAnHz+2m4XL4kVYi5BX0Q=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/viant/assertly v0.4.8 h1:5x1GzBaRteIwTr5RAGFVG14uNeRFxVNbXPWrK2qAgpc=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0 h1:6TteTDQ68CjgcCe8wH3D3ZhUQQOJXMTbj/D9rkk2a1k=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977 h1:actzWV6iWn3GLqN8dZjzsB+CLt+gaV2+wsxroxiQI8I=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f h1:yCrMx/EeIue0+Qca57bWZS7VX6ymEoypmhWyPhz0NHM=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
golang-github-francoispqt-gojay-1.2.13/gojay.go 0000664 0000000 0000000 00000001046 13653316651 0021435 0 ustar 00root root 0000000 0000000 // Package gojay implements encoding and decoding of JSON as defined in RFC 7159.
// The mapping between JSON and Go values is described
// in the documentation for the Marshal and Unmarshal functions.
//
// It aims at performance and usability by relying on simple interfaces
// to decode and encode structures, slices, arrays and even channels.
//
// On top of the simple interfaces to implement, gojay provides lots of helpers to decode and encode
// multiple of different types natively such as bit.Int, sql.NullString or time.Time
package gojay
golang-github-francoispqt-gojay-1.2.13/gojay.png 0000664 0000000 0000000 00000126203 13653316651 0021617 0 ustar 00root root 0000000 0000000 ‰PNG
IHDR ô & ¥Èx3 pHYs
×
×B(›x tIMEâ-4‡wsž IDATxÚìwxÕúÇ¿ïÙdg6¤PÔkv…)6»‚—k»z\ ^I°bаA@ìzïµ]»¨T) vþ”’²3›ìyì¬c€ÔÝMò~ž‡‡™ÙÝ™“Ó¾ç=sÎû‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ $YÐ2ËÕçóÂÌÞ`0˜ ®Úç•§,|¢”ò———[{¹ßÉRAt¡‰ñz½] ¢î Žp _£U¢{,˺[rZA]h'¢á þ
àð&~\±mÛ%×ADÐ…Æòc‰h
€þÕ?cæmDô9€/™ù¥Ô/ZëÿSJíªþ]u[ ¤”Jàaæ6Ììf™ß kÓ+**ÖI ‚ B1M3Ã0Ë0ÿóz½+ÃåóùÀùÏ0Œ%®g}…FœÆA„V‰a
úöU¯×{lc‹x5AË=x0cŠ”„ ‚ ÔŸdÃ0¶º„5·)…¼º {½Þç¹AÓ4ûJq‚ ÄJ² YXç×ø‹sºÈ¶í±NÂ&