1package jsoniter 2 3import ( 4 "encoding/json" 5 "errors" 6 "io" 7 "reflect" 8 "sync/atomic" 9 "unsafe" 10) 11 12// Config customize how the API should behave. 13// The API is created from Config by Froze. 14type Config struct { 15 IndentionStep int 16 MarshalFloatWith6Digits bool 17 EscapeHTML bool 18 SortMapKeys bool 19 UseNumber bool 20 TagKey string 21} 22 23type frozenConfig struct { 24 configBeforeFrozen Config 25 sortMapKeys bool 26 indentionStep int 27 decoderCache unsafe.Pointer 28 encoderCache unsafe.Pointer 29 extensions []Extension 30 streamPool chan *Stream 31 iteratorPool chan *Iterator 32} 33 34// API the public interface of this package. 35// Primary Marshal and Unmarshal. 36type API interface { 37 IteratorPool 38 StreamPool 39 MarshalToString(v interface{}) (string, error) 40 Marshal(v interface{}) ([]byte, error) 41 MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) 42 UnmarshalFromString(str string, v interface{}) error 43 Unmarshal(data []byte, v interface{}) error 44 Get(data []byte, path ...interface{}) Any 45 NewEncoder(writer io.Writer) *Encoder 46 NewDecoder(reader io.Reader) *Decoder 47} 48 49// ConfigDefault the default API 50var ConfigDefault = Config{ 51 EscapeHTML: true, 52}.Froze() 53 54// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior 55var ConfigCompatibleWithStandardLibrary = Config{ 56 EscapeHTML: true, 57 SortMapKeys: true, 58}.Froze() 59 60// ConfigFastest marshals float with only 6 digits precision 61var ConfigFastest = Config{ 62 EscapeHTML: false, 63 MarshalFloatWith6Digits: true, 64}.Froze() 65 66// Froze forge API from config 67func (cfg Config) Froze() API { 68 // TODO: cache frozen config 69 frozenConfig := &frozenConfig{ 70 sortMapKeys: cfg.SortMapKeys, 71 indentionStep: cfg.IndentionStep, 72 streamPool: make(chan *Stream, 16), 73 iteratorPool: make(chan *Iterator, 16), 74 } 75 atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]ValDecoder{})) 76 atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]ValEncoder{})) 77 if cfg.MarshalFloatWith6Digits { 78 frozenConfig.marshalFloatWith6Digits() 79 } 80 if cfg.EscapeHTML { 81 frozenConfig.escapeHTML() 82 } 83 if cfg.UseNumber { 84 frozenConfig.useNumber() 85 } 86 frozenConfig.configBeforeFrozen = cfg 87 return frozenConfig 88} 89 90func (cfg *frozenConfig) useNumber() { 91 cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { 92 if iter.WhatIsNext() == NumberValue { 93 *((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) 94 } else { 95 *((*interface{})(ptr)) = iter.Read() 96 } 97 }}) 98} 99func (cfg *frozenConfig) getTagKey() string { 100 tagKey := cfg.configBeforeFrozen.TagKey 101 if tagKey == "" { 102 return "json" 103 } 104 return tagKey 105} 106 107func (cfg *frozenConfig) registerExtension(extension Extension) { 108 cfg.extensions = append(cfg.extensions, extension) 109} 110 111type lossyFloat32Encoder struct { 112} 113 114func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { 115 stream.WriteFloat32Lossy(*((*float32)(ptr))) 116} 117 118func (encoder *lossyFloat32Encoder) EncodeInterface(val interface{}, stream *Stream) { 119 WriteToStream(val, stream, encoder) 120} 121 122func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool { 123 return *((*float32)(ptr)) == 0 124} 125 126type lossyFloat64Encoder struct { 127} 128 129func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { 130 stream.WriteFloat64Lossy(*((*float64)(ptr))) 131} 132 133func (encoder *lossyFloat64Encoder) EncodeInterface(val interface{}, stream *Stream) { 134 WriteToStream(val, stream, encoder) 135} 136 137func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool { 138 return *((*float64)(ptr)) == 0 139} 140 141// EnableLossyFloatMarshalling keeps 10**(-6) precision 142// for float variables for better performance. 143func (cfg *frozenConfig) marshalFloatWith6Digits() { 144 // for better performance 145 cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &lossyFloat32Encoder{}) 146 cfg.addEncoderToCache(reflect.TypeOf((*float64)(nil)).Elem(), &lossyFloat64Encoder{}) 147} 148 149type htmlEscapedStringEncoder struct { 150} 151 152func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 153 str := *((*string)(ptr)) 154 stream.WriteStringWithHTMLEscaped(str) 155} 156 157func (encoder *htmlEscapedStringEncoder) EncodeInterface(val interface{}, stream *Stream) { 158 WriteToStream(val, stream, encoder) 159} 160 161func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { 162 return *((*string)(ptr)) == "" 163} 164 165func (cfg *frozenConfig) escapeHTML() { 166 cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{}) 167} 168 169func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder ValDecoder) { 170 done := false 171 for !done { 172 ptr := atomic.LoadPointer(&cfg.decoderCache) 173 cache := *(*map[reflect.Type]ValDecoder)(ptr) 174 copied := map[reflect.Type]ValDecoder{} 175 for k, v := range cache { 176 copied[k] = v 177 } 178 copied[cacheKey] = decoder 179 done = atomic.CompareAndSwapPointer(&cfg.decoderCache, ptr, unsafe.Pointer(&copied)) 180 } 181} 182 183func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder ValEncoder) { 184 done := false 185 for !done { 186 ptr := atomic.LoadPointer(&cfg.encoderCache) 187 cache := *(*map[reflect.Type]ValEncoder)(ptr) 188 copied := map[reflect.Type]ValEncoder{} 189 for k, v := range cache { 190 copied[k] = v 191 } 192 copied[cacheKey] = encoder 193 done = atomic.CompareAndSwapPointer(&cfg.encoderCache, ptr, unsafe.Pointer(&copied)) 194 } 195} 196 197func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) ValDecoder { 198 ptr := atomic.LoadPointer(&cfg.decoderCache) 199 cache := *(*map[reflect.Type]ValDecoder)(ptr) 200 return cache[cacheKey] 201} 202 203func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder { 204 ptr := atomic.LoadPointer(&cfg.encoderCache) 205 cache := *(*map[reflect.Type]ValEncoder)(ptr) 206 return cache[cacheKey] 207} 208 209func (cfg *frozenConfig) cleanDecoders() { 210 typeDecoders = map[string]ValDecoder{} 211 fieldDecoders = map[string]ValDecoder{} 212 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) 213} 214 215func (cfg *frozenConfig) cleanEncoders() { 216 typeEncoders = map[string]ValEncoder{} 217 fieldEncoders = map[string]ValEncoder{} 218 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) 219} 220 221func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { 222 stream := cfg.BorrowStream(nil) 223 defer cfg.ReturnStream(stream) 224 stream.WriteVal(v) 225 if stream.Error != nil { 226 return "", stream.Error 227 } 228 return string(stream.Buffer()), nil 229} 230 231func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { 232 stream := cfg.BorrowStream(nil) 233 defer cfg.ReturnStream(stream) 234 stream.WriteVal(v) 235 if stream.Error != nil { 236 return nil, stream.Error 237 } 238 result := stream.Buffer() 239 copied := make([]byte, len(result)) 240 copy(copied, result) 241 return copied, nil 242} 243 244func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { 245 if prefix != "" { 246 panic("prefix is not supported") 247 } 248 for _, r := range indent { 249 if r != ' ' { 250 panic("indent can only be space") 251 } 252 } 253 newCfg := cfg.configBeforeFrozen 254 newCfg.IndentionStep = len(indent) 255 return newCfg.Froze().Marshal(v) 256} 257 258func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { 259 data := []byte(str) 260 data = data[:lastNotSpacePos(data)] 261 iter := cfg.BorrowIterator(data) 262 defer cfg.ReturnIterator(iter) 263 iter.ReadVal(v) 264 if iter.head == iter.tail { 265 iter.loadMore() 266 } 267 if iter.Error == io.EOF { 268 return nil 269 } 270 if iter.Error == nil { 271 iter.ReportError("UnmarshalFromString", "there are bytes left after unmarshal") 272 } 273 return iter.Error 274} 275 276func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any { 277 iter := cfg.BorrowIterator(data) 278 defer cfg.ReturnIterator(iter) 279 return locatePath(iter, path) 280} 281 282func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error { 283 data = data[:lastNotSpacePos(data)] 284 iter := cfg.BorrowIterator(data) 285 defer cfg.ReturnIterator(iter) 286 typ := reflect.TypeOf(v) 287 if typ.Kind() != reflect.Ptr { 288 // return non-pointer error 289 return errors.New("the second param must be ptr type") 290 } 291 iter.ReadVal(v) 292 if iter.head == iter.tail { 293 iter.loadMore() 294 } 295 if iter.Error == io.EOF { 296 return nil 297 } 298 if iter.Error == nil { 299 iter.ReportError("Unmarshal", "there are bytes left after unmarshal") 300 } 301 return iter.Error 302} 303 304func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder { 305 stream := NewStream(cfg, writer, 512) 306 return &Encoder{stream} 307} 308 309func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { 310 iter := Parse(cfg, reader, 512) 311 return &Decoder{iter} 312} 313