github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/README.md (about) 1 [![Go Report Card](https://goreportcard.com/badge/github.com/zerosnake0/jzon)](https://goreportcard.com/report/github.com/zerosnake0/jzon) 2 [![PkgGoDev](https://pkg.go.dev/badge/github.com/zerosnake0/jzon)](https://pkg.go.dev/github.com/zerosnake0/jzon) 3 [![Github Workflow](https://github.com/zerosnake0/jzon/workflows/Test/badge.svg)](https://github.com/zerosnake0/jzon/actions?query=workflow%3ATest) 4 [![Build Status](https://travis-ci.org/zerosnake0/jzon.svg?branch=master)](https://travis-ci.org/zerosnake0/jzon) 5 [![codecov](https://codecov.io/gh/zerosnake0/jzon/branch/master/graph/badge.svg)](https://codecov.io/gh/zerosnake0/jzon) 6 [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) 7 8 # jzon 9 10 A high performance json library for Golang 11 12 ## Why another jsoniter? 13 14 The code I write here is very similar to [github.com/json-iterator/go](https://github.com/json-iterator/go), 15 so you may ask why reinvent the wheel. 16 17 For sure that I benefit a lot from the `jsoniter` library, but i found some inconvenience for me to use it 18 in some condition, for example: 19 20 - the iterator methods ReadString accepts null, there is no method which accepts exactly string. 21 I have to do some extra check before calling. 22 - some behavior is not compatible with the standard library. 23 - I want a chained streamer 24 25 On the other hand, I also want to learn how the `jsoniter` works, so there is this repo. 26 27 ## What's different from jsoniter? 28 29 Here are some of the differences: 30 31 - the iterator methods accept the exact type, for example ReadString accepts only string, not null 32 - the behavior is almost the same as the standard library (when an error returns, the behavior may differ 33 from the standard library) 34 - the error of the iterator is returned instead of being saved inside iterator 35 - the decoder/encoder interface has additional options, like struct tag options 36 37 Some features of `jsoniter` are not implemented, and may be not implemented in the future neither. 38 I choose only the ones I need to implement. 39 40 ## Compatibility with standard library 41 42 I tried implemented a version which is completely compatible with the standard library: 43 44 https://github.com/zerosnake0/jzon/tree/reflect 45 46 The benchmark shows that it's much faster than the standard library. 47 However it is still much slower than the current version, 48 which cannot be exactly the same as standard library (at least in my POV). 49 50 The major incompatibility is about the two following interfaces: 51 - `json.Marshaler` 52 - `encoding.TextMarshaler` 53 54 The method on pointer receiver may be called with an unaddressable value, 55 for example: 56 57 ```go 58 type field struct {} 59 60 func (*field) MarshalJSON() ([]byte, error) 61 62 type st struct { 63 F field 64 } 65 66 json.Marshal(st{}) // will not call field.MarshalJSON 67 jzon.Marshal(st{}) // will call field.MarshalJSON 68 ``` 69 70 So the user should be care when marshaling a value when method on 71 pointer receiver is involved 72 73 You can check the tests for more detailed info about the difference 74 75 ## How to use 76 77 ### Standard library like 78 79 ```go 80 import "github.com/zerosnake0/jzon" 81 82 // Unmarshal 83 err := jzon.Unmarshal(b, &data) 84 85 // Marshal 86 b, err := jzon.Marshal(&data) 87 88 // Decoder 89 dec := jzon.NewDecoder(reader) 90 defer dec.Release() 91 err := dec.Decode(&data) 92 93 // Encoder 94 enc := jzon.NewEncoder(writer) 95 defer enc.Release() 96 err := enc.Encode(&data) 97 ``` 98 99 ### Iterator 100 101 ```go 102 iter := jzon.NewIterator() 103 defer iter.Release() 104 iter.Reset(b) 105 jzon.ReadVal(&data) 106 ``` 107 108 ### Streamer 109 110 ```go 111 var w io.Writer 112 113 streamer := jzon.NewStreamer() 114 defer streamer.Release() 115 streamer.Reset(w) 116 streamer.Value(&data) 117 streamer.Flush() 118 ``` 119 120 ### Custom Decoder 121 122 see `decoder_test.go` 123 124 ```go 125 type testIntDecoder struct{} 126 127 func (*testIntDecoder) Decode(ptr unsafe.Pointer, it *Iterator, opts *DecOpts) error { 128 ... 129 } 130 131 dec := NewDecoderConfig(&DecoderOption{ 132 ValDecoders: map[reflect.Type]ValDecoder{ 133 reflect.TypeOf(int(0)): (*testIntDecoder)(nil), 134 }, 135 CaseSensitive: true, 136 }) 137 138 // standard library like 139 err := dec.Unmarshal(b, &data) 140 141 // iterator 142 iter := dec.NewIterator() 143 defer iter.Release() 144 ``` 145 146 ### Custom Encoder 147 148 see `encoder_test.go` 149 150 ```go 151 type testIntEncoder struct{} 152 153 func (*testIntEncoder) IsEmpty(ptr unsafe.Pointer) bool { 154 ... 155 } 156 157 func (*testIntEncoder) Encode(ptr unsafe.Pointer, s *Streamer, opts *EncOpts) { 158 ... 159 } 160 161 enc := NewEncoderConfig(&EncoderOption{ 162 ValEncoders: map[reflect.Type]ValEncoder{ 163 reflect.TypeOf(int(0)): (*testIntEncoder)(nil), 164 }, 165 }) 166 167 // standard library like 168 b, err := enc.Marshal(&data) 169 170 // streamer 171 streamer := enc.NewStreamer() 172 defer streamer.Release() 173 ```