From f0487718f647b7ec272607cc5cedfbf3717d63eb Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Sun, 9 Jul 2017 16:09:23 +0800 Subject: [PATCH] document public symbols --- extra/fuzzy_decoder.go | 16 +++---- feature_adapter.go | 17 ++------ feature_config.go | 35 +++++++++------ feature_iter.go | 52 ++++++++++++---------- feature_iter_array.go | 2 + feature_iter_float.go | 14 +++--- feature_iter_int.go | 72 ++++++++++++++++--------------- feature_iter_object.go | 5 +++ feature_iter_skip.go | 7 +-- feature_iter_string.go | 3 ++ feature_pool.go | 12 ++++++ feature_reflect.go | 22 ++++------ feature_reflect_extension.go | 5 +++ feature_reflect_struct_decoder.go | 47 ++++++++++---------- feature_stream.go | 12 ++++-- jsoniter.go | 18 ++++++++ jsoniter_1dot8_only_test.go | 2 +- jsoniter_any_string_test.go | 38 ++++++++-------- jsoniter_customize_test.go | 14 +++--- jsoniter_interface_test.go | 4 +- jsoniter_io_test.go | 2 +- jsoniter_string_test.go | 4 +- 22 files changed, 227 insertions(+), 176 deletions(-) create mode 100644 jsoniter.go diff --git a/extra/fuzzy_decoder.go b/extra/fuzzy_decoder.go index 505a6a7..9c57e58 100644 --- a/extra/fuzzy_decoder.go +++ b/extra/fuzzy_decoder.go @@ -160,8 +160,8 @@ type tolerateEmptyArrayDecoder struct { func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { if iter.WhatIsNext() == jsoniter.Array { iter.Skip() - newIter := iter.Config().BorrowIterator([]byte("{}")) - defer iter.Config().ReturnIterator(newIter) + newIter := iter.Pool().BorrowIterator([]byte("{}")) + defer iter.Pool().ReturnIterator(newIter) decoder.valDecoder.Decode(ptr, newIter) } else { decoder.valDecoder.Decode(ptr, iter) @@ -202,8 +202,8 @@ func (decoder *fuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It default: iter.ReportError("fuzzyIntegerDecoder", "not number or string") } - newIter := iter.Config().BorrowIterator([]byte(str)) - defer iter.Config().ReturnIterator(newIter) + newIter := iter.Pool().BorrowIterator([]byte(str)) + defer iter.Pool().ReturnIterator(newIter) isFloat := strings.IndexByte(str, '.') != -1 decoder.fun(isFloat, ptr, newIter) if newIter.Error != nil { @@ -222,8 +222,8 @@ func (decoder *fuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It *((*float32)(ptr)) = iter.ReadFloat32() case jsoniter.String: str = iter.ReadString() - newIter := iter.Config().BorrowIterator([]byte(str)) - defer iter.Config().ReturnIterator(newIter) + newIter := iter.Pool().BorrowIterator([]byte(str)) + defer iter.Pool().ReturnIterator(newIter) *((*float32)(ptr)) = newIter.ReadFloat32() if newIter.Error != nil { iter.Error = newIter.Error @@ -244,8 +244,8 @@ func (decoder *fuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It *((*float64)(ptr)) = iter.ReadFloat64() case jsoniter.String: str = iter.ReadString() - newIter := iter.Config().BorrowIterator([]byte(str)) - defer iter.Config().ReturnIterator(newIter) + newIter := iter.Pool().BorrowIterator([]byte(str)) + defer iter.Pool().ReturnIterator(newIter) *((*float64)(ptr)) = newIter.ReadFloat64() if newIter.Error != nil { iter.Error = newIter.Error diff --git a/feature_adapter.go b/feature_adapter.go index 5d33788..6100b69 100644 --- a/feature_adapter.go +++ b/feature_adapter.go @@ -1,14 +1,3 @@ -// Package jsoniter implements encoding and decoding of JSON as defined in -// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json. -// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter -// and variable type declarations (if any). -// jsoniter interfaces gives 100% compatibility with code using standard lib. -// -// "JSON and Go" -// (https://golang.org/doc/articles/json_and_go.html) -// gives a description of how Marshal/Unmarshal operate -// between arbitrary or predefined json objects and bytes, -// and it applies to jsoniter.Marshal/Unmarshal as well. package jsoniter import ( @@ -96,7 +85,7 @@ func (adapter *Decoder) Buffered() io.Reader { func (decoder *Decoder) UseNumber() { origCfg := decoder.iter.cfg.configBeforeFrozen origCfg.UseNumber = true - decoder.iter.cfg = origCfg.Froze() + decoder.iter.cfg = origCfg.Froze().(*frozenConfig) } func NewEncoder(writer io.Writer) *Encoder { @@ -119,6 +108,6 @@ func (adapter *Encoder) SetIndent(prefix, indent string) { func (adapter *Encoder) SetEscapeHTML(escapeHtml bool) { config := adapter.stream.cfg.configBeforeFrozen - config.EscapeHtml = escapeHtml - adapter.stream.cfg = config.Froze() + config.EscapeHTML = escapeHtml + adapter.stream.cfg = config.Froze().(*frozenConfig) } diff --git a/feature_config.go b/feature_config.go index aadc76a..4fc5629 100644 --- a/feature_config.go +++ b/feature_config.go @@ -9,10 +9,12 @@ import ( "unsafe" ) +// Config customize how the API should behave. +// The API is created from Config by Froze. type Config struct { IndentionStep int MarshalFloatWith6Digits bool - EscapeHtml bool + EscapeHTML bool SortMapKeys bool UseNumber bool } @@ -28,7 +30,11 @@ type frozenConfig struct { iteratorPool chan *Iterator } -type Api interface { +// API the public interface of this package. +// Primary Marshal and Unmarshal. +type API interface { + IteratorPool + StreamPool MarshalToString(v interface{}) (string, error) Marshal(v interface{}) ([]byte, error) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) @@ -39,22 +45,25 @@ type Api interface { NewDecoder(reader io.Reader) *Decoder } +// ConfigDefault the default API var ConfigDefault = Config{ - EscapeHtml: true, + EscapeHTML: true, }.Froze() -// Trying to be 100% compatible with standard library behavior +// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior var ConfigCompatibleWithStandardLibrary = Config{ - EscapeHtml: true, + EscapeHTML: true, SortMapKeys: true, }.Froze() +// ConfigFastest marshals float with only 6 digits precision var ConfigFastest = Config{ - EscapeHtml: false, + EscapeHTML: false, MarshalFloatWith6Digits: true, }.Froze() -func (cfg Config) Froze() *frozenConfig { +// Froze forge API from config +func (cfg Config) Froze() API { // TODO: cache frozen config frozenConfig := &frozenConfig{ sortMapKeys: cfg.SortMapKeys, @@ -67,8 +76,8 @@ func (cfg Config) Froze() *frozenConfig { if cfg.MarshalFloatWith6Digits { frozenConfig.marshalFloatWith6Digits() } - if cfg.EscapeHtml { - frozenConfig.escapeHtml() + if cfg.EscapeHTML { + frozenConfig.escapeHTML() } if cfg.UseNumber { frozenConfig.useNumber() @@ -145,7 +154,7 @@ func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { return *((*string)(ptr)) == "" } -func (cfg *frozenConfig) escapeHtml() { +func (cfg *frozenConfig) escapeHTML() { cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{}) } @@ -189,18 +198,16 @@ func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder { return cache[cacheKey] } -// cleanDecoders cleans decoders registered or cached func (cfg *frozenConfig) cleanDecoders() { typeDecoders = map[string]ValDecoder{} fieldDecoders = map[string]ValDecoder{} - *cfg = *cfg.configBeforeFrozen.Froze() + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) } -// cleanEncoders cleans encoders registered or cached func (cfg *frozenConfig) cleanEncoders() { typeEncoders = map[string]ValEncoder{} fieldEncoders = map[string]ValEncoder{} - *cfg = *cfg.configBeforeFrozen.Froze() + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) } func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { diff --git a/feature_iter.go b/feature_iter.go index 05fc9ee..6a0d2cd 100644 --- a/feature_iter.go +++ b/feature_iter.go @@ -1,9 +1,3 @@ -// -// Besides, jsoniter.Iterator provides a different set of interfaces -// iterating given bytes/string/reader -// and yielding parsed elements one by one. -// This set of interfaces reads input as required and gives -// better performance. package jsoniter import ( @@ -11,15 +5,23 @@ import ( "io" ) +// ValueType the type for JSON element type ValueType int const ( + // Invalid invalid JSON element Invalid ValueType = iota + // String JSON element "string" String + // Number JSON element 100 or 0.10 Number + // Nil JSON element null Nil + // Bool JSON element true or false Bool + // Array JSON element [] Array + // Object JSON element {} Object ) @@ -63,7 +65,8 @@ func init() { valueTypes['{'] = Object } -// Iterator is a fast and flexible JSON parser +// Iterator is a io.Reader like object, with JSON specific read functions. +// Error is not returned as return value, but stored as Error member on this iterator instance. type Iterator struct { cfg *frozenConfig reader io.Reader @@ -75,10 +78,10 @@ type Iterator struct { Error error } -// Create creates an empty Iterator instance -func NewIterator(cfg *frozenConfig) *Iterator { +// NewIterator creates an empty Iterator instance +func NewIterator(cfg API) *Iterator { return &Iterator{ - cfg: cfg, + cfg: cfg.(*frozenConfig), reader: nil, buf: nil, head: 0, @@ -86,10 +89,10 @@ func NewIterator(cfg *frozenConfig) *Iterator { } } -// Parse parses a json buffer in io.Reader into an Iterator instance -func Parse(cfg *frozenConfig, reader io.Reader, bufSize int) *Iterator { +// Parse creates an Iterator instance from io.Reader +func Parse(cfg API, reader io.Reader, bufSize int) *Iterator { return &Iterator{ - cfg: cfg, + cfg: cfg.(*frozenConfig), reader: reader, buf: make([]byte, bufSize), head: 0, @@ -97,10 +100,10 @@ func Parse(cfg *frozenConfig, reader io.Reader, bufSize int) *Iterator { } } -// ParseBytes parses a json byte slice into an Iterator instance -func ParseBytes(cfg *frozenConfig, input []byte) *Iterator { +// ParseBytes creates an Iterator instance from byte array +func ParseBytes(cfg API, input []byte) *Iterator { return &Iterator{ - cfg: cfg, + cfg: cfg.(*frozenConfig), reader: nil, buf: input, head: 0, @@ -108,16 +111,17 @@ func ParseBytes(cfg *frozenConfig, input []byte) *Iterator { } } -// ParseString parses a json string into an Iterator instance -func ParseString(cfg *frozenConfig, input string) *Iterator { +// ParseString creates an Iterator instance from string +func ParseString(cfg API, input string) *Iterator { return ParseBytes(cfg, []byte(input)) } -func (iter *Iterator) Config() *frozenConfig { +// Pool returns a pool can provide more iterator with same configuration +func (iter *Iterator) Pool() IteratorPool { return iter.cfg } -// Reset can reset an Iterator instance for another json buffer in io.Reader +// Reset reuse iterator instance by specifying another reader func (iter *Iterator) Reset(reader io.Reader) *Iterator { iter.reader = reader iter.head = 0 @@ -125,7 +129,7 @@ func (iter *Iterator) Reset(reader io.Reader) *Iterator { return iter } -// ResetBytes can reset an Iterator instance for another json byte slice +// ResetBytes reuse iterator instance by specifying another byte array as input func (iter *Iterator) ResetBytes(input []byte) *Iterator { iter.reader = nil iter.buf = input @@ -134,7 +138,7 @@ func (iter *Iterator) ResetBytes(input []byte) *Iterator { return iter } -// WhatIsNext gets ValueType of relatively next json object +// WhatIsNext gets ValueType of relatively next json element func (iter *Iterator) WhatIsNext() ValueType { valueType := valueTypes[iter.nextToken()] iter.unreadByte() @@ -184,6 +188,7 @@ func (iter *Iterator) nextToken() byte { } } +// ReportError record a error in iterator instance with current position. func (iter *Iterator) ReportError(operation string, msg string) { if iter.Error != nil { if iter.Error != io.EOF { @@ -198,7 +203,7 @@ func (iter *Iterator) ReportError(operation string, msg string) { string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) } -// CurrentBuffer gets current buffer as string +// CurrentBuffer gets current buffer as string for debugging purpose func (iter *Iterator) CurrentBuffer() string { peekStart := iter.head - 10 if peekStart < 0 { @@ -261,6 +266,7 @@ func (iter *Iterator) unreadByte() { return } +// Read read the next JSON element as generic interface{}. func (iter *Iterator) Read() interface{} { valueType := iter.WhatIsNext() switch valueType { diff --git a/feature_iter_array.go b/feature_iter_array.go index c27f16a..7dad669 100644 --- a/feature_iter_array.go +++ b/feature_iter_array.go @@ -1,5 +1,6 @@ package jsoniter +// ReadArray read array element, tells if the array has more element to read. func (iter *Iterator) ReadArray() (ret bool) { c := iter.nextToken() switch c { @@ -23,6 +24,7 @@ func (iter *Iterator) ReadArray() (ret bool) { } } +// ReadArrayCB read array with callback func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { c := iter.nextToken() if c == '[' { diff --git a/feature_iter_float.go b/feature_iter_float.go index ea4b1f3..994f5ae 100644 --- a/feature_iter_float.go +++ b/feature_iter_float.go @@ -30,6 +30,7 @@ func init() { floatDigits['.'] = dotInNumber } +// ReadBigFloat read big.Float func (iter *Iterator) ReadBigFloat() (ret *big.Float) { str := iter.readNumberAsString() if iter.Error != nil && iter.Error != io.EOF { @@ -47,6 +48,7 @@ func (iter *Iterator) ReadBigFloat() (ret *big.Float) { return val } +// ReadBigInt read big.Int func (iter *Iterator) ReadBigInt() (ret *big.Int) { str := iter.readNumberAsString() if iter.Error != nil && iter.Error != io.EOF { @@ -62,14 +64,14 @@ func (iter *Iterator) ReadBigInt() (ret *big.Int) { return ret } +//ReadFloat32 read float32 func (iter *Iterator) ReadFloat32() (ret float32) { c := iter.nextToken() if c == '-' { return -iter.readPositiveFloat32() - } else { - iter.unreadByte() - return iter.readPositiveFloat32() } + iter.unreadByte() + return iter.readPositiveFloat32() } func (iter *Iterator) readPositiveFloat32() (ret float32) { @@ -165,14 +167,14 @@ func (iter *Iterator) readFloat32SlowPath() (ret float32) { return float32(val) } +// ReadFloat64 read float64 func (iter *Iterator) ReadFloat64() (ret float64) { c := iter.nextToken() if c == '-' { return -iter.readPositiveFloat64() - } else { - iter.unreadByte() - return iter.readPositiveFloat64() } + iter.unreadByte() + return iter.readPositiveFloat64() } func (iter *Iterator) readPositiveFloat64() (ret float64) { diff --git a/feature_iter_int.go b/feature_iter_int.go index 139f6f8..886879e 100644 --- a/feature_iter_int.go +++ b/feature_iter_int.go @@ -20,14 +20,17 @@ func init() { } } +// ReadUint read uint func (iter *Iterator) ReadUint() uint { return uint(iter.ReadUint64()) } +// ReadInt read int func (iter *Iterator) ReadInt() int { return int(iter.ReadInt64()) } +// ReadInt8 read int8 func (iter *Iterator) ReadInt8() (ret int8) { c := iter.nextToken() if c == '-' { @@ -37,16 +40,16 @@ func (iter *Iterator) ReadInt8() (ret int8) { return } return -int8(val) - } else { - val := iter.readUint32(c) - if val > math.MaxInt8 { - iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int8(val) } + val := iter.readUint32(c) + if val > math.MaxInt8 { + iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int8(val) } +// ReadUint8 read uint8 func (iter *Iterator) ReadUint8() (ret uint8) { val := iter.readUint32(iter.nextToken()) if val > math.MaxUint8 { @@ -56,6 +59,7 @@ func (iter *Iterator) ReadUint8() (ret uint8) { return uint8(val) } +// ReadInt16 read int16 func (iter *Iterator) ReadInt16() (ret int16) { c := iter.nextToken() if c == '-' { @@ -65,16 +69,16 @@ func (iter *Iterator) ReadInt16() (ret int16) { return } return -int16(val) - } else { - val := iter.readUint32(c) - if val > math.MaxInt16 { - iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int16(val) } + val := iter.readUint32(c) + if val > math.MaxInt16 { + iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int16(val) } +// ReadUint16 read uint16 func (iter *Iterator) ReadUint16() (ret uint16) { val := iter.readUint32(iter.nextToken()) if val > math.MaxUint16 { @@ -84,6 +88,7 @@ func (iter *Iterator) ReadUint16() (ret uint16) { return uint16(val) } +// ReadInt32 read int32 func (iter *Iterator) ReadInt32() (ret int32) { c := iter.nextToken() if c == '-' { @@ -93,16 +98,16 @@ func (iter *Iterator) ReadInt32() (ret int32) { return } return -int32(val) - } else { - val := iter.readUint32(c) - if val > math.MaxInt32 { - iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int32(val) } + val := iter.readUint32(c) + if val > math.MaxInt32 { + iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int32(val) } +// ReadUint32 read uint32 func (iter *Iterator) ReadUint32() (ret uint32) { return iter.readUint32(iter.nextToken()) } @@ -182,10 +187,9 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) { if value2 < value { iter.ReportError("readUint32", "overflow") return - } else { - value = value2 - continue } + value = value2 + continue } value = (value << 3) + (value << 1) + uint32(ind) } @@ -195,6 +199,7 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) { } } +// ReadInt64 read int64 func (iter *Iterator) ReadInt64() (ret int64) { c := iter.nextToken() if c == '-' { @@ -204,16 +209,16 @@ func (iter *Iterator) ReadInt64() (ret int64) { return } return -int64(val) - } else { - val := iter.readUint64(c) - if val > math.MaxInt64 { - iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) - return - } - return int64(val) } + val := iter.readUint64(c) + if val > math.MaxInt64 { + iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) + return + } + return int64(val) } +// ReadUint64 read uint64 func (iter *Iterator) ReadUint64() uint64 { return iter.readUint64(iter.nextToken()) } @@ -240,10 +245,9 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) { if value2 < value { iter.ReportError("readUint64", "overflow") return - } else { - value = value2 - continue } + value = value2 + continue } value = (value << 3) + (value << 1) + uint64(ind) } diff --git a/feature_iter_object.go b/feature_iter_object.go index c999d56..2dd567e 100644 --- a/feature_iter_object.go +++ b/feature_iter_object.go @@ -6,6 +6,9 @@ import ( "unsafe" ) +// ReadObject read one field from object. +// If object ended, returns empty string. +// Otherwise, returns the field name. func (iter *Iterator) ReadObject() (ret string) { c := iter.nextToken() switch c { @@ -74,6 +77,7 @@ func calcHash(str string) int32 { return int32(hash) } +// ReadObjectCB read object with callback, the key is ascii only and field name not copied func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { c := iter.nextToken() if c == '{' { @@ -106,6 +110,7 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { return false } +// ReadMapCB read map with callback, the key can be any string func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { c := iter.nextToken() if c == '{' { diff --git a/feature_iter_skip.go b/feature_iter_skip.go index 5f0f9a1..3d49d6a 100644 --- a/feature_iter_skip.go +++ b/feature_iter_skip.go @@ -29,6 +29,8 @@ func (iter *Iterator) ReadBool() (ret bool) { return } +// SkipAndReturnBytes skip next JSON element, and return its content as []byte. +// The []byte can be kept, it is a copy of data. func (iter *Iterator) SkipAndReturnBytes() []byte { iter.startCapture(iter.head) iter.Skip() @@ -58,10 +60,9 @@ func (iter *Iterator) stopCapture() []byte { iter.captured = nil if len(captured) == 0 { return remaining - } else { - captured = append(captured, remaining...) - return captured } + captured = append(captured, remaining...) + return captured } // Skip skips a json object and positions to relatively the next json object diff --git a/feature_iter_string.go b/feature_iter_string.go index 231c332..2541880 100644 --- a/feature_iter_string.go +++ b/feature_iter_string.go @@ -4,6 +4,7 @@ import ( "unicode/utf16" ) +// ReadString read string from iterator func (iter *Iterator) ReadString() (ret string) { c := iter.nextToken() if c == '"' { @@ -96,6 +97,8 @@ func (iter *Iterator) readStringSlowPath() (ret string) { return } +// ReadStringAsSlice read string from iterator without copying into string form. +// The []byte can not be kept, as it will change after next iterator call. func (iter *Iterator) ReadStringAsSlice() (ret []byte) { c := iter.nextToken() if c == '"' { diff --git a/feature_pool.go b/feature_pool.go index 7b1aeef..73962bc 100644 --- a/feature_pool.go +++ b/feature_pool.go @@ -4,6 +4,18 @@ import ( "io" ) +// IteratorPool a thread safe pool of iterators with same configuration +type IteratorPool interface { + BorrowIterator(data []byte) *Iterator + ReturnIterator(iter *Iterator) +} + +// StreamPool a thread safe pool of streams with same configuration +type StreamPool interface { + BorrowStream(writer io.Writer) *Stream + ReturnStream(stream *Stream) +} + func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream { select { case stream := <-cfg.streamPool: diff --git a/feature_reflect.go b/feature_reflect.go index 211f50a..852d580 100644 --- a/feature_reflect.go +++ b/feature_reflect.go @@ -36,6 +36,7 @@ type checkIsEmpty interface { IsEmpty(ptr unsafe.Pointer) bool } +// WriteToStream the default implementation for TypeEncoder method EncodeInterface func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) { e := (*emptyInterface)(unsafe.Pointer(&val)) if e.word == nil { @@ -49,9 +50,6 @@ func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) { } } -type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) -type EncoderFunc func(ptr unsafe.Pointer, stream *Stream) - var jsonNumberType reflect.Type var jsonRawMessageType reflect.Type var jsoniterRawMessageType reflect.Type @@ -132,9 +130,8 @@ func (encoder *optionalEncoder) EncodeInterface(val interface{}, stream *Stream) func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { if *((*unsafe.Pointer)(ptr)) == nil { return true - } else { - return false } + return false } type placeholderEncoder struct { @@ -206,7 +203,7 @@ type nonEmptyInterface struct { word unsafe.Pointer } -// Read converts an Iterator instance into go interface, same as json.Unmarshal +// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal func (iter *Iterator) ReadVal(obj interface{}) { typ := reflect.TypeOf(obj) cacheKey := typ.Elem() @@ -219,6 +216,7 @@ func (iter *Iterator) ReadVal(obj interface{}) { decoder.Decode(e.word, iter) } +// WriteVal copy the go interface into underlying JSON, same as json.Marshal func (stream *Stream) WriteVal(val interface{}) { if nil == val { stream.WriteNil() @@ -393,9 +391,8 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error case reflect.Interface: if typ.NumMethod() == 0 { return &emptyInterfaceCodec{}, nil - } else { - return &nonEmptyInterfaceCodec{}, nil } + return &nonEmptyInterfaceCodec{}, nil case reflect.Struct: return prefix(fmt.Sprintf("[%s]", typeName)).addToDecoder(decoderOfStruct(cfg, typ)) case reflect.Array: @@ -517,9 +514,8 @@ func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) { case reflect.Interface: if typ.NumMethod() == 0 { return &emptyInterfaceCodec{}, nil - } else { - return &nonEmptyInterfaceCodec{}, nil } + return &nonEmptyInterfaceCodec{}, nil case reflect.Struct: return &structEncoder{}, nil case reflect.Array: @@ -617,9 +613,8 @@ func createEncoderOfSimpleType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, case reflect.Interface: if typ.NumMethod() == 0 { return &emptyInterfaceCodec{}, nil - } else { - return &nonEmptyInterfaceCodec{}, nil } + return &nonEmptyInterfaceCodec{}, nil case reflect.Struct: return prefix(fmt.Sprintf("[%s]", typeName)).addToEncoder(encoderOfStruct(cfg, typ)) case reflect.Array: @@ -679,7 +674,6 @@ func encoderOfMap(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { mapInterface := reflect.New(typ).Elem().Interface() if cfg.sortMapKeys { return &sortKeysMapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil - } else { - return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil } + return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil } diff --git a/feature_reflect_extension.go b/feature_reflect_extension.go index a8ed221..ea66a07 100644 --- a/feature_reflect_extension.go +++ b/feature_reflect_extension.go @@ -110,6 +110,11 @@ func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool { return encoder.isEmptyFunc(ptr) } +// DecoderFunc the function form of TypeDecoder +type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) +// EncoderFunc the function form of TypeEncoder +type EncoderFunc func(ptr unsafe.Pointer, stream *Stream) + // RegisterTypeDecoderFunc register TypeDecoder for a type with function func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { typeDecoders[typ] = &funcDecoder{fun} diff --git a/feature_reflect_struct_decoder.go b/feature_reflect_struct_decoder.go index dca109b..3a645dc 100644 --- a/feature_reflect_struct_decoder.go +++ b/feature_reflect_struct_decoder.go @@ -1,9 +1,9 @@ package jsoniter import ( - "reflect" - "io" "fmt" + "io" + "reflect" "unsafe" ) @@ -71,7 +71,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &threeFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil case 4: var fieldName1 int32 var fieldName2 int32 @@ -103,8 +103,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &fourFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4}, nil case 5: var fieldName1 int32 var fieldName2 int32 @@ -141,8 +141,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &fiveFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil case 6: var fieldName1 int32 var fieldName2 int32 @@ -184,8 +184,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &sixFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil case 7: var fieldName1 int32 var fieldName2 int32 @@ -232,9 +232,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &sevenFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7}, nil case 8: var fieldName1 int32 var fieldName2 int32 @@ -286,9 +286,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &eightFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil case 9: var fieldName1 int32 var fieldName2 int32 @@ -345,9 +345,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &nineFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil case 10: var fieldName1 int32 var fieldName2 int32 @@ -409,15 +409,14 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder } } return &tenFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9, - fieldName10, fieldDecoder10}, nil + fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9, + fieldName10, fieldDecoder10}, nil } return &generalStructDecoder{typ, fields}, nil } - type generalStructDecoder struct { typ reflect.Type fields map[string]*structFieldDecoder @@ -911,4 +910,4 @@ func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { if iter.Error != nil && iter.Error != io.EOF { iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error()) } -} \ No newline at end of file +} diff --git a/feature_stream.go b/feature_stream.go index 2eeb079..f4fa385 100644 --- a/feature_stream.go +++ b/feature_stream.go @@ -4,7 +4,7 @@ import ( "io" ) -// Stream is a writer like object, with JSON specific write functions. +// Stream is a io.Writer like object, with JSON specific write functions. // Error is not returned as return value, but stored as Error member on this stream instance. type Stream struct { cfg *frozenConfig @@ -19,9 +19,9 @@ type Stream struct { // cfg can be jsoniter.ConfigDefault. // out can be nil if write to internal buffer. // bufSize is the initial size for the internal buffer in bytes. -func NewStream(cfg *frozenConfig, out io.Writer, bufSize int) *Stream { +func NewStream(cfg API, out io.Writer, bufSize int) *Stream { return &Stream{ - cfg: cfg, + cfg: cfg.(*frozenConfig), out: out, buf: make([]byte, bufSize), n: 0, @@ -30,6 +30,11 @@ func NewStream(cfg *frozenConfig, out io.Writer, bufSize int) *Stream { } } +// Pool returns a pool can provide more stream with same configuration +func (stream *Stream) Pool() StreamPool { + return stream.cfg +} + // Reset reuse this stream instance by assign a new writer func (stream *Stream) Reset(out io.Writer) { stream.out = out @@ -196,7 +201,6 @@ func (stream *Stream) growAtLeast(minimal int) { stream.buf = newBuf } - // WriteRaw write string out without quotes, just like []byte func (stream *Stream) WriteRaw(s string) { stream.ensure(len(s)) diff --git a/jsoniter.go b/jsoniter.go new file mode 100644 index 0000000..c2934f9 --- /dev/null +++ b/jsoniter.go @@ -0,0 +1,18 @@ +// Package jsoniter implements encoding and decoding of JSON as defined in +// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json. +// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter +// and variable type declarations (if any). +// jsoniter interfaces gives 100% compatibility with code using standard lib. +// +// "JSON and Go" +// (https://golang.org/doc/articles/json_and_go.html) +// gives a description of how Marshal/Unmarshal operate +// between arbitrary or predefined json objects and bytes, +// and it applies to jsoniter.Marshal/Unmarshal as well. +// +// Besides, jsoniter.Iterator provides a different set of interfaces +// iterating given bytes/string/reader +// and yielding parsed elements one by one. +// This set of interfaces reads input as required and gives +// better performance. +package jsoniter diff --git a/jsoniter_1dot8_only_test.go b/jsoniter_1dot8_only_test.go index d57366a..7a0886a 100644 --- a/jsoniter_1dot8_only_test.go +++ b/jsoniter_1dot8_only_test.go @@ -26,7 +26,7 @@ func Test_new_encoder(t *testing.T) { } func Test_string_encode_with_std_without_html_escape(t *testing.T) { - api := Config{EscapeHtml: false}.Froze() + api := Config{EscapeHTML: false}.Froze() should := require.New(t) for i := 0; i < utf8.RuneSelf; i++ { input := string([]byte{byte(i)}) diff --git a/jsoniter_any_string_test.go b/jsoniter_any_string_test.go index 32fdca3..d6e9a07 100644 --- a/jsoniter_any_string_test.go +++ b/jsoniter_any_string_test.go @@ -7,25 +7,25 @@ import ( ) var stringConvertMap = map[string]string{ - "null": "", - "321.1": "321.1", - `"1.1"`: "1.1", - `"-123.1"`: "-123.1", - "0.0": "0.0", - "0": "0", - `"0"`: "0", - `"0.0"`: "0.0", - `"00.0"`: "00.0", - "true": "true", - "false": "false", - `"true"`: "true", - `"false"`: "false", - `"true123"`: "true123", - `"+1"`: "+1", - "[]": "[]", - "[1,2]": "[1,2]", - "{}": "{}", - "{1,2}": "{1,2}", + "null": "", + "321.1": "321.1", + `"1.1"`: "1.1", + `"-123.1"`: "-123.1", + "0.0": "0.0", + "0": "0", + `"0"`: "0", + `"0.0"`: "0.0", + `"00.0"`: "00.0", + "true": "true", + "false": "false", + `"true"`: "true", + `"false"`: "false", + `"true123"`: "true123", + `"+1"`: "+1", + "[]": "[]", + "[1,2]": "[1,2]", + "{}": "{}", + "{1,2}": "{1,2}", `{"a":1, "stream":true}`: `{"a":1, "stream":true}`, } diff --git a/jsoniter_customize_test.go b/jsoniter_customize_test.go index cb457c2..d625f6e 100644 --- a/jsoniter_customize_test.go +++ b/jsoniter_customize_test.go @@ -18,7 +18,7 @@ func Test_customize_type_decoder(t *testing.T) { } *((*time.Time)(ptr)) = t }) - defer ConfigDefault.cleanDecoders() + defer ConfigDefault.(*frozenConfig).cleanDecoders() val := time.Time{} err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val) if err != nil { @@ -36,7 +36,7 @@ func Test_customize_type_encoder(t *testing.T) { t := *((*time.Time)(ptr)) stream.WriteString(t.UTC().Format("2006-01-02 15:04:05")) }, nil) - defer ConfigDefault.cleanEncoders() + defer ConfigDefault.(*frozenConfig).cleanEncoders() val := time.Unix(0, 0) str, err := MarshalToString(val) should.Nil(err) @@ -44,13 +44,13 @@ func Test_customize_type_encoder(t *testing.T) { } func Test_customize_byte_array_encoder(t *testing.T) { - ConfigDefault.cleanEncoders() + ConfigDefault.(*frozenConfig).cleanEncoders() should := require.New(t) RegisterTypeEncoderFunc("[]uint8", func(ptr unsafe.Pointer, stream *Stream) { t := *((*[]byte)(ptr)) stream.WriteString(string(t)) }, nil) - defer ConfigDefault.cleanEncoders() + defer ConfigDefault.(*frozenConfig).cleanEncoders() val := []byte("abc") str, err := MarshalToString(val) should.Nil(err) @@ -73,7 +73,7 @@ func Test_customize_field_decoder(t *testing.T) { RegisterFieldDecoderFunc("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) { *((*string)(ptr)) = strconv.Itoa(iter.ReadInt()) }) - defer ConfigDefault.cleanDecoders() + defer ConfigDefault.(*frozenConfig).cleanDecoders() tom := Tom{} err := Unmarshal([]byte(`{"field1": 100}`), &tom) if err != nil { @@ -144,7 +144,7 @@ func Test_marshaler_and_encoder(t *testing.T) { type TestObject struct { Field *timeImplementedMarshaler } - ConfigDefault.cleanEncoders() + ConfigDefault.(*frozenConfig).cleanEncoders() should := require.New(t) RegisterTypeEncoderFunc("jsoniter.timeImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) { stream.WriteString("hello from encoder") @@ -184,7 +184,7 @@ func Test_unmarshaler_and_decoder(t *testing.T) { Field *ObjectImplementedUnmarshaler Field2 string } - ConfigDefault.cleanDecoders() + ConfigDefault.(*frozenConfig).cleanDecoders() should := require.New(t) RegisterTypeDecoderFunc("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) { *(*ObjectImplementedUnmarshaler)(ptr) = 10 diff --git a/jsoniter_interface_test.go b/jsoniter_interface_test.go index 916ec6f..44104b1 100644 --- a/jsoniter_interface_test.go +++ b/jsoniter_interface_test.go @@ -141,8 +141,8 @@ func Test_encode_object_contain_non_empty_interface(t *testing.T) { } func Test_nil_non_empty_interface(t *testing.T) { - ConfigDefault.cleanEncoders() - ConfigDefault.cleanDecoders() + ConfigDefault.(*frozenConfig).cleanEncoders() + ConfigDefault.(*frozenConfig).cleanDecoders() type TestObject struct { Field []MyInterface } diff --git a/jsoniter_io_test.go b/jsoniter_io_test.go index fdfabb0..2ec8ac9 100644 --- a/jsoniter_io_test.go +++ b/jsoniter_io_test.go @@ -2,9 +2,9 @@ package jsoniter import ( "bytes" + "github.com/stretchr/testify/require" "io" "testing" - "github.com/stretchr/testify/require" ) func Test_read_by_one(t *testing.T) { diff --git a/jsoniter_string_test.go b/jsoniter_string_test.go index 0231f74..713af75 100644 --- a/jsoniter_string_test.go +++ b/jsoniter_string_test.go @@ -127,7 +127,7 @@ func Test_unicode(t *testing.T) { should := require.New(t) output, _ := MarshalToString(map[string]interface{}{"a": "数字山谷"}) should.Equal(`{"a":"数字山谷"}`, output) - output, _ = Config{EscapeHtml: false}.Froze().MarshalToString(map[string]interface{}{"a": "数字山谷"}) + output, _ = Config{EscapeHTML: false}.Froze().MarshalToString(map[string]interface{}{"a": "数字山谷"}) should.Equal(`{"a":"数字山谷"}`, output) } @@ -142,7 +142,7 @@ func Test_unicode_and_escape(t *testing.T) { } func Test_unsafe_unicode(t *testing.T) { - ConfigDefault.cleanEncoders() + ConfigDefault.(*frozenConfig).cleanEncoders() should := require.New(t) output, err := ConfigDefault.MarshalToString("he\u2029\u2028he") should.Nil(err)