update vendor lib

This commit is contained in:
Megan Marsh 2019-10-28 16:11:27 -07:00
parent 9c02d7c1eb
commit 3c58b9c1f6
29 changed files with 29224 additions and 30956 deletions

View File

@ -1,9 +1,10 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
/* /*
High Performance, Feature-Rich Idiomatic Go codec/encoding library for Package codec provides a
binc, msgpack, cbor, json. High Performance, Feature-Rich Idiomatic Go 1.4+ codec/encoding library
for binc, msgpack, cbor, json.
Supported Serialization formats are: Supported Serialization formats are:
@ -11,21 +12,17 @@ Supported Serialization formats are:
- binc: http://github.com/ugorji/binc - binc: http://github.com/ugorji/binc
- cbor: http://cbor.io http://tools.ietf.org/html/rfc7049 - cbor: http://cbor.io http://tools.ietf.org/html/rfc7049
- json: http://json.org http://tools.ietf.org/html/rfc7159 - json: http://json.org http://tools.ietf.org/html/rfc7159
- simple: - simple:
To install: To install:
go get github.com/ugorji/go/codec go get github.com/ugorji/go/codec
This package understands the 'unsafe' tag, to allow using unsafe semantics: This package will carefully use 'unsafe' for performance reasons in specific places.
You can build without unsafe use by passing the safe or appengine tag
- When decoding into a struct, you need to read the field name as a string i.e. 'go install -tags=safe ...'. Note that unsafe is only supported for the last 3
so you can find the struct field it is mapped to. go sdk versions e.g. current go release is go 1.9, so we support unsafe use only from
Using `unsafe` will bypass the allocation and copying overhead of []byte->string conversion. go 1.7+ . This is because supporting unsafe requires knowledge of implementation details.
To install using unsafe, pass the 'unsafe' tag:
go get -tags=unsafe github.com/ugorji/go/codec
For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer . For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer .
@ -35,12 +32,16 @@ the standard library (ie json, xml, gob, etc).
Rich Feature Set includes: Rich Feature Set includes:
- Simple but extremely powerful and feature-rich API - Simple but extremely powerful and feature-rich API
- Support for go1.4 and above, while selectively using newer APIs for later releases
- Excellent code coverage ( > 90% )
- Very High Performance. - Very High Performance.
Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X. Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X.
- Multiple conversions: - Careful selected use of 'unsafe' for targeted performance gains.
Package coerces types where appropriate 100% mode exists where 'unsafe' is not used at all.
e.g. decode an int in the stream into a float, etc. - Lock-free (sans mutex) concurrency for scaling to 100's of cores
- Corner Cases: - Coerce types where appropriate
e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc
- Corner Cases:
Overflows, nil maps/slices, nil values in streams are handled correctly Overflows, nil maps/slices, nil values in streams are handled correctly
- Standard field renaming via tags - Standard field renaming via tags
- Support for omitting empty fields during an encoding - Support for omitting empty fields during an encoding
@ -48,15 +49,21 @@ Rich Feature Set includes:
(struct, slice, map, primitives, pointers, interface{}, etc) (struct, slice, map, primitives, pointers, interface{}, etc)
- Extensions to support efficient encoding/decoding of any named types - Extensions to support efficient encoding/decoding of any named types
- Support encoding.(Binary|Text)(M|Unm)arshaler interfaces - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces
- Support IsZero() bool to determine if a value is a zero value.
Analogous to time.Time.IsZero() bool.
- Decoding without a schema (into a interface{}). - Decoding without a schema (into a interface{}).
Includes Options to configure what specific map or slice type to use Includes Options to configure what specific map or slice type to use
when decoding an encoded list or map into a nil interface{} when decoding an encoded list or map into a nil interface{}
- Mapping a non-interface type to an interface, so we can decode appropriately
into any interface type with a correctly configured non-interface value.
- Encode a struct as an array, and decode struct from an array in the data stream - Encode a struct as an array, and decode struct from an array in the data stream
- Option to encode struct keys as numbers (instead of strings)
(to support structured streams with fields encoded as numeric codes)
- Comprehensive support for anonymous fields - Comprehensive support for anonymous fields
- Fast (no-reflection) encoding/decoding of common maps and slices - Fast (no-reflection) encoding/decoding of common maps and slices
- Code-generation for faster performance. - Code-generation for faster performance.
- Support binary (e.g. messagepack, cbor) and text (e.g. json) formats - Support binary (e.g. messagepack, cbor) and text (e.g. json) formats
- Support indefinite-length formats to enable true streaming - Support indefinite-length formats to enable true streaming
(for formats which support it e.g. json, cbor) (for formats which support it e.g. json, cbor)
- Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes. - Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes.
This mostly applies to maps, where iteration order is non-deterministic. This mostly applies to maps, where iteration order is non-deterministic.
@ -68,12 +75,12 @@ Rich Feature Set includes:
- Encode/Decode from/to chan types (for iterative streaming support) - Encode/Decode from/to chan types (for iterative streaming support)
- Drop-in replacement for encoding/json. `json:` key in struct tag supported. - Drop-in replacement for encoding/json. `json:` key in struct tag supported.
- Provides a RPC Server and Client Codec for net/rpc communication protocol. - Provides a RPC Server and Client Codec for net/rpc communication protocol.
- Handle unique idiosynchracies of codecs e.g. - Handle unique idiosyncrasies of codecs e.g.
- For messagepack, configure how ambiguities in handling raw bytes are resolved - For messagepack, configure how ambiguities in handling raw bytes are resolved
- For messagepack, provide rpc server/client codec to support - For messagepack, provide rpc server/client codec to support
msgpack-rpc protocol defined at: msgpack-rpc protocol defined at:
https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
Extension Support Extension Support
Users can register a function to handle the encoding or decoding of Users can register a function to handle the encoding or decoding of
@ -92,6 +99,27 @@ encoded as an empty map because it has no exported fields, while UUID
would be encoded as a string. However, with extension support, you can would be encoded as a string. However, with extension support, you can
encode any of these however you like. encode any of these however you like.
Custom Encoding and Decoding
This package maintains symmetry in the encoding and decoding halfs.
We determine how to encode or decode by walking this decision tree
- is type a codec.Selfer?
- is there an extension registered for the type?
- is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler?
- is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler?
- is format text-based, and type an encoding.TextMarshaler?
- else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc
This symmetry is important to reduce chances of issues happening because the
encoding and decoding sides are out of sync e.g. decoded via very specific
encoding.TextUnmarshaler but encoded via kind-specific generalized mode.
Consequently, if a type only defines one-half of the symmetry
(e.g. it implements UnmarshalJSON() but not MarshalJSON() ),
then that type doesn't satisfy the check and we will continue walking down the
decision tree.
RPC RPC
RPC Client and Server Codecs are implemented, so the codecs can be used RPC Client and Server Codecs are implemented, so the codecs can be used
@ -160,40 +188,77 @@ Sample usage model:
//OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
client := rpc.NewClientWithCodec(rpcCodec) client := rpc.NewClientWithCodec(rpcCodec)
Running Tests
To run tests, use the following:
go test
To run the full suite of tests, use the following:
go test -tags alltests -run Suite
You can run the tag 'safe' to run tests or build in safe mode. e.g.
go test -tags safe -run Json
go test -tags "alltests safe" -run Suite
Running Benchmarks
Please see http://github.com/ugorji/go-codec-bench .
Caveats
Struct fields matching the following are ignored during encoding and decoding
- struct tag value set to -
- func, complex numbers, unsafe pointers
- unexported and not embedded
- unexported and embedded and not struct kind
- unexported and embedded pointers (from go1.10)
Every other field in a struct will be encoded/decoded.
Embedded fields are encoded as if they exist in the top-level struct,
with some caveats. See Encode documentation.
*/ */
package codec package codec
// Benefits of go-codec:
//
// - encoding/json always reads whole file into memory first.
// This makes it unsuitable for parsing very large files.
// - encoding/xml cannot parse into a map[string]interface{}
// I found this out on reading https://github.com/clbanning/mxj
// TODO: // TODO:
// - For Go 1.11, when mid-stack inlining is enabled,
// we should use committed functions for writeXXX and readXXX calls.
// This involves uncommenting the methods for decReaderSwitch and encWriterSwitch
// and using those (decReaderSwitch and encWriterSwitch) in all handles
// instead of encWriter and decReader.
// The benefit is that, for the (En|De)coder over []byte, the encWriter/decReader
// will be inlined, giving a performance bump for that typical case.
// However, it will only be inlined if mid-stack inlining is enabled,
// as we call panic to raise errors, and panic currently prevents inlining.
// //
// - optimization for codecgen: // PUNTED:
// if len of entity is <= 3 words, then support a value receiver for encode. // - To make Handle comparable, make extHandle in BasicHandle a non-embedded pointer,
// - (En|De)coder should store an error when it occurs. // and use overlay methods on *BasicHandle to call through to extHandle after initializing
// Until reset, subsequent calls return that error that was stored. // the "xh *extHandle" to point to a real slice.
// This means that free panics must go away. //
// All errors must be raised through errorf method. // BEFORE EACH RELEASE:
// - Decoding using a chan is good, but incurs concurrency costs. // - Look through and fix padding for each type, to eliminate false sharing
// This is because there's no fast way to use a channel without it // - critical shared objects that are read many times
// having to switch goroutines constantly. // TypeInfos
// Callback pattern is still the best. Maybe cnsider supporting something like: // - pooled objects:
// type X struct { // decNaked, decNakedContainers, codecFner, typeInfoLoadArray,
// Name string // - small objects allocated independently, that we read/use much across threads:
// Ys []Y // codecFn, typeInfo
// Ys chan <- Y // - Objects allocated independently and used a lot
// Ys func(Y) -> call this function for each entry // Decoder, Encoder,
// } // xxxHandle, xxxEncDriver, xxxDecDriver (xxx = json, msgpack, cbor, binc, simple)
// - Consider adding a isZeroer interface { isZero() bool } // - In all above, arrange values modified together to be close to each other.
// It is used within isEmpty, for omitEmpty support. //
// - Consider making Handle used AS-IS within the encoding/decoding session. // For all of these, either ensure that they occupy full cache lines,
// This means that we don't cache Handle information within the (En|De)coder, // or ensure that the things just past the cache line boundary are hardly read/written
// except we really need it at Reset(...) // e.g. JsonHandle.RawBytesExt - which is copied into json(En|De)cDriver at init
// - Consider adding math/big support //
// - Consider reducing the size of the generated functions: // Occupying full cache lines means they occupy 8*N words (where N is an integer).
// Maybe use one loop, and put the conditionals in the loop. // Check this out by running: ./run.sh -z
// for ... { if cLen > 0 { if j == cLen { break } } else if dd.CheckBreak() { break } } // - look at those tagged ****, meaning they are not occupying full cache lines
// - look at those tagged <<<<, meaning they are larger than 32 words (something to watch)
// - Run "golint -min_confidence 0.81"

View File

@ -15,17 +15,11 @@ To install:
go get github.com/ugorji/go/codec go get github.com/ugorji/go/codec
This package understands the `unsafe` tag, to allow using unsafe semantics: This package will carefully use 'unsafe' for performance reasons in specific places.
You can build without unsafe use by passing the safe or appengine tag
- When decoding into a struct, you need to read the field name as a string i.e. 'go install -tags=safe ...'. Note that unsafe is only supported for the last 3
so you can find the struct field it is mapped to. go sdk versions e.g. current go release is go 1.9, so we support unsafe use only from
Using `unsafe` will bypass the allocation and copying overhead of `[]byte->string` conversion. go 1.7+ . This is because supporting unsafe requires knowledge of implementation details.
To use it, you must pass the `unsafe` tag during install:
```
go install -tags=unsafe github.com/ugorji/go/codec
```
Online documentation: http://godoc.org/github.com/ugorji/go/codec Online documentation: http://godoc.org/github.com/ugorji/go/codec
Detailed Usage/How-to Primer: http://ugorji.net/blog/go-codec-primer Detailed Usage/How-to Primer: http://ugorji.net/blog/go-codec-primer
@ -36,11 +30,15 @@ the standard library (ie json, xml, gob, etc).
Rich Feature Set includes: Rich Feature Set includes:
- Simple but extremely powerful and feature-rich API - Simple but extremely powerful and feature-rich API
- Support for go1.4 and above, while selectively using newer APIs for later releases
- Excellent code coverage ( > 90% )
- Very High Performance. - Very High Performance.
Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X. Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X.
- Multiple conversions: - Careful selected use of 'unsafe' for targeted performance gains.
Package coerces types where appropriate 100% mode exists where 'unsafe' is not used at all.
e.g. decode an int in the stream into a float, etc. - Lock-free (sans mutex) concurrency for scaling to 100's of cores
- Coerce types where appropriate
e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc
- Corner Cases: - Corner Cases:
Overflows, nil maps/slices, nil values in streams are handled correctly Overflows, nil maps/slices, nil values in streams are handled correctly
- Standard field renaming via tags - Standard field renaming via tags
@ -49,10 +47,16 @@ Rich Feature Set includes:
(struct, slice, map, primitives, pointers, interface{}, etc) (struct, slice, map, primitives, pointers, interface{}, etc)
- Extensions to support efficient encoding/decoding of any named types - Extensions to support efficient encoding/decoding of any named types
- Support encoding.(Binary|Text)(M|Unm)arshaler interfaces - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces
- Support IsZero() bool to determine if a value is a zero value.
Analogous to time.Time.IsZero() bool.
- Decoding without a schema (into a interface{}). - Decoding without a schema (into a interface{}).
Includes Options to configure what specific map or slice type to use Includes Options to configure what specific map or slice type to use
when decoding an encoded list or map into a nil interface{} when decoding an encoded list or map into a nil interface{}
- Mapping a non-interface type to an interface, so we can decode appropriately
into any interface type with a correctly configured non-interface value.
- Encode a struct as an array, and decode struct from an array in the data stream - Encode a struct as an array, and decode struct from an array in the data stream
- Option to encode struct keys as numbers (instead of strings)
(to support structured streams with fields encoded as numeric codes)
- Comprehensive support for anonymous fields - Comprehensive support for anonymous fields
- Fast (no-reflection) encoding/decoding of common maps and slices - Fast (no-reflection) encoding/decoding of common maps and slices
- Code-generation for faster performance. - Code-generation for faster performance.
@ -68,7 +72,7 @@ Rich Feature Set includes:
- Encode/Decode from/to chan types (for iterative streaming support) - Encode/Decode from/to chan types (for iterative streaming support)
- Drop-in replacement for encoding/json. `json:` key in struct tag supported. - Drop-in replacement for encoding/json. `json:` key in struct tag supported.
- Provides a RPC Server and Client Codec for net/rpc communication protocol. - Provides a RPC Server and Client Codec for net/rpc communication protocol.
- Handle unique idiosynchracies of codecs e.g. - Handle unique idiosyncrasies of codecs e.g.
- For messagepack, configure how ambiguities in handling raw bytes are resolved - For messagepack, configure how ambiguities in handling raw bytes are resolved
- For messagepack, provide rpc server/client codec to support - For messagepack, provide rpc server/client codec to support
msgpack-rpc protocol defined at: msgpack-rpc protocol defined at:
@ -92,6 +96,27 @@ encoded as an empty map because it has no exported fields, while UUID
would be encoded as a string. However, with extension support, you can would be encoded as a string. However, with extension support, you can
encode any of these however you like. encode any of these however you like.
## Custom Encoding and Decoding
This package maintains symmetry in the encoding and decoding halfs.
We determine how to encode or decode by walking this decision tree
- is type a codec.Selfer?
- is there an extension registered for the type?
- is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler?
- is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler?
- is format text-based, and type an encoding.TextMarshaler?
- else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc
This symmetry is important to reduce chances of issues happening because the
encoding and decoding sides are out of sync e.g. decoded via very specific
encoding.TextUnmarshaler but encoded via kind-specific generalized mode.
Consequently, if a type only defines one-half of the symmetry
(e.g. it implements UnmarshalJSON() but not MarshalJSON() ),
then that type doesn't satisfy the check and we will continue walking down the
decision tree.
## RPC ## RPC
RPC Client and Server Codecs are implemented, so the codecs can be used RPC Client and Server Codecs are implemented, so the codecs can be used
@ -146,3 +171,36 @@ Typical usage model:
//OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
client := rpc.NewClientWithCodec(rpcCodec) client := rpc.NewClientWithCodec(rpcCodec)
## Running Tests
To run tests, use the following:
go test
To run the full suite of tests, use the following:
go test -tags alltests -run Suite
You can run the tag 'safe' to run tests or build in safe mode. e.g.
go test -tags safe -run Json
go test -tags "alltests safe" -run Suite
## Running Benchmarks
Please see http://github.com/ugorji/go-codec-bench .
## Caveats
Struct fields matching the following are ignored during encoding and decoding
- struct tag value set to -
- func, complex numbers, unsafe pointers
- unexported and not embedded
- unexported and embedded and not struct kind
- unexported and embedded pointers (from go1.10)
Every other field in a struct will be encoded/decoded.
Embedded fields are encoded as if they exist in the top-level struct,
with some caveats. See Encode documentation.

View File

@ -1,4 +1,4 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
package codec package codec
@ -55,39 +55,77 @@ const (
// others not currently supported // others not currently supported
) )
func bincdesc(vd, vs byte) string {
switch vd {
case bincVdSpecial:
switch vs {
case bincSpNil:
return "nil"
case bincSpFalse:
return "false"
case bincSpTrue:
return "true"
case bincSpNan, bincSpPosInf, bincSpNegInf, bincSpZeroFloat:
return "float"
case bincSpZero:
return "uint"
case bincSpNegOne:
return "int"
default:
return "unknown"
}
case bincVdSmallInt, bincVdPosInt:
return "uint"
case bincVdNegInt:
return "int"
case bincVdFloat:
return "float"
case bincVdSymbol:
return "string"
case bincVdString:
return "string"
case bincVdByteArray:
return "bytes"
case bincVdTimestamp:
return "time"
case bincVdCustomExt:
return "ext"
case bincVdArray:
return "array"
case bincVdMap:
return "map"
default:
return "unknown"
}
}
type bincEncDriver struct { type bincEncDriver struct {
e *Encoder e *Encoder
h *BincHandle
w encWriter w encWriter
m map[string]uint16 // symbols m map[string]uint16 // symbols
b [scratchByteArrayLen]byte b [16]byte // scratch, used for encoding numbers - bigendian style
s uint16 // symbols sequencer s uint16 // symbols sequencer
encNoSeparator // c containerState
} encDriverTrackContainerWriter
noBuiltInTypes
func (e *bincEncDriver) IsBuiltinType(rt uintptr) bool { // encNoSeparator
return rt == timeTypId
}
func (e *bincEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {
if rt == timeTypId {
var bs []byte
switch x := v.(type) {
case time.Time:
bs = encodeTime(x)
case *time.Time:
bs = encodeTime(*x)
default:
e.e.errorf("binc error encoding builtin: expect time.Time, received %T", v)
}
e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs)))
e.w.writeb(bs)
}
} }
func (e *bincEncDriver) EncodeNil() { func (e *bincEncDriver) EncodeNil() {
e.w.writen1(bincVdSpecial<<4 | bincSpNil) e.w.writen1(bincVdSpecial<<4 | bincSpNil)
} }
func (e *bincEncDriver) EncodeTime(t time.Time) {
if t.IsZero() {
e.EncodeNil()
} else {
bs := bincEncodeTime(t)
e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs)))
e.w.writeb(bs)
}
}
func (e *bincEncDriver) EncodeBool(b bool) { func (e *bincEncDriver) EncodeBool(b bool) {
if b { if b {
e.w.writen1(bincVdSpecial<<4 | bincSpTrue) e.w.writen1(bincVdSpecial<<4 | bincSpTrue)
@ -195,15 +233,21 @@ func (e *bincEncDriver) encodeExtPreamble(xtag byte, length int) {
e.w.writen1(xtag) e.w.writen1(xtag)
} }
func (e *bincEncDriver) EncodeArrayStart(length int) { func (e *bincEncDriver) WriteArrayStart(length int) {
e.encLen(bincVdArray<<4, uint64(length)) e.encLen(bincVdArray<<4, uint64(length))
e.c = containerArrayStart
} }
func (e *bincEncDriver) EncodeMapStart(length int) { func (e *bincEncDriver) WriteMapStart(length int) {
e.encLen(bincVdMap<<4, uint64(length)) e.encLen(bincVdMap<<4, uint64(length))
e.c = containerMapStart
} }
func (e *bincEncDriver) EncodeString(c charEncoding, v string) { func (e *bincEncDriver) EncodeString(c charEncoding, v string) {
if e.c == containerMapKey && c == cUTF8 && (e.h.AsSymbols == 0 || e.h.AsSymbols == 1) {
e.EncodeSymbol(v)
return
}
l := uint64(len(v)) l := uint64(len(v))
e.encBytesLen(c, l) e.encBytesLen(c, l)
if l > 0 { if l > 0 {
@ -213,7 +257,7 @@ func (e *bincEncDriver) EncodeString(c charEncoding, v string) {
func (e *bincEncDriver) EncodeSymbol(v string) { func (e *bincEncDriver) EncodeSymbol(v string) {
// if WriteSymbolsNoRefs { // if WriteSymbolsNoRefs {
// e.encodeString(c_UTF8, v) // e.encodeString(cUTF8, v)
// return // return
// } // }
@ -223,10 +267,10 @@ func (e *bincEncDriver) EncodeSymbol(v string) {
l := len(v) l := len(v)
if l == 0 { if l == 0 {
e.encBytesLen(c_UTF8, 0) e.encBytesLen(cUTF8, 0)
return return
} else if l == 1 { } else if l == 1 {
e.encBytesLen(c_UTF8, 1) e.encBytesLen(cUTF8, 1)
e.w.writen1(v[0]) e.w.writen1(v[0])
return return
} }
@ -276,6 +320,10 @@ func (e *bincEncDriver) EncodeSymbol(v string) {
} }
func (e *bincEncDriver) EncodeStringBytes(c charEncoding, v []byte) { func (e *bincEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
if v == nil {
e.EncodeNil()
return
}
l := uint64(len(v)) l := uint64(len(v))
e.encBytesLen(c, l) e.encBytesLen(c, l)
if l > 0 { if l > 0 {
@ -285,7 +333,7 @@ func (e *bincEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) { func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) {
//TODO: support bincUnicodeOther (for now, just use string or bytearray) //TODO: support bincUnicodeOther (for now, just use string or bytearray)
if c == c_RAW { if c == cRAW {
e.encLen(bincVdByteArray<<4, length) e.encLen(bincVdByteArray<<4, length)
} else { } else {
e.encLen(bincVdString<<4, length) e.encLen(bincVdString<<4, length)
@ -324,6 +372,9 @@ type bincDecSymbol struct {
} }
type bincDecDriver struct { type bincDecDriver struct {
decDriverNoopContainerReader
noBuiltInTypes
d *Decoder d *Decoder
h *BincHandle h *BincHandle
r decReader r decReader
@ -332,13 +383,15 @@ type bincDecDriver struct {
bd byte bd byte
vd byte vd byte
vs byte vs byte
noStreamingCodec _ [3]byte // padding
decNoSeparator
b [scratchByteArrayLen]byte
// linear searching on this slice is ok, // linear searching on this slice is ok,
// because we typically expect < 32 symbols in each stream. // because we typically expect < 32 symbols in each stream.
s []bincDecSymbol s []bincDecSymbol
// noStreamingCodec
// decNoSeparator
b [8 * 8]byte // scratch
} }
func (d *bincDecDriver) readNextBd() { func (d *bincDecDriver) readNextBd() {
@ -348,7 +401,17 @@ func (d *bincDecDriver) readNextBd() {
d.bdRead = true d.bdRead = true
} }
func (d *bincDecDriver) uncacheRead() {
if d.bdRead {
d.r.unreadn1()
d.bdRead = false
}
}
func (d *bincDecDriver) ContainerType() (vt valueType) { func (d *bincDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
if d.vd == bincVdSpecial && d.vs == bincSpNil { if d.vd == bincVdSpecial && d.vs == bincSpNil {
return valueTypeNil return valueTypeNil
} else if d.vd == bincVdByteArray { } else if d.vd == bincVdByteArray {
@ -359,9 +422,10 @@ func (d *bincDecDriver) ContainerType() (vt valueType) {
return valueTypeArray return valueTypeArray
} else if d.vd == bincVdMap { } else if d.vd == bincVdMap {
return valueTypeMap return valueTypeMap
} else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
} }
// else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
// }
return valueTypeUnset return valueTypeUnset
} }
@ -376,27 +440,24 @@ func (d *bincDecDriver) TryDecodeAsNil() bool {
return false return false
} }
func (d *bincDecDriver) IsBuiltinType(rt uintptr) bool { func (d *bincDecDriver) DecodeTime() (t time.Time) {
return rt == timeTypId
}
func (d *bincDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
if rt == timeTypId { if d.bd == bincVdSpecial<<4|bincSpNil {
if d.vd != bincVdTimestamp {
d.d.errorf("Invalid d.vd. Expecting 0x%x. Received: 0x%x", bincVdTimestamp, d.vd)
return
}
tt, err := decodeTime(d.r.readx(int(d.vs)))
if err != nil {
panic(err)
}
var vt *time.Time = v.(*time.Time)
*vt = tt
d.bdRead = false d.bdRead = false
return
} }
if d.vd != bincVdTimestamp {
d.d.errorf("cannot decode time - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
return
}
t, err := bincDecodeTime(d.r.readx(int(d.vs)))
if err != nil {
panic(err)
}
d.bdRead = false
return
} }
func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) { func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) {
@ -405,7 +466,7 @@ func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) {
} else { } else {
l := d.r.readn1() l := d.r.readn1()
if l > 8 { if l > 8 {
d.d.errorf("At most 8 bytes used to represent float. Received: %v bytes", l) d.d.errorf("cannot read float - at most 8 bytes used to represent float - received %v bytes", l)
return return
} }
for i := l; i < 8; i++ { for i := l; i < 8; i++ {
@ -424,7 +485,7 @@ func (d *bincDecDriver) decFloat() (f float64) {
d.decFloatPre(d.vs, 8) d.decFloatPre(d.vs, 8)
f = math.Float64frombits(bigen.Uint64(d.b[0:8])) f = math.Float64frombits(bigen.Uint64(d.b[0:8]))
} else { } else {
d.d.errorf("only float32 and float64 are supported. d.vd: 0x%x, d.vs: 0x%x", d.vd, d.vs) d.d.errorf("read float - only float32 and float64 are supported - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
return return
} }
return return
@ -481,49 +542,38 @@ func (d *bincDecDriver) decCheckInteger() (ui uint64, neg bool) {
neg = true neg = true
ui = 1 ui = 1
} else { } else {
d.d.errorf("numeric decode fails for special value: d.vs: 0x%x", d.vs) d.d.errorf("integer decode fails - invalid special value from descriptor %x-%x/%s",
d.vd, d.vs, bincdesc(d.vd, d.vs))
return return
} }
} else { } else {
d.d.errorf("number can only be decoded from uint or int values. d.bd: 0x%x, d.vd: 0x%x", d.bd, d.vd) d.d.errorf("integer can only be decoded from int/uint. d.bd: 0x%x, d.vd: 0x%x", d.bd, d.vd)
return return
} }
return return
} }
func (d *bincDecDriver) DecodeInt(bitsize uint8) (i int64) { func (d *bincDecDriver) DecodeInt64() (i int64) {
ui, neg := d.decCheckInteger() ui, neg := d.decCheckInteger()
i, overflow := chkOvf.SignedInt(ui) i = chkOvf.SignedIntV(ui)
if overflow {
d.d.errorf("simple: overflow converting %v to signed integer", ui)
return
}
if neg { if neg {
i = -i i = -i
} }
if chkOvf.Int(i, bitsize) {
d.d.errorf("binc: overflow integer: %v", i)
return
}
d.bdRead = false d.bdRead = false
return return
} }
func (d *bincDecDriver) DecodeUint(bitsize uint8) (ui uint64) { func (d *bincDecDriver) DecodeUint64() (ui uint64) {
ui, neg := d.decCheckInteger() ui, neg := d.decCheckInteger()
if neg { if neg {
d.d.errorf("Assigning negative signed value to unsigned type") d.d.errorf("assigning negative signed value to unsigned integer type")
return
}
if chkOvf.Uint(ui, bitsize) {
d.d.errorf("binc: overflow integer: %v", ui)
return return
} }
d.bdRead = false d.bdRead = false
return return
} }
func (d *bincDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { func (d *bincDecDriver) DecodeFloat64() (f float64) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -539,17 +589,14 @@ func (d *bincDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
} else if vs == bincSpNegInf { } else if vs == bincSpNegInf {
return math.Inf(-1) return math.Inf(-1)
} else { } else {
d.d.errorf("Invalid d.vs decoding float where d.vd=bincVdSpecial: %v", d.vs) d.d.errorf("float - invalid special value from descriptor %x-%x/%s",
d.vd, d.vs, bincdesc(d.vd, d.vs))
return return
} }
} else if vd == bincVdFloat { } else if vd == bincVdFloat {
f = d.decFloat() f = d.decFloat()
} else { } else {
f = float64(d.DecodeInt(64)) f = float64(d.DecodeInt64())
}
if chkOverflow32 && chkOvf.Float32(f) {
d.d.errorf("binc: float32 overflow: %v", f)
return
} }
d.bdRead = false d.bdRead = false
return return
@ -565,7 +612,7 @@ func (d *bincDecDriver) DecodeBool() (b bool) {
} else if bd == (bincVdSpecial | bincSpTrue) { } else if bd == (bincVdSpecial | bincSpTrue) {
b = true b = true
} else { } else {
d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd) d.d.errorf("bool - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
return return
} }
d.bdRead = false d.bdRead = false
@ -573,8 +620,11 @@ func (d *bincDecDriver) DecodeBool() (b bool) {
} }
func (d *bincDecDriver) ReadMapStart() (length int) { func (d *bincDecDriver) ReadMapStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
if d.vd != bincVdMap { if d.vd != bincVdMap {
d.d.errorf("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd) d.d.errorf("map - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
return return
} }
length = d.decLen() length = d.decLen()
@ -583,8 +633,11 @@ func (d *bincDecDriver) ReadMapStart() (length int) {
} }
func (d *bincDecDriver) ReadArrayStart() (length int) { func (d *bincDecDriver) ReadArrayStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
if d.vd != bincVdArray { if d.vd != bincVdArray {
d.d.errorf("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd) d.d.errorf("array - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
return return
} }
length = d.decLen() length = d.decLen()
@ -615,7 +668,8 @@ func (d *bincDecDriver) decLenNumber() (v uint64) {
return return
} }
func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool) (bs2 []byte, s string) { func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool) (
bs2 []byte, s string) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -623,7 +677,7 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
d.bdRead = false d.bdRead = false
return return
} }
var slen int = -1 var slen = -1
// var ok bool // var ok bool
switch d.vd { switch d.vd {
case bincVdString, bincVdByteArray: case bincVdString, bincVdByteArray:
@ -632,12 +686,12 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
if d.br { if d.br {
bs2 = d.r.readx(slen) bs2 = d.r.readx(slen)
} else if len(bs) == 0 { } else if len(bs) == 0 {
bs2 = decByteSlice(d.r, slen, d.b[:]) bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, d.b[:])
} else { } else {
bs2 = decByteSlice(d.r, slen, bs) bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, bs)
} }
} else { } else {
bs2 = decByteSlice(d.r, slen, bs) bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, bs)
} }
if withString { if withString {
s = string(bs2) s = string(bs2)
@ -689,15 +743,14 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
// since using symbols, do not store any part of // since using symbols, do not store any part of
// the parameter bs in the map, as it might be a shared buffer. // the parameter bs in the map, as it might be a shared buffer.
// bs2 = decByteSlice(d.r, slen, bs) // bs2 = decByteSlice(d.r, slen, bs)
bs2 = decByteSlice(d.r, slen, nil) bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, nil)
if withString { if withString {
s = string(bs2) s = string(bs2)
} }
d.s = append(d.s, bincDecSymbol{i: symbol, s: s, b: bs2}) d.s = append(d.s, bincDecSymbol{i: symbol, s: s, b: bs2})
} }
default: default:
d.d.errorf("Invalid d.vd. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x", d.d.errorf("string/bytes - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
bincVdString, bincVdByteArray, bincVdSymbol, d.vd)
return return
} }
d.bdRead = false d.bdRead = false
@ -705,18 +758,19 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
} }
func (d *bincDecDriver) DecodeString() (s string) { func (d *bincDecDriver) DecodeString() (s string) {
// DecodeBytes does not accomodate symbols, whose impl stores string version in map. // DecodeBytes does not accommodate symbols, whose impl stores string version in map.
// Use decStringAndBytes directly. // Use decStringAndBytes directly.
// return string(d.DecodeBytes(d.b[:], true, true)) // return string(d.DecodeBytes(d.b[:], true, true))
_, s = d.decStringAndBytes(d.b[:], true, true) _, s = d.decStringAndBytes(d.b[:], true, true)
return return
} }
func (d *bincDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) { func (d *bincDecDriver) DecodeStringAsBytes() (s []byte) {
if isstring { s, _ = d.decStringAndBytes(d.b[:], false, true)
bsOut, _ = d.decStringAndBytes(bs, false, zerocopy) return
return }
}
func (d *bincDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -724,12 +778,16 @@ func (d *bincDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
d.bdRead = false d.bdRead = false
return nil return nil
} }
// check if an "array" of uint8's (see ContainerType for how to infer if an array)
if d.vd == bincVdArray {
bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d)
return
}
var clen int var clen int
if d.vd == bincVdString || d.vd == bincVdByteArray { if d.vd == bincVdString || d.vd == bincVdByteArray {
clen = d.decLen() clen = d.decLen()
} else { } else {
d.d.errorf("Invalid d.vd for bytes. Expecting string:0x%x or bytearray:0x%x. Got: 0x%x", d.d.errorf("bytes - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
bincVdString, bincVdByteArray, d.vd)
return return
} }
d.bdRead = false d.bdRead = false
@ -740,12 +798,12 @@ func (d *bincDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
bs = d.b[:] bs = d.b[:]
} }
} }
return decByteSlice(d.r, clen, bs) return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs)
} }
func (d *bincDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { func (d *bincDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
if xtag > 0xff { if xtag > 0xff {
d.d.errorf("decodeExt: tag must be <= 0xff; got: %v", xtag) d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag)
return return
} }
realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag)) realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag))
@ -768,14 +826,14 @@ func (d *bincDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []b
l := d.decLen() l := d.decLen()
xtag = d.r.readn1() xtag = d.r.readn1()
if verifyTag && xtag != tag { if verifyTag && xtag != tag {
d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", xtag, tag) d.d.errorf("wrong extension tag - got %b, expecting: %v", xtag, tag)
return return
} }
xbs = d.r.readx(l) xbs = d.r.readx(l)
} else if d.vd == bincVdByteArray { } else if d.vd == bincVdByteArray {
xbs = d.DecodeBytes(nil, false, true) xbs = d.DecodeBytes(nil, true)
} else { } else {
d.d.errorf("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.vd) d.d.errorf("ext - expecting extensions or byte array - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
return return
} }
d.bdRead = false d.bdRead = false
@ -787,7 +845,7 @@ func (d *bincDecDriver) DecodeNaked() {
d.readNextBd() d.readNextBd()
} }
n := &d.d.n n := d.d.n
var decodeFurther bool var decodeFurther bool
switch d.vd { switch d.vd {
@ -820,7 +878,7 @@ func (d *bincDecDriver) DecodeNaked() {
n.v = valueTypeInt n.v = valueTypeInt
n.i = int64(-1) // int8(-1) n.i = int64(-1) // int8(-1)
default: default:
d.d.errorf("decodeNaked: Unrecognized special value 0x%x", d.vs) d.d.errorf("cannot infer value - unrecognized special value from descriptor %x-%x/%s", d.vd, d.vs, bincdesc(d.vd, d.vs))
} }
case bincVdSmallInt: case bincVdSmallInt:
n.v = valueTypeUint n.v = valueTypeUint
@ -842,10 +900,10 @@ func (d *bincDecDriver) DecodeNaked() {
n.s = d.DecodeString() n.s = d.DecodeString()
case bincVdByteArray: case bincVdByteArray:
n.v = valueTypeBytes n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false)
case bincVdTimestamp: case bincVdTimestamp:
n.v = valueTypeTimestamp n.v = valueTypeTime
tt, err := decodeTime(d.r.readx(int(d.vs))) tt, err := bincDecodeTime(d.r.readx(int(d.vs)))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -862,7 +920,7 @@ func (d *bincDecDriver) DecodeNaked() {
n.v = valueTypeMap n.v = valueTypeMap
decodeFurther = true decodeFurther = true
default: default:
d.d.errorf("decodeNaked: Unrecognized d.vd: 0x%x", d.vd) d.d.errorf("cannot infer value - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
} }
if !decodeFurther { if !decodeFurther {
@ -892,31 +950,219 @@ func (d *bincDecDriver) DecodeNaked() {
type BincHandle struct { type BincHandle struct {
BasicHandle BasicHandle
binaryEncodingType binaryEncodingType
noElemSeparators
// AsSymbols defines what should be encoded as symbols.
//
// Encoding as symbols can reduce the encoded size significantly.
//
// However, during decoding, each string to be encoded as a symbol must
// be checked to see if it has been seen before. Consequently, encoding time
// will increase if using symbols, because string comparisons has a clear cost.
//
// Values:
// - 0: default: library uses best judgement
// - 1: use symbols
// - 2: do not use symbols
AsSymbols uint8
// AsSymbols: may later on introduce more options ...
// - m: map keys
// - s: struct fields
// - n: none
// - a: all: same as m, s, ...
// _ [1]uint64 // padding
} }
// Name returns the name of the handle: binc
func (h *BincHandle) Name() string { return "binc" }
// SetBytesExt sets an extension
func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{b: ext}) return h.SetExt(rt, tag, &extWrapper{ext, interfaceExtFailer{}})
} }
func (h *BincHandle) newEncDriver(e *Encoder) encDriver { func (h *BincHandle) newEncDriver(e *Encoder) encDriver {
return &bincEncDriver{e: e, w: e.w} return &bincEncDriver{e: e, h: h, w: e.w}
} }
func (h *BincHandle) newDecDriver(d *Decoder) decDriver { func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &bincDecDriver{d: d, h: h, r: d.r, br: d.bytes}
} }
func (e *bincEncDriver) reset() { func (e *bincEncDriver) reset() {
e.w = e.e.w e.w = e.e.w
e.s = 0 e.s = 0
e.c = 0
e.m = nil e.m = nil
} }
func (d *bincDecDriver) reset() { func (d *bincDecDriver) reset() {
d.r = d.d.r d.r, d.br = d.d.r, d.d.bytes
d.s = nil d.s = nil
d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0 d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0
} }
// var timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
// EncodeTime encodes a time.Time as a []byte, including
// information on the instant in time and UTC offset.
//
// Format Description
//
// A timestamp is composed of 3 components:
//
// - secs: signed integer representing seconds since unix epoch
// - nsces: unsigned integer representing fractional seconds as a
// nanosecond offset within secs, in the range 0 <= nsecs < 1e9
// - tz: signed integer representing timezone offset in minutes east of UTC,
// and a dst (daylight savings time) flag
//
// When encoding a timestamp, the first byte is the descriptor, which
// defines which components are encoded and how many bytes are used to
// encode secs and nsecs components. *If secs/nsecs is 0 or tz is UTC, it
// is not encoded in the byte array explicitly*.
//
// Descriptor 8 bits are of the form `A B C DDD EE`:
// A: Is secs component encoded? 1 = true
// B: Is nsecs component encoded? 1 = true
// C: Is tz component encoded? 1 = true
// DDD: Number of extra bytes for secs (range 0-7).
// If A = 1, secs encoded in DDD+1 bytes.
// If A = 0, secs is not encoded, and is assumed to be 0.
// If A = 1, then we need at least 1 byte to encode secs.
// DDD says the number of extra bytes beyond that 1.
// E.g. if DDD=0, then secs is represented in 1 byte.
// if DDD=2, then secs is represented in 3 bytes.
// EE: Number of extra bytes for nsecs (range 0-3).
// If B = 1, nsecs encoded in EE+1 bytes (similar to secs/DDD above)
//
// Following the descriptor bytes, subsequent bytes are:
//
// secs component encoded in `DDD + 1` bytes (if A == 1)
// nsecs component encoded in `EE + 1` bytes (if B == 1)
// tz component encoded in 2 bytes (if C == 1)
//
// secs and nsecs components are integers encoded in a BigEndian
// 2-complement encoding format.
//
// tz component is encoded as 2 bytes (16 bits). Most significant bit 15 to
// Least significant bit 0 are described below:
//
// Timezone offset has a range of -12:00 to +14:00 (ie -720 to +840 minutes).
// Bit 15 = have\_dst: set to 1 if we set the dst flag.
// Bit 14 = dst\_on: set to 1 if dst is in effect at the time, or 0 if not.
// Bits 13..0 = timezone offset in minutes. It is a signed integer in Big Endian format.
//
func bincEncodeTime(t time.Time) []byte {
//t := rv.Interface().(time.Time)
tsecs, tnsecs := t.Unix(), t.Nanosecond()
var (
bd byte
btmp [8]byte
bs [16]byte
i int = 1
)
l := t.Location()
if l == time.UTC {
l = nil
}
if tsecs != 0 {
bd = bd | 0x80
bigen.PutUint64(btmp[:], uint64(tsecs))
f := pruneSignExt(btmp[:], tsecs >= 0)
bd = bd | (byte(7-f) << 2)
copy(bs[i:], btmp[f:])
i = i + (8 - f)
}
if tnsecs != 0 {
bd = bd | 0x40
bigen.PutUint32(btmp[:4], uint32(tnsecs))
f := pruneSignExt(btmp[:4], true)
bd = bd | byte(3-f)
copy(bs[i:], btmp[f:4])
i = i + (4 - f)
}
if l != nil {
bd = bd | 0x20
// Note that Go Libs do not give access to dst flag.
_, zoneOffset := t.Zone()
//zoneName, zoneOffset := t.Zone()
zoneOffset /= 60
z := uint16(zoneOffset)
bigen.PutUint16(btmp[:2], z)
// clear dst flags
bs[i] = btmp[0] & 0x3f
bs[i+1] = btmp[1]
i = i + 2
}
bs[0] = bd
return bs[0:i]
}
// bincDecodeTime decodes a []byte into a time.Time.
func bincDecodeTime(bs []byte) (tt time.Time, err error) {
bd := bs[0]
var (
tsec int64
tnsec uint32
tz uint16
i byte = 1
i2 byte
n byte
)
if bd&(1<<7) != 0 {
var btmp [8]byte
n = ((bd >> 2) & 0x7) + 1
i2 = i + n
copy(btmp[8-n:], bs[i:i2])
//if first bit of bs[i] is set, then fill btmp[0..8-n] with 0xff (ie sign extend it)
if bs[i]&(1<<7) != 0 {
copy(btmp[0:8-n], bsAll0xff)
//for j,k := byte(0), 8-n; j < k; j++ { btmp[j] = 0xff }
}
i = i2
tsec = int64(bigen.Uint64(btmp[:]))
}
if bd&(1<<6) != 0 {
var btmp [4]byte
n = (bd & 0x3) + 1
i2 = i + n
copy(btmp[4-n:], bs[i:i2])
i = i2
tnsec = bigen.Uint32(btmp[:])
}
if bd&(1<<5) == 0 {
tt = time.Unix(tsec, int64(tnsec)).UTC()
return
}
// In stdlib time.Parse, when a date is parsed without a zone name, it uses "" as zone name.
// However, we need name here, so it can be shown when time is printed.
// Zone name is in form: UTC-08:00.
// Note that Go Libs do not give access to dst flag, so we ignore dst bits
i2 = i + 2
tz = bigen.Uint16(bs[i:i2])
// i = i2
// sign extend sign bit into top 2 MSB (which were dst bits):
if tz&(1<<13) == 0 { // positive
tz = tz & 0x3fff //clear 2 MSBs: dst bits
} else { // negative
tz = tz | 0xc000 //set 2 MSBs: dst bits
}
tzint := int16(tz)
if tzint == 0 {
tt = time.Unix(tsec, int64(tnsec)).UTC()
} else {
// For Go Time, do not use a descriptive timezone.
// It's unnecessary, and makes it harder to do a reflect.DeepEqual.
// The Offset already tells what the offset should be, if not on UTC and unknown zone name.
// var zoneName = timeLocUTCName(tzint)
tt = time.Unix(tsec, int64(tnsec)).In(time.FixedZone("", int(tzint)*60))
}
return
}
var _ decDriver = (*bincDecDriver)(nil) var _ decDriver = (*bincDecDriver)(nil)
var _ encDriver = (*bincEncDriver)(nil) var _ encDriver = (*bincEncDriver)(nil)

View File

@ -1,4 +1,4 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
package codec package codec
@ -6,6 +6,7 @@ package codec
import ( import (
"math" "math"
"reflect" "reflect"
"time"
) )
const ( const (
@ -38,6 +39,8 @@ const (
cborBdBreak = 0xff cborBdBreak = 0xff
) )
// These define some in-stream descriptors for
// manual encoding e.g. when doing explicit indefinite-length
const ( const (
CborStreamBytes byte = 0x5f CborStreamBytes byte = 0x5f
CborStreamString = 0x7f CborStreamString = 0x7f
@ -57,15 +60,56 @@ const (
cborBaseSimple = 0xe0 cborBaseSimple = 0xe0
) )
func cbordesc(bd byte) string {
switch bd {
case cborBdNil:
return "nil"
case cborBdFalse:
return "false"
case cborBdTrue:
return "true"
case cborBdFloat16, cborBdFloat32, cborBdFloat64:
return "float"
case cborBdIndefiniteBytes:
return "bytes*"
case cborBdIndefiniteString:
return "string*"
case cborBdIndefiniteArray:
return "array*"
case cborBdIndefiniteMap:
return "map*"
default:
switch {
case bd >= cborBaseUint && bd < cborBaseNegInt:
return "(u)int"
case bd >= cborBaseNegInt && bd < cborBaseBytes:
return "int"
case bd >= cborBaseBytes && bd < cborBaseString:
return "bytes"
case bd >= cborBaseString && bd < cborBaseArray:
return "string"
case bd >= cborBaseArray && bd < cborBaseMap:
return "array"
case bd >= cborBaseMap && bd < cborBaseTag:
return "map"
case bd >= cborBaseTag && bd < cborBaseSimple:
return "ext"
default:
return "unknown"
}
}
}
// ------------------- // -------------------
type cborEncDriver struct { type cborEncDriver struct {
noBuiltInTypes noBuiltInTypes
encNoSeparator encDriverNoopContainerWriter
e *Encoder e *Encoder
w encWriter w encWriter
h *CborHandle h *CborHandle
x [8]byte x [8]byte
// _ [3]uint64 // padding
} }
func (e *cborEncDriver) EncodeNil() { func (e *cborEncDriver) EncodeNil() {
@ -123,6 +167,24 @@ func (e *cborEncDriver) encLen(bd byte, length int) {
e.encUint(uint64(length), bd) e.encUint(uint64(length), bd)
} }
func (e *cborEncDriver) EncodeTime(t time.Time) {
if t.IsZero() {
e.EncodeNil()
} else if e.h.TimeRFC3339 {
e.encUint(0, cborBaseTag)
e.EncodeString(cUTF8, t.Format(time.RFC3339Nano))
} else {
e.encUint(1, cborBaseTag)
t = t.UTC().Round(time.Microsecond)
sec, nsec := t.Unix(), uint64(t.Nanosecond())
if nsec == 0 {
e.EncodeInt(sec)
} else {
e.EncodeFloat64(float64(sec) + float64(nsec)/1e9)
}
}
}
func (e *cborEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) { func (e *cborEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) {
e.encUint(uint64(xtag), cborBaseTag) e.encUint(uint64(xtag), cborBaseTag)
if v := ext.ConvertExt(rv); v == nil { if v := ext.ConvertExt(rv); v == nil {
@ -134,39 +196,89 @@ func (e *cborEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Enco
func (e *cborEncDriver) EncodeRawExt(re *RawExt, en *Encoder) { func (e *cborEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
e.encUint(uint64(re.Tag), cborBaseTag) e.encUint(uint64(re.Tag), cborBaseTag)
if re.Data != nil { // only encodes re.Value (never re.Data)
en.encode(re.Data) // if false && re.Data != nil {
} else if re.Value == nil { // en.encode(re.Data)
e.EncodeNil() // } else if re.Value != nil {
} else { if re.Value != nil {
en.encode(re.Value) en.encode(re.Value)
} else {
e.EncodeNil()
} }
} }
func (e *cborEncDriver) EncodeArrayStart(length int) { func (e *cborEncDriver) WriteArrayStart(length int) {
e.encLen(cborBaseArray, length) if e.h.IndefiniteLength {
e.w.writen1(cborBdIndefiniteArray)
} else {
e.encLen(cborBaseArray, length)
}
} }
func (e *cborEncDriver) EncodeMapStart(length int) { func (e *cborEncDriver) WriteMapStart(length int) {
e.encLen(cborBaseMap, length) if e.h.IndefiniteLength {
e.w.writen1(cborBdIndefiniteMap)
} else {
e.encLen(cborBaseMap, length)
}
}
func (e *cborEncDriver) WriteMapEnd() {
if e.h.IndefiniteLength {
e.w.writen1(cborBdBreak)
}
}
func (e *cborEncDriver) WriteArrayEnd() {
if e.h.IndefiniteLength {
e.w.writen1(cborBdBreak)
}
} }
func (e *cborEncDriver) EncodeString(c charEncoding, v string) { func (e *cborEncDriver) EncodeString(c charEncoding, v string) {
e.encLen(cborBaseString, len(v)) e.encStringBytesS(cborBaseString, v)
e.w.writestr(v)
}
func (e *cborEncDriver) EncodeSymbol(v string) {
e.EncodeString(c_UTF8, v)
} }
func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) { func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
if c == c_RAW { if v == nil {
e.encLen(cborBaseBytes, len(v)) e.EncodeNil()
} else if c == cRAW {
e.encStringBytesS(cborBaseBytes, stringView(v))
} else { } else {
e.encLen(cborBaseString, len(v)) e.encStringBytesS(cborBaseString, stringView(v))
}
}
func (e *cborEncDriver) encStringBytesS(bb byte, v string) {
if e.h.IndefiniteLength {
if bb == cborBaseBytes {
e.w.writen1(cborBdIndefiniteBytes)
} else {
e.w.writen1(cborBdIndefiniteString)
}
blen := len(v) / 4
if blen == 0 {
blen = 64
} else if blen > 1024 {
blen = 1024
}
for i := 0; i < len(v); {
var v2 string
i2 := i + blen
if i2 < len(v) {
v2 = v[i:i2]
} else {
v2 = v[i:]
}
e.encLen(bb, len(v2))
e.w.writestr(v2)
i = i2
}
e.w.writen1(cborBdBreak)
} else {
e.encLen(bb, len(v))
e.w.writestr(v)
} }
e.w.writeb(v)
} }
// ---------------------- // ----------------------
@ -175,12 +287,13 @@ type cborDecDriver struct {
d *Decoder d *Decoder
h *CborHandle h *CborHandle
r decReader r decReader
b [scratchByteArrayLen]byte
br bool // bytes reader br bool // bytes reader
bdRead bool bdRead bool
bd byte bd byte
noBuiltInTypes noBuiltInTypes
decNoSeparator // decNoSeparator
decDriverNoopContainerReader
// _ [3]uint64 // padding
} }
func (d *cborDecDriver) readNextBd() { func (d *cborDecDriver) readNextBd() {
@ -188,7 +301,17 @@ func (d *cborDecDriver) readNextBd() {
d.bdRead = true d.bdRead = true
} }
func (d *cborDecDriver) uncacheRead() {
if d.bdRead {
d.r.unreadn1()
d.bdRead = false
}
}
func (d *cborDecDriver) ContainerType() (vt valueType) { func (d *cborDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
if d.bd == cborBdNil { if d.bd == cborBdNil {
return valueTypeNil return valueTypeNil
} else if d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) { } else if d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) {
@ -199,9 +322,10 @@ func (d *cborDecDriver) ContainerType() (vt valueType) {
return valueTypeArray return valueTypeArray
} else if d.bd == cborBdIndefiniteMap || (d.bd >= cborBaseMap && d.bd < cborBaseTag) { } else if d.bd == cborBdIndefiniteMap || (d.bd >= cborBaseMap && d.bd < cborBaseTag) {
return valueTypeMap return valueTypeMap
} else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
} }
// else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
// }
return valueTypeUnset return valueTypeUnset
} }
@ -242,7 +366,7 @@ func (d *cborDecDriver) decUint() (ui uint64) {
} else if v == 0x1b { } else if v == 0x1b {
ui = uint64(bigen.Uint64(d.r.readx(8))) ui = uint64(bigen.Uint64(d.r.readx(8)))
} else { } else {
d.d.errorf("decUint: Invalid descriptor: %v", d.bd) d.d.errorf("invalid descriptor decoding uint: %x/%s", d.bd, cbordesc(d.bd))
return return
} }
} }
@ -258,52 +382,36 @@ func (d *cborDecDriver) decCheckInteger() (neg bool) {
} else if major == cborMajorNegInt { } else if major == cborMajorNegInt {
neg = true neg = true
} else { } else {
d.d.errorf("invalid major: %v (bd: %v)", major, d.bd) d.d.errorf("not an integer - invalid major %v from descriptor %x/%s", major, d.bd, cbordesc(d.bd))
return return
} }
return return
} }
func (d *cborDecDriver) DecodeInt(bitsize uint8) (i int64) { func (d *cborDecDriver) DecodeInt64() (i int64) {
neg := d.decCheckInteger() neg := d.decCheckInteger()
ui := d.decUint() ui := d.decUint()
// check if this number can be converted to an int without overflow // check if this number can be converted to an int without overflow
var overflow bool
if neg { if neg {
if i, overflow = chkOvf.SignedInt(ui + 1); overflow { i = -(chkOvf.SignedIntV(ui + 1))
d.d.errorf("cbor: overflow converting %v to signed integer", ui+1)
return
}
i = -i
} else { } else {
if i, overflow = chkOvf.SignedInt(ui); overflow { i = chkOvf.SignedIntV(ui)
d.d.errorf("cbor: overflow converting %v to signed integer", ui)
return
}
}
if chkOvf.Int(i, bitsize) {
d.d.errorf("cbor: overflow integer: %v", i)
return
} }
d.bdRead = false d.bdRead = false
return return
} }
func (d *cborDecDriver) DecodeUint(bitsize uint8) (ui uint64) { func (d *cborDecDriver) DecodeUint64() (ui uint64) {
if d.decCheckInteger() { if d.decCheckInteger() {
d.d.errorf("Assigning negative signed value to unsigned type") d.d.errorf("assigning negative signed value to unsigned type")
return return
} }
ui = d.decUint() ui = d.decUint()
if chkOvf.Uint(ui, bitsize) {
d.d.errorf("cbor: overflow integer: %v", ui)
return
}
d.bdRead = false d.bdRead = false
return return
} }
func (d *cborDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { func (d *cborDecDriver) DecodeFloat64() (f float64) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -314,13 +422,9 @@ func (d *cborDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
} else if bd == cborBdFloat64 { } else if bd == cborBdFloat64 {
f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
} else if bd >= cborBaseUint && bd < cborBaseBytes { } else if bd >= cborBaseUint && bd < cborBaseBytes {
f = float64(d.DecodeInt(64)) f = float64(d.DecodeInt64())
} else { } else {
d.d.errorf("Float only valid from float16/32/64: Invalid descriptor: %v", bd) d.d.errorf("float only valid from float16/32/64 - invalid descriptor %x/%s", bd, cbordesc(bd))
return
}
if chkOverflow32 && chkOvf.Float32(f) {
d.d.errorf("cbor: float32 overflow: %v", f)
return return
} }
d.bdRead = false d.bdRead = false
@ -336,7 +440,7 @@ func (d *cborDecDriver) DecodeBool() (b bool) {
b = true b = true
} else if bd == cborBdFalse { } else if bd == cborBdFalse {
} else { } else {
d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd) d.d.errorf("not bool - %s %x/%s", msgBadDesc, d.bd, cbordesc(d.bd))
return return
} }
d.bdRead = false d.bdRead = false
@ -344,6 +448,9 @@ func (d *cborDecDriver) DecodeBool() (b bool) {
} }
func (d *cborDecDriver) ReadMapStart() (length int) { func (d *cborDecDriver) ReadMapStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false d.bdRead = false
if d.bd == cborBdIndefiniteMap { if d.bd == cborBdIndefiniteMap {
return -1 return -1
@ -352,6 +459,9 @@ func (d *cborDecDriver) ReadMapStart() (length int) {
} }
func (d *cborDecDriver) ReadArrayStart() (length int) { func (d *cborDecDriver) ReadArrayStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false d.bdRead = false
if d.bd == cborBdIndefiniteArray { if d.bd == cborBdIndefiniteArray {
return -1 return -1
@ -370,7 +480,8 @@ func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte {
break break
} }
if major := d.bd >> 5; major != cborMajorBytes && major != cborMajorText { if major := d.bd >> 5; major != cborMajorBytes && major != cborMajorText {
d.d.errorf("cbor: expect bytes or string major type in indefinite string/bytes; got: %v, byte: %v", major, d.bd) d.d.errorf("expect bytes/string major type in indefinite string/bytes;"+
" got major %v from descriptor %x/%x", major, d.bd, cbordesc(d.bd))
return nil return nil
} }
n := d.decLen() n := d.decLen()
@ -391,7 +502,7 @@ func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte {
return bs return bs
} }
func (d *cborDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) { func (d *cborDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -400,25 +511,84 @@ func (d *cborDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
return nil return nil
} }
if d.bd == cborBdIndefiniteBytes || d.bd == cborBdIndefiniteString { if d.bd == cborBdIndefiniteBytes || d.bd == cborBdIndefiniteString {
d.bdRead = false
if bs == nil { if bs == nil {
return d.decAppendIndefiniteBytes(nil) if zerocopy {
return d.decAppendIndefiniteBytes(d.d.b[:0])
}
return d.decAppendIndefiniteBytes(zeroByteSlice)
} }
return d.decAppendIndefiniteBytes(bs[:0]) return d.decAppendIndefiniteBytes(bs[:0])
} }
// check if an "array" of uint8's (see ContainerType for how to infer if an array)
if d.bd == cborBdIndefiniteArray || (d.bd >= cborBaseArray && d.bd < cborBaseMap) {
bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d)
return
}
clen := d.decLen() clen := d.decLen()
d.bdRead = false d.bdRead = false
if zerocopy { if zerocopy {
if d.br { if d.br {
return d.r.readx(clen) return d.r.readx(clen)
} else if len(bs) == 0 { } else if len(bs) == 0 {
bs = d.b[:] bs = d.d.b[:]
} }
} }
return decByteSlice(d.r, clen, bs) return decByteSlice(d.r, clen, d.h.MaxInitLen, bs)
} }
func (d *cborDecDriver) DecodeString() (s string) { func (d *cborDecDriver) DecodeString() (s string) {
return string(d.DecodeBytes(d.b[:], true, true)) return string(d.DecodeBytes(d.d.b[:], true))
}
func (d *cborDecDriver) DecodeStringAsBytes() (s []byte) {
return d.DecodeBytes(d.d.b[:], true)
}
func (d *cborDecDriver) DecodeTime() (t time.Time) {
if !d.bdRead {
d.readNextBd()
}
if d.bd == cborBdNil || d.bd == cborBdUndefined {
d.bdRead = false
return
}
xtag := d.decUint()
d.bdRead = false
return d.decodeTime(xtag)
}
func (d *cborDecDriver) decodeTime(xtag uint64) (t time.Time) {
if !d.bdRead {
d.readNextBd()
}
switch xtag {
case 0:
var err error
if t, err = time.Parse(time.RFC3339, stringView(d.DecodeStringAsBytes())); err != nil {
d.d.errorv(err)
}
case 1:
// decode an int64 or a float, and infer time.Time from there.
// for floats, round to microseconds, as that is what is guaranteed to fit well.
switch {
case d.bd == cborBdFloat16, d.bd == cborBdFloat32:
f1, f2 := math.Modf(d.DecodeFloat64())
t = time.Unix(int64(f1), int64(f2*1e9))
case d.bd == cborBdFloat64:
f1, f2 := math.Modf(d.DecodeFloat64())
t = time.Unix(int64(f1), int64(f2*1e9))
case d.bd >= cborBaseUint && d.bd < cborBaseNegInt,
d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
t = time.Unix(d.DecodeInt64(), 0)
default:
d.d.errorf("time.Time can only be decoded from a number (or RFC3339 string)")
}
default:
d.d.errorf("invalid tag for time.Time - expecting 0 or 1, got 0x%x", xtag)
}
t = t.UTC().Round(time.Microsecond)
return
} }
func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
@ -449,7 +619,7 @@ func (d *cborDecDriver) DecodeNaked() {
d.readNextBd() d.readNextBd()
} }
n := &d.d.n n := d.d.n
var decodeFurther bool var decodeFurther bool
switch d.bd { switch d.bd {
@ -461,15 +631,12 @@ func (d *cborDecDriver) DecodeNaked() {
case cborBdTrue: case cborBdTrue:
n.v = valueTypeBool n.v = valueTypeBool
n.b = true n.b = true
case cborBdFloat16, cborBdFloat32: case cborBdFloat16, cborBdFloat32, cborBdFloat64:
n.v = valueTypeFloat n.v = valueTypeFloat
n.f = d.DecodeFloat(true) n.f = d.DecodeFloat64()
case cborBdFloat64:
n.v = valueTypeFloat
n.f = d.DecodeFloat(false)
case cborBdIndefiniteBytes: case cborBdIndefiniteBytes:
n.v = valueTypeBytes n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false)
case cborBdIndefiniteString: case cborBdIndefiniteString:
n.v = valueTypeString n.v = valueTypeString
n.s = d.DecodeString() n.s = d.DecodeString()
@ -484,17 +651,17 @@ func (d *cborDecDriver) DecodeNaked() {
case d.bd >= cborBaseUint && d.bd < cborBaseNegInt: case d.bd >= cborBaseUint && d.bd < cborBaseNegInt:
if d.h.SignedInteger { if d.h.SignedInteger {
n.v = valueTypeInt n.v = valueTypeInt
n.i = d.DecodeInt(64) n.i = d.DecodeInt64()
} else { } else {
n.v = valueTypeUint n.v = valueTypeUint
n.u = d.DecodeUint(64) n.u = d.DecodeUint64()
} }
case d.bd >= cborBaseNegInt && d.bd < cborBaseBytes: case d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
n.v = valueTypeInt n.v = valueTypeInt
n.i = d.DecodeInt(64) n.i = d.DecodeInt64()
case d.bd >= cborBaseBytes && d.bd < cborBaseString: case d.bd >= cborBaseBytes && d.bd < cborBaseString:
n.v = valueTypeBytes n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false)
case d.bd >= cborBaseString && d.bd < cborBaseArray: case d.bd >= cborBaseString && d.bd < cborBaseArray:
n.v = valueTypeString n.v = valueTypeString
n.s = d.DecodeString() n.s = d.DecodeString()
@ -508,6 +675,11 @@ func (d *cborDecDriver) DecodeNaked() {
n.v = valueTypeExt n.v = valueTypeExt
n.u = d.decUint() n.u = d.decUint()
n.l = nil n.l = nil
if n.u == 0 || n.u == 1 {
d.bdRead = false
n.v = valueTypeTime
n.t = d.decodeTime(n.u)
}
// d.bdRead = false // d.bdRead = false
// d.d.decode(&re.Value) // handled by decode itself. // d.d.decode(&re.Value) // handled by decode itself.
// decodeFurther = true // decodeFurther = true
@ -538,30 +710,29 @@ func (d *cborDecDriver) DecodeNaked() {
// //
// None of the optional extensions (with tags) defined in the spec are supported out-of-the-box. // None of the optional extensions (with tags) defined in the spec are supported out-of-the-box.
// Users can implement them as needed (using SetExt), including spec-documented ones: // Users can implement them as needed (using SetExt), including spec-documented ones:
// - timestamp, BigNum, BigFloat, Decimals, Encoded Text (e.g. URL, regexp, base64, MIME Message), etc. // - timestamp, BigNum, BigFloat, Decimals,
// // - Encoded Text (e.g. URL, regexp, base64, MIME Message), etc.
// To encode with indefinite lengths (streaming), users will use
// (Must)Encode methods of *Encoder, along with writing CborStreamXXX constants.
//
// For example, to encode "one-byte" as an indefinite length string:
// var buf bytes.Buffer
// e := NewEncoder(&buf, new(CborHandle))
// buf.WriteByte(CborStreamString)
// e.MustEncode("one-")
// e.MustEncode("byte")
// buf.WriteByte(CborStreamBreak)
// encodedBytes := buf.Bytes()
// var vv interface{}
// NewDecoderBytes(buf.Bytes(), new(CborHandle)).MustDecode(&vv)
// // Now, vv contains the same string "one-byte"
//
type CborHandle struct { type CborHandle struct {
binaryEncodingType binaryEncodingType
noElemSeparators
BasicHandle BasicHandle
// IndefiniteLength=true, means that we encode using indefinitelength
IndefiniteLength bool
// TimeRFC3339 says to encode time.Time using RFC3339 format.
// If unset, we encode time.Time using seconds past epoch.
TimeRFC3339 bool
// _ [1]uint64 // padding
} }
// Name returns the name of the handle: cbor
func (h *CborHandle) Name() string { return "cbor" }
// SetInterfaceExt sets an extension
func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{i: ext}) return h.SetExt(rt, tag, &extWrapper{bytesExtFailer{}, ext})
} }
func (h *CborHandle) newEncDriver(e *Encoder) encDriver { func (h *CborHandle) newEncDriver(e *Encoder) encDriver {
@ -569,7 +740,7 @@ func (h *CborHandle) newEncDriver(e *Encoder) encDriver {
} }
func (h *CborHandle) newDecDriver(d *Decoder) decDriver { func (h *CborHandle) newDecDriver(d *Decoder) decDriver {
return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &cborDecDriver{d: d, h: h, r: d.r, br: d.bytes}
} }
func (e *cborEncDriver) reset() { func (e *cborEncDriver) reset() {
@ -577,7 +748,7 @@ func (e *cborEncDriver) reset() {
} }
func (d *cborDecDriver) reset() { func (d *cborDecDriver) reset() {
d.r = d.d.r d.r, d.br = d.d.r, d.d.bytes
d.bd, d.bdRead = 0, false d.bd, d.bdRead = 0, false
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,10 +3,7 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
// ************************************************************ // Code generated from fast-path.go.tmpl - DO NOT EDIT.
// DO NOT EDIT.
// THIS FILE IS AUTO-GENERATED from fast-path.go.tmpl
// ************************************************************
package codec package codec
@ -18,19 +15,19 @@ package codec
// This file can be omitted without causing a build failure. // This file can be omitted without causing a build failure.
// //
// The advantage of fast paths is: // The advantage of fast paths is:
// - Many calls bypass reflection altogether // - Many calls bypass reflection altogether
// //
// Currently support // Currently support
// - slice of all builtin types, // - slice of all builtin types,
// - map of all builtin types to string or interface value // - map of all builtin types to string or interface value
// - symetrical maps of all builtin types (e.g. str-str, uint8-uint8) // - symmetrical maps of all builtin types (e.g. str-str, uint8-uint8)
// This should provide adequate "typical" implementations. // This should provide adequate "typical" implementations.
// //
// Note that fast track decode functions must handle values for which an address cannot be obtained. // Note that fast track decode functions must handle values for which an address cannot be obtained.
// For example: // For example:
// m2 := map[string]int{} // m2 := map[string]int{}
// p2 := []interface{}{m2} // p2 := []interface{}{m2}
// // decoding into p2 will bomb if fast track functions do not treat like unaddressable. // // decoding into p2 will bomb if fast track functions do not treat like unaddressable.
// //
import ( import (
@ -38,8 +35,7 @@ import (
"sort" "sort"
) )
const fastpathCheckNilFalse = false // for reflect const fastpathEnabled = true
const fastpathCheckNilTrue = true // for type switch
type fastpathT struct {} type fastpathT struct {}
@ -48,8 +44,8 @@ var fastpathTV fastpathT
type fastpathE struct { type fastpathE struct {
rtid uintptr rtid uintptr
rt reflect.Type rt reflect.Type
encfn func(*encFnInfo, reflect.Value) encfn func(*Encoder, *codecFnInfo, reflect.Value)
decfn func(*decFnInfo, reflect.Value) decfn func(*Decoder, *codecFnInfo, reflect.Value)
} }
type fastpathA [{{ .FastpathLen }}]fastpathE type fastpathA [{{ .FastpathLen }}]fastpathE
@ -81,23 +77,22 @@ var fastpathAV fastpathA
// due to possible initialization loop error, make fastpath in an init() // due to possible initialization loop error, make fastpath in an init()
func init() { func init() {
if !fastpathEnabled {
return
}
i := 0 i := 0
fn := func(v interface{}, fe func(*encFnInfo, reflect.Value), fd func(*decFnInfo, reflect.Value)) (f fastpathE) { fn := func(v interface{},
fe func(*Encoder, *codecFnInfo, reflect.Value),
fd func(*Decoder, *codecFnInfo, reflect.Value)) (f fastpathE) {
xrt := reflect.TypeOf(v) xrt := reflect.TypeOf(v)
xptr := reflect.ValueOf(xrt).Pointer() xptr := rt2id(xrt)
fastpathAV[i] = fastpathE{xptr, xrt, fe, fd} fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
i++ i++
return return
} }
{{/* do not register []uint8 in fast-path */}}
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
fn([]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}} fn([]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}} fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
sort.Sort(fastpathAslice(fastpathAV[:])) sort.Sort(fastpathAslice(fastpathAV[:]))
} }
@ -106,128 +101,150 @@ func init() {
// -- -- fast path type switch // -- -- fast path type switch
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
if !fastpathEnabled {
return false
}
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:{{else}} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
case map[{{ .MapKey }}]{{ .Elem }}:{{end}} case []{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e){{if not .MapKey }} fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
case *[]{{ .Elem }}:{{else}} case *[]{{ .Elem }}:
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}} fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/*
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) */}}{{end}}{{end}}{{end}}{{end}}
{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
case map[{{ .MapKey }}]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
case *map[{{ .MapKey }}]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/*
*/}}{{end}}{{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release) _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
return false return false
} }
return true return true
} }
{{/*
**** removing this block, as they are never called directly ****
**** removing this block, as they are never called directly ****
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
if !fastpathEnabled {
return false
}
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}: case []{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
case *[]{{ .Elem }}: case *[]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release) _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
return false return false
} }
return true return true
} }
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
if !fastpathEnabled {
return false
}
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if .MapKey }} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
case map[{{ .MapKey }}]{{ .Elem }}: case map[{{ .MapKey }}]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
case *map[{{ .MapKey }}]{{ .Elem }}: case *map[{{ .MapKey }}]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release) _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
return false return false
} }
return true return true
} }
**** removing this block, as they are never called directly ****
**** removing this block, as they are never called directly ****
*/}}
// -- -- fast path functions // -- -- fast path functions
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
if f.ti.mbs { if f.ti.mbs {
fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e) fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv2i(rv).([]{{ .Elem }}), e)
} else { } else {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).([]{{ .Elem }}), e)
} }
} }
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) { func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, e *Encoder) {
ee := e.e if v == nil { e.e.EncodeNil(); return }
cr := e.cr ee, esep := e.e, e.hh.hasElemSeparators()
if checkNil && v == nil { ee.WriteArrayStart(len(v))
ee.EncodeNil() if esep {
return for _, v2 := range v {
} ee.WriteArrayElem()
ee.EncodeArrayStart(len(v)) {{ encmd .Elem "v2"}}
}
} else {
for _, v2 := range v {
{{ encmd .Elem "v2"}}
}
} {{/*
for _, v2 := range v { for _, v2 := range v {
if cr != nil { cr.sendContainerState(containerArrayElem) } if esep { ee.WriteArrayElem() }
{{ encmd .Elem "v2"}} {{ encmd .Elem "v2"}}
} } */}}
if cr != nil { cr.sendContainerState(containerArrayEnd) }{{/* ee.EncodeEnd() */}} ee.WriteArrayEnd()
} }
func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Encoder) {
func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) { ee, esep := e.e, e.hh.hasElemSeparators()
ee := e.e
cr := e.cr
if checkNil && v == nil {
ee.EncodeNil()
return
}
if len(v)%2 == 1 { if len(v)%2 == 1 {
e.errorf("mapBySlice requires even slice length, but got %v", len(v)) e.errorf("mapBySlice requires even slice length, but got %v", len(v))
return return
} }
ee.EncodeMapStart(len(v) / 2) ee.WriteMapStart(len(v) / 2)
for j, v2 := range v { if esep {
if cr != nil { for j, v2 := range v {
if j%2 == 0 { if j%2 == 0 {
cr.sendContainerState(containerMapKey) ee.WriteMapElemKey()
} else { } else {
cr.sendContainerState(containerMapValue) ee.WriteMapElemValue()
}
{{ encmd .Elem "v2"}}
}
} else {
for _, v2 := range v {
{{ encmd .Elem "v2"}}
}
} {{/*
for j, v2 := range v {
if esep {
if j%2 == 0 {
ee.WriteMapElemKey()
} else {
ee.WriteMapElemValue()
} }
} }
{{ encmd .Elem "v2"}} {{ encmd .Elem "v2"}}
} } */}}
if cr != nil { cr.sendContainerState(containerMapEnd) } ee.WriteMapEnd()
} }
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) { fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), e)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}), fastpathCheckNilFalse, f.e)
} }
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) { func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, e *Encoder) {
ee := e.e if v == nil { e.e.EncodeNil(); return }
cr := e.cr ee, esep := e.e, e.hh.hasElemSeparators()
if checkNil && v == nil { ee.WriteMapStart(len(v))
ee.EncodeNil() if e.h.Canonical {
return
}
ee.EncodeMapStart(len(v))
{{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
{{end}}if e.h.Canonical {
{{if eq .MapKey "interface{}"}}{{/* out of band {{if eq .MapKey "interface{}"}}{{/* out of band
*/}}var mksv []byte = make([]byte, 0, len(v)*16) // temporary byte slice for the encoding */}}var mksv []byte = make([]byte, 0, len(v)*16) // temporary byte slice for the encoding
e2 := NewEncoderBytes(&mksv, e.hh) e2 := NewEncoderBytes(&mksv, e.hh)
@ -243,66 +260,126 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
i++ i++
} }
sort.Sort(bytesISlice(v2)) sort.Sort(bytesISlice(v2))
if esep {
for j := range v2 {
ee.WriteMapElemKey()
e.asis(v2[j].v)
ee.WriteMapElemValue()
e.encode(v[v2[j].i])
}
} else {
for j := range v2 {
e.asis(v2[j].v)
e.encode(v[v2[j].i])
}
} {{/*
for j := range v2 { for j := range v2 {
if cr != nil { cr.sendContainerState(containerMapKey) } if esep { ee.WriteMapElemKey() }
e.asis(v2[j].v) e.asis(v2[j].v)
if cr != nil { cr.sendContainerState(containerMapValue) } if esep { ee.WriteMapElemValue() }
e.encode(v[v2[j].i]) e.encode(v[v2[j].i])
} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v)) } */}} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
var i int var i int
for k, _ := range v { for k, _ := range v {
v2[i] = {{ $x }}(k) v2[i] = {{ $x }}(k)
i++ i++
} }
sort.Sort({{ sorttype .MapKey false}}(v2)) sort.Sort({{ sorttype .MapKey false}}(v2))
if esep {
for _, k2 := range v2 {
ee.WriteMapElemKey()
{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
ee.WriteMapElemValue()
{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
}
} else {
for _, k2 := range v2 {
{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
}
} {{/*
for _, k2 := range v2 { for _, k2 := range v2 {
if cr != nil { cr.sendContainerState(containerMapKey) } if esep { ee.WriteMapElemKey() }
{{if eq .MapKey "string"}}if asSymbols { {{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
ee.EncodeSymbol(k2) if esep { ee.WriteMapElemValue() }
} else {
ee.EncodeString(c_UTF8, k2)
}{{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }} {{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
} {{end}} } */}} {{end}}
} else { } else {
if esep {
for k2, v2 := range v {
ee.WriteMapElemKey()
{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
ee.WriteMapElemValue()
{{ encmd .Elem "v2"}}
}
} else {
for k2, v2 := range v {
{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
{{ encmd .Elem "v2"}}
}
} {{/*
for k2, v2 := range v { for k2, v2 := range v {
if cr != nil { cr.sendContainerState(containerMapKey) } if esep { ee.WriteMapElemKey() }
{{if eq .MapKey "string"}}if asSymbols { {{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
ee.EncodeSymbol(k2) if esep { ee.WriteMapElemValue() }
} else {
ee.EncodeString(c_UTF8, k2)
}{{else}}{{ encmd .MapKey "k2"}}{{end}}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ encmd .Elem "v2"}} {{ encmd .Elem "v2"}}
} } */}}
} }
if cr != nil { cr.sendContainerState(containerMapEnd) }{{/* ee.EncodeEnd() */}} ee.WriteMapEnd()
} }
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
// -- decode // -- decode
// -- -- fast path type switch // -- -- fast path type switch
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
if !fastpathEnabled { var changed bool
switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
case []{{ .Elem }}:
var v2 []{{ .Elem }}
v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d)
if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) {
copy(v, v2)
}
case *[]{{ .Elem }}:
var v2 []{{ .Elem }}
v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
if changed {
*v = v2
}{{/*
*/}}{{end}}{{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}{{/*
// maps only change if nil, and in that case, there's no point copying
*/}}
case map[{{ .MapKey }}]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d)
case *map[{{ .MapKey }}]{{ .Elem }}:
var v2 map[{{ .MapKey }}]{{ .Elem }}
v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
if changed {
*v = v2
}{{/*
*/}}{{end}}{{end}}{{end}}
default:
_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
return false return false
} }
return true
}
func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:{{else}} case *[]{{ .Elem }}:
case map[{{ .MapKey }}]{{ .Elem }}:{{end}} *v = nil {{/*
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, d){{if not .MapKey }} */}}{{end}}{{end}}{{end}}
case *[]{{ .Elem }}:{{else}} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}} case *map[{{ .MapKey }}]{{ .Elem }}:
v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, fastpathCheckNilFalse, true, d) *v = nil {{/*
if changed2 { */}}{{end}}{{end}}{{end}}
*v = v2
}
{{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release) _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
return false return false
} }
return true return true
@ -316,225 +393,152 @@ Slices can change if they
- are addressable (from a ptr) - are addressable (from a ptr)
- are settable (e.g. contained in an interface{}) - are settable (e.g. contained in an interface{})
*/}} */}}
func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) { func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
array := f.seq == seqTypeArray if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr {
if !array && rv.CanAddr() { {{/* // CanSet => CanAddr + Exported */}} vp := rv2i(rv).(*[]{{ .Elem }})
vp := rv.Addr().Interface().(*[]{{ .Elem }}) v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, !array, d)
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, !array, f.d) if changed { *vp = v }
if changed {
*vp = v
}
} else { } else {
v := rv.Interface().([]{{ .Elem }}) v := rv2i(rv).([]{{ .Elem }})
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d) v2, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, !array, d)
if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) {
copy(v, v2)
}
} }
} }
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, d *Decoder) {
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, checkNil bool, d *Decoder) { v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d)
v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d) if changed { *vp = v }
if changed {
*vp = v
}
} }
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) { func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
dd := d.d dd := d.d{{/*
{{/* // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() */}} // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil()
if checkNil && dd.TryDecodeAsNil() { */}}
if v != nil {
changed = true
}
return nil, changed
}
slh, containerLenS := d.decSliceHelperStart() slh, containerLenS := d.decSliceHelperStart()
if containerLenS == 0 { if containerLenS == 0 {
if canChange { if canChange {
if v == nil { if v == nil { v = []{{ .Elem }}{} } else if len(v) != 0 { v = v[:0] }
v = []{{ .Elem }}{}
} else if len(v) != 0 {
v = v[:0]
}
changed = true changed = true
} }
slh.End() slh.End()
return v, changed return v, changed
} }
hasLen := containerLenS > 0
if containerLenS > 0 { var xlen int
x2read := containerLenS if hasLen && canChange {
var xtrunc bool
if containerLenS > cap(v) { if containerLenS > cap(v) {
if canChange { {{/* xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
// fast-path is for "basic" immutable types, so no need to copy them over if xlen <= cap(v) {
// s := make([]{{ .Elem }}, decInferLen(containerLenS, d.h.MaxInitLen)) v = v[:xlen]
// copy(s, v[:cap(v)])
// v = s */}}
var xlen int
xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
if xtrunc {
if xlen <= cap(v) {
v = v[:xlen]
} else {
v = make([]{{ .Elem }}, xlen)
}
} else {
v = make([]{{ .Elem }}, xlen)
}
changed = true
} else { } else {
d.arrayCannotExpand(len(v), containerLenS) v = make([]{{ .Elem }}, xlen)
} }
x2read = len(v) changed = true
} else if containerLenS != len(v) { } else if containerLenS != len(v) {
if canChange { v = v[:containerLenS]
v = v[:containerLenS]
changed = true
}
} {{/* // all checks done. cannot go past len. */}}
j := 0
for ; j < x2read; j++ {
slh.ElemContainerState(j)
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
}
if xtrunc { {{/* // means canChange=true, changed=true already. */}}
for ; j < containerLenS; j++ {
v = append(v, {{ zerocmd .Elem }})
slh.ElemContainerState(j)
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
}
} else if !canChange {
for ; j < containerLenS; j++ {
slh.ElemContainerState(j)
d.swallow()
}
}
} else {
breakFound := dd.CheckBreak() {{/* check break first, so we can initialize v with a capacity of 4 if necessary */}}
if breakFound {
if canChange {
if v == nil {
v = []{{ .Elem }}{}
} else if len(v) != 0 {
v = v[:0]
}
changed = true
}
slh.End()
return v, changed
}
if cap(v) == 0 {
v = make([]{{ .Elem }}, 1, 4)
changed = true
}
j := 0
for ; !breakFound; j++ {
if j >= len(v) {
if canChange {
v = append(v, {{ zerocmd .Elem }})
changed = true
} else {
d.arrayCannotExpand(len(v), j+1)
}
}
slh.ElemContainerState(j)
if j < len(v) { {{/* // all checks done. cannot go past len. */}}
{{ if eq .Elem "interface{}" }}d.decode(&v[j])
{{ else }}v[j] = {{ decmd .Elem }}{{ end }}
} else {
d.swallow()
}
breakFound = dd.CheckBreak()
}
if canChange && j < len(v) {
v = v[:j]
changed = true changed = true
} }
} }
slh.End() j := 0
for ; (hasLen && j < containerLenS) || !(hasLen || dd.CheckBreak()); j++ {
if j == 0 && len(v) == 0 && canChange {
if hasLen {
xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
} else {
xlen = 8
}
v = make([]{{ .Elem }}, xlen)
changed = true
}
// if indefinite, etc, then expand the slice if necessary
var decodeIntoBlank bool
if j >= len(v) {
if canChange {
v = append(v, {{ zerocmd .Elem }})
changed = true
} else {
d.arrayCannotExpand(len(v), j+1)
decodeIntoBlank = true
}
}
slh.ElemContainerState(j)
if decodeIntoBlank {
d.swallow()
} else if dd.TryDecodeAsNil() {
v[j] = {{ zerocmd .Elem }}
} else {
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
}
}
if canChange {
if j < len(v) {
v = v[:j]
changed = true
} else if j == 0 && v == nil {
v = make([]{{ .Elem }}, 0)
changed = true
}
}
slh.End()
return v, changed return v, changed
} }
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
{{/* {{/*
Maps can change if they are Maps can change if they are
- addressable (from a ptr) - addressable (from a ptr)
- settable (e.g. contained in an interface{}) - settable (e.g. contained in an interface{})
*/}} */}}
func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) { func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
if rv.CanAddr() { if rv.Kind() == reflect.Ptr {
vp := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }}) vp := rv2i(rv).(*map[{{ .MapKey }}]{{ .Elem }})
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, true, f.d) v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d);
if changed { if changed { *vp = v }
*vp = v
}
} else { } else {
v := rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}) fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), false, d)
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d) }
}
} }
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, d *Decoder) { func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) {
v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d) v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d)
if changed { if changed { *vp = v }
*vp = v
}
} }
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool, func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, canChange bool,
d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) { d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
dd := d.d dd, esep := d.d, d.hh.hasElemSeparators(){{/*
cr := d.cr // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil()
{{/* // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() */}} */}}
if checkNil && dd.TryDecodeAsNil() {
if v != nil {
changed = true
}
return nil, changed
}
containerLen := dd.ReadMapStart() containerLen := dd.ReadMapStart()
if canChange && v == nil { if canChange && v == nil {
xlen, _ := decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}) xlen := decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }})
v = make(map[{{ .MapKey }}]{{ .Elem }}, xlen) v = make(map[{{ .MapKey }}]{{ .Elem }}, xlen)
changed = true changed = true
} }
{{ if eq .Elem "interface{}" }}mapGet := !d.h.MapValueReset && !d.h.InterfaceReset{{end}} if containerLen == 0 {
var mk {{ .MapKey }} dd.ReadMapEnd()
var mv {{ .Elem }} return v, changed
if containerLen > 0 {
for j := 0; j < containerLen; j++ {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil {
v[mk] = mv
}
}
} else if containerLen < 0 {
for j := 0; !dd.CheckBreak(); j++ {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil {
v[mk] = mv
}
}
} }
if cr != nil { cr.sendContainerState(containerMapEnd) } {{ if eq .Elem "interface{}" }}mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset
{{end}}var mk {{ .MapKey }}
var mv {{ .Elem }}
hasLen := containerLen > 0
for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
if esep { dd.ReadMapElemKey() }
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if esep { dd.ReadMapElemValue() }
if dd.TryDecodeAsNil() {
if v == nil {} else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = {{ zerocmd .Elem }} }
continue
}
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil { v[mk] = mv }
}
dd.ReadMapEnd()
return v, changed return v, changed
} }
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}

View File

@ -1,9 +1,14 @@
// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// +build notfastpath // +build notfastpath
package codec package codec
import "reflect" import "reflect"
const fastpathEnabled = false
// The generated fast-path code is very large, and adds a few seconds to the build time. // The generated fast-path code is very large, and adds a few seconds to the build time.
// This causes test execution, execution of small tools which use codec, etc // This causes test execution, execution of small tools which use codec, etc
// to take a long time. // to take a long time.
@ -16,17 +21,27 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return fal
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false } func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false }
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false } func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false }
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false } func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false }
func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool { return false }
type fastpathT struct{} type fastpathT struct{}
type fastpathE struct { type fastpathE struct {
rtid uintptr rtid uintptr
rt reflect.Type rt reflect.Type
encfn func(*encFnInfo, reflect.Value) encfn func(*Encoder, *codecFnInfo, reflect.Value)
decfn func(*decFnInfo, reflect.Value) decfn func(*Decoder, *codecFnInfo, reflect.Value)
} }
type fastpathA [0]fastpathE type fastpathA [0]fastpathE
func (x fastpathA) index(rtid uintptr) int { return -1 } func (x fastpathA) index(rtid uintptr) int { return -1 }
func (_ fastpathT) DecSliceUint8V(v []uint8, canChange bool, d *Decoder) (_ []uint8, changed bool) {
fn := d.cfer().get(uint8SliceTyp, true, true)
d.kSlice(&fn.i, reflect.ValueOf(&v).Elem())
return v, true
}
var fastpathAV fastpathA var fastpathAV fastpathA
var fastpathTV fastpathT var fastpathTV fastpathT
// ----
type TestMammoth2Wrapper struct{} // to allow testMammoth work in notfastpath mode

View File

@ -9,94 +9,68 @@ if {{var "l"}} == 0 {
} else if len({{var "v"}}) != 0 { } else if len({{var "v"}}) != 0 {
{{var "v"}} = {{var "v"}}[:0] {{var "v"}} = {{var "v"}}[:0]
{{var "c"}} = true {{var "c"}} = true
} {{end}} {{if isChan }}if {{var "v"}} == nil { } {{else if isChan }}if {{var "v"}} == nil {
{{var "v"}} = make({{ .CTyp }}, 0) {{var "v"}} = make({{ .CTyp }}, 0)
{{var "c"}} = true {{var "c"}} = true
} {{end}} } {{end}}
} else if {{var "l"}} > 0 { } else {
{{if isChan }}if {{var "v"}} == nil { {{var "hl"}} := {{var "l"}} > 0
{{var "rl"}}, _ = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) var {{var "rl"}} int
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}}) _ = {{var "rl"}}
{{var "c"}} = true {{if isSlice }} if {{var "hl"}} {
}
for {{var "r"}} := 0; {{var "r"}} < {{var "l"}}; {{var "r"}}++ {
{{var "h"}}.ElemContainerState({{var "r"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
}
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}}
_, _ = {{var "rl"}}, {{var "rt"}}
{{var "rr"}} = {{var "l"}} // len({{var "v"}})
if {{var "l"}} > cap({{var "v"}}) { if {{var "l"}} > cap({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}}) {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
{{ else }}{{if not .Immutable }} if {{var "rl"}} <= cap({{var "v"}}) {
{{var "rg"}} := len({{var "v"}}) > 0 {{var "v"}} = {{var "v"}}[:{{var "rl"}}]
{{var "v2"}} := {{var "v"}} {{end}}
{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if {{var "rt"}} {
if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
} else { } else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
} }
{{var "c"}} = true {{var "c"}} = true
{{var "rr"}} = len({{var "v"}}) {{if not .Immutable }} } else if {{var "l"}} != len({{var "v"}}) {
if {{var "rg"}} { copy({{var "v"}}, {{var "v2"}}) } {{end}} {{end}}{{/* end not Immutable, isArray */}}
} {{if isSlice }} else if {{var "l"}} != len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "l"}}] {{var "v"}} = {{var "v"}}[:{{var "l"}}]
{{var "c"}} = true {{var "c"}} = true
} {{end}} {{/* end isSlice:47 */}}
{{var "j"}} := 0
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ {
{{var "h"}}.ElemContainerState({{var "j"}})
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
{{if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { } {{end}}
var {{var "j"}} int
// var {{var "dn"}} bool
for ; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
{{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil {
if {{var "hl"}} {
{{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
} else {
{{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}}
}
{{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}})
{{var "c"}} = true
}{{end}}
{{var "h"}}.ElemContainerState({{var "j"}}) {{var "h"}}.ElemContainerState({{var "j"}})
z.DecSwallow() {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */}}
} {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }}
{{ else }}if {{var "rt"}} { {{ decLineVar $x }}
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { {{var "v"}} <- {{ $x }}
{{var "v"}} = append({{var "v"}}, {{ zero}}) // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this
{{var "h"}}.ElemContainerState({{var "j"}}) {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */}}
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }} var {{var "db"}} bool
}
} {{end}} {{/* end isArray:56 */}}
{{end}} {{/* end isChan:16 */}}
} else { {{/* len < 0 */}}
{{var "j"}} := 0
for ; !r.CheckBreak(); {{var "j"}}++ {
{{if isChan }}
{{var "h"}}.ElemContainerState({{var "j"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
{{ else }}
if {{var "j"}} >= len({{var "v"}}) { if {{var "j"}} >= len({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1) {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }})
{{ else }}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }} {{var "c"}} = true
{{var "c"}} = true {{end}} {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true
{{end}}
} }
{{var "h"}}.ElemContainerState({{var "j"}}) if {{var "db"}} {
if {{var "j"}} < len({{var "v"}}) {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} else {
z.DecSwallow() z.DecSwallow()
} else {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
{{end}} {{end}}
} }
{{if isSlice }}if {{var "j"}} < len({{var "v"}}) { {{if isSlice}} if {{var "j"}} < len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "j"}}] {{var "v"}} = {{var "v"}}[:{{var "j"}}]
{{var "c"}} = true {{var "c"}} = true
} else if {{var "j"}} == 0 && {{var "v"}} == nil { } else if {{var "j"}} == 0 && {{var "v"}} == nil {
{{var "v"}} = []{{ .Typ }}{} {{var "v"}} = make([]{{ .Typ }}, 0)
{{var "c"}} = true {{var "c"}} = true
}{{end}} } {{end}}
} }
{{var "h"}}.End() {{var "h"}}.End()
{{if not isArray }}if {{var "c"}} { {{if not isArray }}if {{var "c"}} {

View File

@ -2,21 +2,22 @@
{{var "l"}} := r.ReadMapStart() {{var "l"}} := r.ReadMapStart()
{{var "bh"}} := z.DecBasicHandle() {{var "bh"}} := z.DecBasicHandle()
if {{var "v"}} == nil { if {{var "v"}} == nil {
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }}) {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}}) {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
*{{ .Varname }} = {{var "v"}} *{{ .Varname }} = {{var "v"}}
} }
var {{var "mk"}} {{ .KTyp }} var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }} var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
if {{var "bh"}}.MapValueReset { if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true {{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
{{else if not decElemKindImmutable}}{{var "mg"}} = true {{else if not decElemKindImmutable}}{{var "mg"}} = true
{{end}} } {{end}} }
if {{var "l"}} > 0 { if {{var "l"}} != 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ { {{var "hl"}} := {{var "l"}} > 0
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}}
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} { {{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}}) {{var "mk"}} = string({{var "bv"}})
@ -28,31 +29,14 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
{{var "ms"}} = false {{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}} } {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}}
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }} {{var "mdn"}} = false
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil { {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }}
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} if {{var "mdn"}} {
} if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} }
} } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
} else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}})
}{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true {{ end }}
if {{var "mg"}} {
{{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}]
if {{var "mok"}} {
{{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
} }
} }
} // else len==0: TODO: Should we clear map entries? } // else len==0: TODO: Should we clear map entries?
z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}}

View File

@ -1,23 +1,24 @@
// //+build ignore /* // +build ignore */
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
// ************************************************************ // Code generated from gen-helper.go.tmpl - DO NOT EDIT.
// DO NOT EDIT.
// THIS FILE IS AUTO-GENERATED from gen-helper.go.tmpl
// ************************************************************
package codec package codec
import ( import (
"encoding" "encoding"
"reflect" "reflect"
"strconv"
) )
// GenVersion is the current version of codecgen.
const GenVersion = 8
// This file is used to generate helper code for codecgen. // This file is used to generate helper code for codecgen.
// The values here i.e. genHelper(En|De)coder are not to be used directly by // The values here i.e. genHelper(En|De)coder are not to be used directly by
// library users. They WILL change continously and without notice. // library users. They WILL change continuously and without notice.
// //
// To help enforce this, we create an unexported type with exported members. // To help enforce this, we create an unexported type with exported members.
// The only way to get the type is via the one exported type that we control (somewhat). // The only way to get the type is via the one exported type that we control (somewhat).
@ -26,25 +27,85 @@ import (
// to perform encoding or decoding of primitives or known slice or map types. // to perform encoding or decoding of primitives or known slice or map types.
// GenHelperEncoder is exported so that it can be used externally by codecgen. // GenHelperEncoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperEncoder(e *Encoder) (genHelperEncoder, encDriver) { func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
return genHelperEncoder{e: e}, e.e ge = genHelperEncoder{e: e}
ee = genHelperEncDriver{encDriver: e.e}
return
} }
// GenHelperDecoder is exported so that it can be used externally by codecgen. // GenHelperDecoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperDecoder(d *Decoder) (genHelperDecoder, decDriver) { func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
return genHelperDecoder{d: d}, d.d gd = genHelperDecoder{d: d}
dd = genHelperDecDriver{decDriver: d.d}
return
}
type genHelperEncDriver struct {
encDriver
}
func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
var m must
if keyType == valueTypeString {
x.encDriver.EncodeString(cUTF8, s)
} else if keyType == valueTypeInt {
x.encDriver.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
} else if keyType == valueTypeUint {
x.encDriver.EncodeUint(m.Uint(strconv.ParseUint(s, 10, 64)))
} else if keyType == valueTypeFloat {
x.encDriver.EncodeFloat64(m.Float(strconv.ParseFloat(s, 64)))
}
// encStructFieldKey(x.encDriver, keyType, s)
}
func (x genHelperEncDriver) EncodeSymbol(s string) {
x.encDriver.EncodeString(cUTF8, s)
}
type genHelperDecDriver struct {
decDriver
C checkOverflow
}
func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[decScratchByteArrayLen]byte) []byte {
return decStructFieldKey(x.decDriver, keyType, buf)
}
func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) {
return x.C.IntV(x.decDriver.DecodeInt64(), bitsize)
}
func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
return x.C.UintV(x.decDriver.DecodeUint64(), bitsize)
}
func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
f = x.DecodeFloat64()
if chkOverflow32 && chkOvf.Float32(f) {
panicv.errorf("float32 overflow: %v", f)
}
return
}
func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
f = x.DecodeFloat64()
if chkOvf.Float32(f) {
panicv.errorf("float32 overflow: %v", f)
}
return
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
type genHelperEncoder struct { type genHelperEncoder struct {
M must
e *Encoder e *Encoder
F fastpathT F fastpathT
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
type genHelperDecoder struct { type genHelperDecoder struct {
C checkOverflow
d *Decoder d *Decoder
F fastpathT F fastpathT
} }
@ -59,69 +120,91 @@ func (f genHelperEncoder) EncBinary() bool {
return f.e.be // f.e.hh.isBinaryEncoding() return f.e.be // f.e.hh.isBinaryEncoding()
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncFallback(iv interface{}) {
// println(">>>>>>>>> EncFallback")
f.e.encodeI(iv, false, false)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
bs, fnerr := iv.MarshalText()
f.e.marshal(bs, fnerr, false, c_UTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
bs, fnerr := iv.MarshalJSON()
f.e.marshal(bs, fnerr, true, c_UTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
bs, fnerr := iv.MarshalBinary()
f.e.marshal(bs, fnerr, false, c_RAW)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
if _, ok := f.e.hh.(*BincHandle); ok {
return timeTypId
}
return 0
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) IsJSONHandle() bool { func (f genHelperEncoder) IsJSONHandle() bool {
return f.e.js return f.e.js
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncFallback(iv interface{}) {
// println(">>>>>>>>> EncFallback")
// f.e.encodeI(iv, false, false)
f.e.encodeValue(reflect.ValueOf(iv), nil, false)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
bs, fnerr := iv.MarshalText()
f.e.marshal(bs, fnerr, false, cUTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
bs, fnerr := iv.MarshalJSON()
f.e.marshal(bs, fnerr, true, cUTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
bs, fnerr := iv.MarshalBinary()
f.e.marshal(bs, fnerr, false, cRAW)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: builtin no longer supported - so we make this method a no-op,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperEncoder) TimeRtidIfBinc() (v uintptr) { return }
// func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
// if _, ok := f.e.hh.(*BincHandle); ok {
// return timeTypId
// }
// }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) I2Rtid(v interface{}) uintptr {
return i2rtid(v)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
return f.e.h.getExt(rtid)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) {
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) WriteStr(s string) {
f.e.w.writestr(s)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperEncoder) HasExtensions() bool { func (f genHelperEncoder) HasExtensions() bool {
return len(f.e.h.extHandle) != 0 return len(f.e.h.extHandle) != 0
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperEncoder) EncExt(v interface{}) (r bool) { func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
rt := reflect.TypeOf(v) if xfFn := f.e.h.getExt(i2rtid(v)); xfFn != nil {
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
rtid := reflect.ValueOf(rt).Pointer()
if xfFn := f.e.h.getExt(rtid); xfFn != nil {
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
return true return true
} }
return false return false
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncSendContainerState(c containerState) {
if f.e.cr != nil {
f.e.cr.sendContainerState(c)
}
}
// ---------------- DECODER FOLLOWS ----------------- // ---------------- DECODER FOLLOWS -----------------
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@ -135,19 +218,27 @@ func (f genHelperDecoder) DecBinary() bool {
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSwallow() { func (f genHelperDecoder) DecSwallow() { f.d.swallow() }
f.d.swallow()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecScratchBuffer() []byte { func (f genHelperDecoder) DecScratchBuffer() []byte {
return f.d.b[:] return f.d.b[:]
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte {
return &f.d.b
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) { func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
// println(">>>>>>>>> DecFallback") // println(">>>>>>>>> DecFallback")
f.d.decodeI(iv, chkPtr, false, false, false) rv := reflect.ValueOf(iv)
if chkPtr {
rv = f.d.ensureDecodeable(rv)
}
f.d.decodeValue(rv, nil, false)
// f.d.decodeValueFallback(rv)
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@ -167,7 +258,7 @@ func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
fnerr := tm.UnmarshalText(f.d.d.DecodeBytes(f.d.b[:], true, true)) fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes())
if fnerr != nil { if fnerr != nil {
panic(fnerr) panic(fnerr)
} }
@ -175,7 +266,7 @@ func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// bs := f.dd.DecodeBytes(f.d.b[:], true, true) // bs := f.dd.DecodeStringAsBytes()
// grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
fnerr := tm.UnmarshalJSON(f.d.nextValueBytes()) fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
if fnerr != nil { if fnerr != nil {
@ -185,19 +276,28 @@ func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, false, true)) fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true))
if fnerr != nil { if fnerr != nil {
panic(fnerr) panic(fnerr)
} }
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) TimeRtidIfBinc() uintptr { func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() }
if _, ok := f.d.hh.(*BincHandle); ok {
return timeTypId // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
} //
return 0 // Deprecated: builtin no longer supported - so we make this method a no-op,
} // but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperDecoder) TimeRtidIfBinc() (v uintptr) { return }
// func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
// // Note: builtin is no longer supported - so make this a no-op
// if _, ok := f.d.hh.(*BincHandle); ok {
// return timeTypId
// }
// return 0
// }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) IsJSONHandle() bool { func (f genHelperDecoder) IsJSONHandle() bool {
@ -205,15 +305,34 @@ func (f genHelperDecoder) IsJSONHandle() bool {
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) I2Rtid(v interface{}) uintptr {
return i2rtid(v)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
return f.d.h.getExt(rtid)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) {
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperDecoder) HasExtensions() bool { func (f genHelperDecoder) HasExtensions() bool {
return len(f.d.h.extHandle) != 0 return len(f.d.h.extHandle) != 0
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperDecoder) DecExt(v interface{}) (r bool) { func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
rt := reflect.TypeOf(v).Elem() if xfFn := f.d.h.getExt(i2rtid(v)); xfFn != nil {
rtid := reflect.ValueOf(rt).Pointer()
if xfFn := f.d.h.getExt(rtid); xfFn != nil {
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
return true return true
} }
@ -221,13 +340,12 @@ func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) { func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) {
return decInferLen(clen, maxlen, unit) return decInferLen(clen, maxlen, unit)
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSendContainerState(c containerState) { //
if f.d.cr != nil { // Deprecated: no longer used,
f.d.cr.sendContainerState(c) // but leave in-place so that old generated files continue to work without regeneration.
} func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) }
}

View File

@ -1,50 +1,111 @@
// //+build ignore /* // +build ignore */
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
// ************************************************************ // Code generated from gen-helper.go.tmpl - DO NOT EDIT.
// DO NOT EDIT.
// THIS FILE IS AUTO-GENERATED from gen-helper.go.tmpl
// ************************************************************
package codec package codec
import ( import (
"encoding" "encoding"
"reflect" "reflect"
"strconv"
) )
// GenVersion is the current version of codecgen.
const GenVersion = {{ .Version }}
// This file is used to generate helper code for codecgen. // This file is used to generate helper code for codecgen.
// The values here i.e. genHelper(En|De)coder are not to be used directly by // The values here i.e. genHelper(En|De)coder are not to be used directly by
// library users. They WILL change continously and without notice. // library users. They WILL change continuously and without notice.
// //
// To help enforce this, we create an unexported type with exported members. // To help enforce this, we create an unexported type with exported members.
// The only way to get the type is via the one exported type that we control (somewhat). // The only way to get the type is via the one exported type that we control (somewhat).
// //
// When static codecs are created for types, they will use this value // When static codecs are created for types, they will use this value
// to perform encoding or decoding of primitives or known slice or map types. // to perform encoding or decoding of primitives or known slice or map types.
// GenHelperEncoder is exported so that it can be used externally by codecgen. // GenHelperEncoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperEncoder(e *Encoder) (genHelperEncoder, encDriver) { func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
return genHelperEncoder{e:e}, e.e ge = genHelperEncoder{e: e}
ee = genHelperEncDriver{encDriver: e.e}
return
} }
// GenHelperDecoder is exported so that it can be used externally by codecgen. // GenHelperDecoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperDecoder(d *Decoder) (genHelperDecoder, decDriver) { func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
return genHelperDecoder{d:d}, d.d gd = genHelperDecoder{d: d}
dd = genHelperDecDriver{decDriver: d.d}
return
}
type genHelperEncDriver struct {
encDriver
}
func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
var m must
if keyType == valueTypeString {
x.encDriver.EncodeString(cUTF8, s)
} else if keyType == valueTypeInt {
x.encDriver.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
} else if keyType == valueTypeUint {
x.encDriver.EncodeUint(m.Uint(strconv.ParseUint(s, 10, 64)))
} else if keyType == valueTypeFloat {
x.encDriver.EncodeFloat64(m.Float(strconv.ParseFloat(s, 64)))
}
// encStructFieldKey(x.encDriver, keyType, s)
}
func (x genHelperEncDriver) EncodeSymbol(s string) {
x.encDriver.EncodeString(cUTF8, s)
}
type genHelperDecDriver struct {
decDriver
C checkOverflow
}
func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[decScratchByteArrayLen]byte) []byte {
return decStructFieldKey(x.decDriver, keyType, buf)
}
func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) {
return x.C.IntV(x.decDriver.DecodeInt64(), bitsize)
}
func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
return x.C.UintV(x.decDriver.DecodeUint64(), bitsize)
}
func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
f = x.DecodeFloat64()
if chkOverflow32 && chkOvf.Float32(f) {
panicv.errorf("float32 overflow: %v", f)
}
return
}
func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
f = x.DecodeFloat64()
if chkOvf.Float32(f) {
panicv.errorf("float32 overflow: %v", f)
}
return
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
type genHelperEncoder struct { type genHelperEncoder struct {
M must
e *Encoder e *Encoder
F fastpathT F fastpathT
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
type genHelperDecoder struct { type genHelperDecoder struct {
C checkOverflow
d *Decoder d *Decoder
F fastpathT F fastpathT
} }
@ -53,65 +114,82 @@ type genHelperDecoder struct {
func (f genHelperEncoder) EncBasicHandle() *BasicHandle { func (f genHelperEncoder) EncBasicHandle() *BasicHandle {
return f.e.h return f.e.h
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncBinary() bool { func (f genHelperEncoder) EncBinary() bool {
return f.e.be // f.e.hh.isBinaryEncoding() return f.e.be // f.e.hh.isBinaryEncoding()
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncFallback(iv interface{}) {
// println(">>>>>>>>> EncFallback")
f.e.encodeI(iv, false, false)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
bs, fnerr := iv.MarshalText()
f.e.marshal(bs, fnerr, false, c_UTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
bs, fnerr := iv.MarshalJSON()
f.e.marshal(bs, fnerr, true, c_UTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
bs, fnerr := iv.MarshalBinary()
f.e.marshal(bs, fnerr, false, c_RAW)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
if _, ok := f.e.hh.(*BincHandle); ok {
return timeTypId
}
return 0
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) IsJSONHandle() bool { func (f genHelperEncoder) IsJSONHandle() bool {
return f.e.js return f.e.js
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncFallback(iv interface{}) {
// println(">>>>>>>>> EncFallback")
// f.e.encodeI(iv, false, false)
f.e.encodeValue(reflect.ValueOf(iv), nil, false)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
bs, fnerr := iv.MarshalText()
f.e.marshal(bs, fnerr, false, cUTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
bs, fnerr := iv.MarshalJSON()
f.e.marshal(bs, fnerr, true, cUTF8)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
bs, fnerr := iv.MarshalBinary()
f.e.marshal(bs, fnerr, false, cRAW)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: builtin no longer supported - so we make this method a no-op,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperEncoder) TimeRtidIfBinc() (v uintptr) { return }
// func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
// if _, ok := f.e.hh.(*BincHandle); ok {
// return timeTypId
// }
// }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) I2Rtid(v interface{}) uintptr {
return i2rtid(v)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
return f.e.h.getExt(rtid)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) {
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) WriteStr(s string) {
f.e.w.writestr(s)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperEncoder) HasExtensions() bool { func (f genHelperEncoder) HasExtensions() bool {
return len(f.e.h.extHandle) != 0 return len(f.e.h.extHandle) != 0
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperEncoder) EncExt(v interface{}) (r bool) { func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
rt := reflect.TypeOf(v) if xfFn := f.e.h.getExt(i2rtid(v)); xfFn != nil {
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
rtid := reflect.ValueOf(rt).Pointer()
if xfFn := f.e.h.getExt(rtid); xfFn != nil {
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
return true return true
} }
return false return false
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncSendContainerState(c containerState) {
if f.e.cr != nil {
f.e.cr.sendContainerState(c)
}
}
// ---------------- DECODER FOLLOWS ----------------- // ---------------- DECODER FOLLOWS -----------------
@ -124,17 +202,24 @@ func (f genHelperDecoder) DecBinary() bool {
return f.d.be // f.d.hh.isBinaryEncoding() return f.d.be // f.d.hh.isBinaryEncoding()
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSwallow() { func (f genHelperDecoder) DecSwallow() { f.d.swallow() }
f.d.swallow()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecScratchBuffer() []byte { func (f genHelperDecoder) DecScratchBuffer() []byte {
return f.d.b[:] return f.d.b[:]
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte {
return &f.d.b
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) { func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
// println(">>>>>>>>> DecFallback") // println(">>>>>>>>> DecFallback")
f.d.decodeI(iv, chkPtr, false, false, false) rv := reflect.ValueOf(iv)
if chkPtr {
rv = f.d.ensureDecodeable(rv)
}
f.d.decodeValue(rv, nil, false)
// f.d.decodeValueFallback(rv)
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) { func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) {
@ -150,14 +235,14 @@ func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
fnerr := tm.UnmarshalText(f.d.d.DecodeBytes(f.d.b[:], true, true)) fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes())
if fnerr != nil { if fnerr != nil {
panic(fnerr) panic(fnerr)
} }
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// bs := f.dd.DecodeBytes(f.d.b[:], true, true) // bs := f.dd.DecodeStringAsBytes()
// grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
fnerr := tm.UnmarshalJSON(f.d.nextValueBytes()) fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
if fnerr != nil { if fnerr != nil {
@ -166,199 +251,67 @@ func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, false, true)) fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true))
if fnerr != nil { if fnerr != nil {
panic(fnerr) panic(fnerr)
} }
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) TimeRtidIfBinc() uintptr { func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() }
if _, ok := f.d.hh.(*BincHandle); ok { // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
return timeTypId //
} // Deprecated: builtin no longer supported - so we make this method a no-op,
return 0 // but leave in-place so that old generated files continue to work without regeneration.
} func (f genHelperDecoder) TimeRtidIfBinc() (v uintptr) { return }
// func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
// // Note: builtin is no longer supported - so make this a no-op
// if _, ok := f.d.hh.(*BincHandle); ok {
// return timeTypId
// }
// return 0
// }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) IsJSONHandle() bool { func (f genHelperDecoder) IsJSONHandle() bool {
return f.d.js return f.d.js
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) I2Rtid(v interface{}) uintptr {
return i2rtid(v)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) {
return f.d.h.getExt(rtid)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) {
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperDecoder) HasExtensions() bool { func (f genHelperDecoder) HasExtensions() bool {
return len(f.d.h.extHandle) != 0 return len(f.d.h.extHandle) != 0
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
//
// Deprecated: No longer used,
// but leave in-place so that old generated files continue to work without regeneration.
func (f genHelperDecoder) DecExt(v interface{}) (r bool) { func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
rt := reflect.TypeOf(v).Elem() if xfFn := f.d.h.getExt(i2rtid(v)); xfFn != nil {
rtid := reflect.ValueOf(rt).Pointer()
if xfFn := f.d.h.getExt(rtid); xfFn != nil {
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
return true return true
} }
return false return false
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) { func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) {
return decInferLen(clen, maxlen, unit) return decInferLen(clen, maxlen, unit)
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSendContainerState(c containerState) { //
if f.d.cr != nil { // Deprecated: no longer used,
f.d.cr.sendContainerState(c) // but leave in-place so that old generated files continue to work without regeneration.
} func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) }
}
{{/*
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncDriver() encDriver {
return f.e.e
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecDriver() decDriver {
return f.d.d
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncNil() {
f.e.e.EncodeNil()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncBytes(v []byte) {
f.e.e.EncodeStringBytes(c_RAW, v)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncArrayStart(length int) {
f.e.e.EncodeArrayStart(length)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncArrayEnd() {
f.e.e.EncodeArrayEnd()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncArrayEntrySeparator() {
f.e.e.EncodeArrayEntrySeparator()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncMapStart(length int) {
f.e.e.EncodeMapStart(length)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncMapEnd() {
f.e.e.EncodeMapEnd()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncMapEntrySeparator() {
f.e.e.EncodeMapEntrySeparator()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncMapKVSeparator() {
f.e.e.EncodeMapKVSeparator()
}
// ---------
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecBytes(v *[]byte) {
*v = f.d.d.DecodeBytes(*v)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecTryNil() bool {
return f.d.d.TryDecodeAsNil()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecContainerIsNil() (b bool) {
return f.d.d.IsContainerType(valueTypeNil)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecContainerIsMap() (b bool) {
return f.d.d.IsContainerType(valueTypeMap)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecContainerIsArray() (b bool) {
return f.d.d.IsContainerType(valueTypeArray)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecCheckBreak() bool {
return f.d.d.CheckBreak()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecMapStart() int {
return f.d.d.ReadMapStart()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecArrayStart() int {
return f.d.d.ReadArrayStart()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecMapEnd() {
f.d.d.ReadMapEnd()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecArrayEnd() {
f.d.d.ReadArrayEnd()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecArrayEntrySeparator() {
f.d.d.ReadArrayEntrySeparator()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecMapEntrySeparator() {
f.d.d.ReadMapEntrySeparator()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecMapKVSeparator() {
f.d.d.ReadMapKVSeparator()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) ReadStringAsBytes(bs []byte) []byte {
return f.d.d.DecodeStringAsBytes(bs)
}
// -- encode calls (primitives)
{{range .Values}}{{if .Primitive }}{{if ne .Primitive "interface{}" }}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) {{ .MethodNamePfx "Enc" true }}(v {{ .Primitive }}) {
ee := f.e.e
{{ encmd .Primitive "v" }}
}
{{ end }}{{ end }}{{ end }}
// -- decode calls (primitives)
{{range .Values}}{{if .Primitive }}{{if ne .Primitive "interface{}" }}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) {{ .MethodNamePfx "Dec" true }}(vp *{{ .Primitive }}) {
dd := f.d.d
*vp = {{ decmd .Primitive }}
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) {{ .MethodNamePfx "Read" true }}() (v {{ .Primitive }}) {
dd := f.d.d
v = {{ decmd .Primitive }}
return
}
{{ end }}{{ end }}{{ end }}
// -- encode calls (slices/maps)
{{range .Values}}{{if not .Primitive }}{{if .Slice }}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) {{ .MethodNamePfx "Enc" false }}(v []{{ .Elem }}) { {{ else }}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) {{ .MethodNamePfx "Enc" false }}(v map[{{ .MapKey }}]{{ .Elem }}) { {{end}}
f.F.{{ .MethodNamePfx "Enc" false }}V(v, false, f.e)
}
{{ end }}{{ end }}
// -- decode calls (slices/maps)
{{range .Values}}{{if not .Primitive }}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
{{if .Slice }}func (f genHelperDecoder) {{ .MethodNamePfx "Dec" false }}(vp *[]{{ .Elem }}) {
{{else}}func (f genHelperDecoder) {{ .MethodNamePfx "Dec" false }}(vp *map[{{ .MapKey }}]{{ .Elem }}) { {{end}}
v, changed := f.F.{{ .MethodNamePfx "Dec" false }}V(*vp, false, true, f.d)
if changed {
*vp = v
}
}
{{ end }}{{ end }}
*/}}

View File

@ -1,3 +1,5 @@
// +build codecgen.exec
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
@ -10,21 +12,22 @@ const genDecMapTmpl = `
{{var "l"}} := r.ReadMapStart() {{var "l"}} := r.ReadMapStart()
{{var "bh"}} := z.DecBasicHandle() {{var "bh"}} := z.DecBasicHandle()
if {{var "v"}} == nil { if {{var "v"}} == nil {
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }}) {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}}) {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
*{{ .Varname }} = {{var "v"}} *{{ .Varname }} = {{var "v"}}
} }
var {{var "mk"}} {{ .KTyp }} var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }} var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
if {{var "bh"}}.MapValueReset { if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true {{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
{{else if not decElemKindImmutable}}{{var "mg"}} = true {{else if not decElemKindImmutable}}{{var "mg"}} = true
{{end}} } {{end}} }
if {{var "l"}} > 0 { if {{var "l"}} != 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ { {{var "hl"}} := {{var "l"}} > 0
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}}
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} { {{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}}) {{var "mk"}} = string({{var "bv"}})
@ -36,34 +39,17 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
{{var "ms"}} = false {{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}} } {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}}
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }} {{var "mdn"}} = false
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil { {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }}
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} if {{var "mdn"}} {
} if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} }
} } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
} else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}})
}{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true {{ end }}
if {{var "mg"}} {
{{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}]
if {{var "mok"}} {
{{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
} }
} }
} // else len==0: TODO: Should we clear map entries? } // else len==0: TODO: Should we clear map entries?
z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}}
` `
const genDecListTmpl = ` const genDecListTmpl = `
@ -78,94 +64,68 @@ if {{var "l"}} == 0 {
} else if len({{var "v"}}) != 0 { } else if len({{var "v"}}) != 0 {
{{var "v"}} = {{var "v"}}[:0] {{var "v"}} = {{var "v"}}[:0]
{{var "c"}} = true {{var "c"}} = true
} {{end}} {{if isChan }}if {{var "v"}} == nil { } {{else if isChan }}if {{var "v"}} == nil {
{{var "v"}} = make({{ .CTyp }}, 0) {{var "v"}} = make({{ .CTyp }}, 0)
{{var "c"}} = true {{var "c"}} = true
} {{end}} } {{end}}
} else if {{var "l"}} > 0 { } else {
{{if isChan }}if {{var "v"}} == nil { {{var "hl"}} := {{var "l"}} > 0
{{var "rl"}}, _ = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) var {{var "rl"}} int
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}}) _ = {{var "rl"}}
{{var "c"}} = true {{if isSlice }} if {{var "hl"}} {
}
for {{var "r"}} := 0; {{var "r"}} < {{var "l"}}; {{var "r"}}++ {
{{var "h"}}.ElemContainerState({{var "r"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
}
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}}
_, _ = {{var "rl"}}, {{var "rt"}}
{{var "rr"}} = {{var "l"}} // len({{var "v"}})
if {{var "l"}} > cap({{var "v"}}) { if {{var "l"}} > cap({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}}) {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
{{ else }}{{if not .Immutable }} if {{var "rl"}} <= cap({{var "v"}}) {
{{var "rg"}} := len({{var "v"}}) > 0 {{var "v"}} = {{var "v"}}[:{{var "rl"}}]
{{var "v2"}} := {{var "v"}} {{end}}
{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if {{var "rt"}} {
if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
} else { } else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
} }
{{var "c"}} = true {{var "c"}} = true
{{var "rr"}} = len({{var "v"}}) {{if not .Immutable }} } else if {{var "l"}} != len({{var "v"}}) {
if {{var "rg"}} { copy({{var "v"}}, {{var "v2"}}) } {{end}} {{end}}{{/* end not Immutable, isArray */}}
} {{if isSlice }} else if {{var "l"}} != len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "l"}}] {{var "v"}} = {{var "v"}}[:{{var "l"}}]
{{var "c"}} = true {{var "c"}} = true
} {{end}} {{/* end isSlice:47 */}}
{{var "j"}} := 0
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ {
{{var "h"}}.ElemContainerState({{var "j"}})
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
{{if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { } {{end}}
var {{var "j"}} int
// var {{var "dn"}} bool
for ; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
{{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil {
if {{var "hl"}} {
{{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
} else {
{{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}}
}
{{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}})
{{var "c"}} = true
}{{end}}
{{var "h"}}.ElemContainerState({{var "j"}}) {{var "h"}}.ElemContainerState({{var "j"}})
z.DecSwallow() {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */}}
} {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }}
{{ else }}if {{var "rt"}} { {{ decLineVar $x }}
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { {{var "v"}} <- {{ $x }}
{{var "v"}} = append({{var "v"}}, {{ zero}}) // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this
{{var "h"}}.ElemContainerState({{var "j"}}) {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */}}
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }} var {{var "db"}} bool
}
} {{end}} {{/* end isArray:56 */}}
{{end}} {{/* end isChan:16 */}}
} else { {{/* len < 0 */}}
{{var "j"}} := 0
for ; !r.CheckBreak(); {{var "j"}}++ {
{{if isChan }}
{{var "h"}}.ElemContainerState({{var "j"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
{{ else }}
if {{var "j"}} >= len({{var "v"}}) { if {{var "j"}} >= len({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1) {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }})
{{ else }}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }} {{var "c"}} = true
{{var "c"}} = true {{end}} {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true
{{end}}
} }
{{var "h"}}.ElemContainerState({{var "j"}}) if {{var "db"}} {
if {{var "j"}} < len({{var "v"}}) {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} else {
z.DecSwallow() z.DecSwallow()
} else {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
{{end}} {{end}}
} }
{{if isSlice }}if {{var "j"}} < len({{var "v"}}) { {{if isSlice}} if {{var "j"}} < len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "j"}}] {{var "v"}} = {{var "v"}}[:{{var "j"}}]
{{var "c"}} = true {{var "c"}} = true
} else if {{var "j"}} == 0 && {{var "v"}} == nil { } else if {{var "j"}} == 0 && {{var "v"}} == nil {
{{var "v"}} = []{{ .Typ }}{} {{var "v"}} = make([]{{ .Typ }}, 0)
{{var "c"}} = true {{var "c"}} = true
}{{end}} } {{end}}
} }
{{var "h"}}.End() {{var "h"}}.End()
{{if not isArray }}if {{var "c"}} { {{if not isArray }}if {{var "c"}} {
@ -173,3 +133,32 @@ if {{var "l"}} == 0 {
}{{end}} }{{end}}
` `
const genEncChanTmpl = `
{{.Label}}:
switch timeout{{.Sfx}} := z.EncBasicHandle().ChanRecvTimeout; {
case timeout{{.Sfx}} == 0: // only consume available
for {
select {
case b{{.Sfx}} := <-{{.Chan}}:
{{ .Slice }} = append({{.Slice}}, b{{.Sfx}})
default:
break {{.Label}}
}
}
case timeout{{.Sfx}} > 0: // consume until timeout
tt{{.Sfx}} := time.NewTimer(timeout{{.Sfx}})
for {
select {
case b{{.Sfx}} := <-{{.Chan}}:
{{.Slice}} = append({{.Slice}}, b{{.Sfx}})
case <-tt{{.Sfx}}.C:
// close(tt.C)
break {{.Label}}
}
}
default: // consume until close
for b{{.Sfx}} := range {{.Chan}} {
{{.Slice}} = append({{.Slice}}, b{{.Sfx}})
}
}
`

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,74 +6,6 @@ package codec
// All non-std package dependencies live in this file, // All non-std package dependencies live in this file,
// so porting to different environment is easy (just update functions). // so porting to different environment is easy (just update functions).
import (
"errors"
"fmt"
"math"
"reflect"
)
func panicValToErr(panicVal interface{}, err *error) {
if panicVal == nil {
return
}
// case nil
switch xerr := panicVal.(type) {
case error:
*err = xerr
case string:
*err = errors.New(xerr)
default:
*err = fmt.Errorf("%v", panicVal)
}
return
}
func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool {
switch v.Kind() {
case reflect.Invalid:
return true
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
if deref {
if v.IsNil() {
return true
}
return hIsEmptyValue(v.Elem(), deref, checkStruct)
} else {
return v.IsNil()
}
case reflect.Struct:
if !checkStruct {
return false
}
// return true if all fields are empty. else return false.
// we cannot use equality check, because some fields may be maps/slices/etc
// and consequently the structs are not comparable.
// return v.Interface() == reflect.Zero(v.Type()).Interface()
for i, n := 0, v.NumField(); i < n; i++ {
if !hIsEmptyValue(v.Field(i), deref, checkStruct) {
return false
}
}
return true
}
return false
}
func isEmptyValue(v reflect.Value) bool {
return hIsEmptyValue(v, derefForIsEmptyValue, checkStructForEmptyValue)
}
func pruneSignExt(v []byte, pos bool) (n int) { func pruneSignExt(v []byte, pos bool) (n int) {
if len(v) < 2 { if len(v) < 2 {
} else if pos && v[0] == 0 { } else if pos && v[0] == 0 {
@ -86,37 +18,6 @@ func pruneSignExt(v []byte, pos bool) (n int) {
return return
} }
func implementsIntf(typ, iTyp reflect.Type) (success bool, indir int8) {
if typ == nil {
return
}
rt := typ
// The type might be a pointer and we need to keep
// dereferencing to the base type until we find an implementation.
for {
if rt.Implements(iTyp) {
return true, indir
}
if p := rt; p.Kind() == reflect.Ptr {
indir++
if indir >= math.MaxInt8 { // insane number of indirections
return false, 0
}
rt = p.Elem()
continue
}
break
}
// No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
if typ.Kind() != reflect.Ptr {
// Not a pointer, but does the pointer work?
if reflect.PtrTo(typ).Implements(iTyp) {
return true, -1
}
}
return false, 0
}
// validate that this function is correct ... // validate that this function is correct ...
// culled from OGRE (Object-Oriented Graphics Rendering Engine) // culled from OGRE (Object-Oriented Graphics Rendering Engine)
// function: halfToFloatI (http://stderr.org/doc/ogre-doc/api/OgreBitwise_8h-source.html) // function: halfToFloatI (http://stderr.org/doc/ogre-doc/api/OgreBitwise_8h-source.html)
@ -129,21 +30,20 @@ func halfFloatToFloatBits(yy uint16) (d uint32) {
if e == 0 { if e == 0 {
if m == 0 { // plu or minus 0 if m == 0 { // plu or minus 0
return s << 31 return s << 31
} else { // Denormalized number -- renormalize it
for (m & 0x00000400) == 0 {
m <<= 1
e -= 1
}
e += 1
const zz uint32 = 0x0400
m &= ^zz
} }
// Denormalized number -- renormalize it
for (m & 0x00000400) == 0 {
m <<= 1
e -= 1
}
e += 1
const zz uint32 = 0x0400
m &= ^zz
} else if e == 31 { } else if e == 31 {
if m == 0 { // Inf if m == 0 { // Inf
return (s << 31) | 0x7f800000 return (s << 31) | 0x7f800000
} else { // NaN
return (s << 31) | 0x7f800000 | (m << 13)
} }
return (s << 31) | 0x7f800000 | (m << 13) // NaN
} }
e = e + (127 - 15) e = e + (127 - 15)
m = m << 13 m = m << 13
@ -219,24 +119,3 @@ func growCap(oldCap, unit, num int) (newCap int) {
} }
return return
} }
func expandSliceValue(s reflect.Value, num int) reflect.Value {
if num <= 0 {
return s
}
l0 := s.Len()
l1 := l0 + num // new slice length
if l1 < l0 {
panic("ExpandSlice: slice overflow")
}
c0 := s.Cap()
if l1 <= c0 {
return s.Slice(0, l1)
}
st := s.Type()
c1 := growCap(c0, int(st.Elem().Size()), num)
s2 := reflect.MakeSlice(st, l1, c1)
// println("expandslicevalue: cap-old: ", c0, ", cap-new: ", c1, ", len-new: ", l1)
reflect.Copy(s2, s)
return s2
}

View File

@ -1,13 +1,24 @@
//+build !unsafe // +build !go1.7 safe appengine
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
package codec package codec
import (
"reflect"
"sync/atomic"
"time"
)
const safeMode = true
// stringView returns a view of the []byte as a string. // stringView returns a view of the []byte as a string.
// In unsafe mode, it doesn't incur allocation and copying caused by conversion. // In unsafe mode, it doesn't incur allocation and copying caused by conversion.
// In regular safe mode, it is an allocation and copy. // In regular safe mode, it is an allocation and copy.
//
// Usage: Always maintain a reference to v while result of this call is in use,
// and call keepAlive4BytesView(v) at point where done with view.
func stringView(v []byte) string { func stringView(v []byte) string {
return string(v) return string(v)
} }
@ -15,6 +26,247 @@ func stringView(v []byte) string {
// bytesView returns a view of the string as a []byte. // bytesView returns a view of the string as a []byte.
// In unsafe mode, it doesn't incur allocation and copying caused by conversion. // In unsafe mode, it doesn't incur allocation and copying caused by conversion.
// In regular safe mode, it is an allocation and copy. // In regular safe mode, it is an allocation and copy.
//
// Usage: Always maintain a reference to v while result of this call is in use,
// and call keepAlive4BytesView(v) at point where done with view.
func bytesView(v string) []byte { func bytesView(v string) []byte {
return []byte(v) return []byte(v)
} }
func definitelyNil(v interface{}) bool {
// this is a best-effort option.
// We just return false, so we don't unnecessarily incur the cost of reflection this early.
return false
}
func rv2i(rv reflect.Value) interface{} {
return rv.Interface()
}
func rt2id(rt reflect.Type) uintptr {
return reflect.ValueOf(rt).Pointer()
}
func rv2rtid(rv reflect.Value) uintptr {
return reflect.ValueOf(rv.Type()).Pointer()
}
func i2rtid(i interface{}) uintptr {
return reflect.ValueOf(reflect.TypeOf(i)).Pointer()
}
// --------------------------
func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool {
switch v.Kind() {
case reflect.Invalid:
return true
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
if deref {
if v.IsNil() {
return true
}
return isEmptyValue(v.Elem(), tinfos, deref, checkStruct)
}
return v.IsNil()
case reflect.Struct:
return isEmptyStruct(v, tinfos, deref, checkStruct)
}
return false
}
// --------------------------
// type ptrToRvMap struct{}
// func (*ptrToRvMap) init() {}
// func (*ptrToRvMap) get(i interface{}) reflect.Value {
// return reflect.ValueOf(i).Elem()
// }
// --------------------------
type atomicTypeInfoSlice struct { // expected to be 2 words
v atomic.Value
}
func (x *atomicTypeInfoSlice) load() []rtid2ti {
i := x.v.Load()
if i == nil {
return nil
}
return i.([]rtid2ti)
}
func (x *atomicTypeInfoSlice) store(p []rtid2ti) {
x.v.Store(p)
}
// --------------------------
func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) {
rv.SetBytes(d.rawBytes())
}
func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) {
rv.SetString(d.d.DecodeString())
}
func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) {
rv.SetBool(d.d.DecodeBool())
}
func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) {
rv.Set(reflect.ValueOf(d.d.DecodeTime()))
}
func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
fv := d.d.DecodeFloat64()
if chkOvf.Float32(fv) {
d.errorf("float32 overflow: %v", fv)
}
rv.SetFloat(fv)
}
func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
rv.SetFloat(d.d.DecodeFloat64())
}
func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))
}
func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 8))
}
func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 16))
}
func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 32))
}
func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(d.d.DecodeInt64())
}
func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
}
func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
}
func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 8))
}
func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 16))
}
func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 32))
}
func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(d.d.DecodeUint64())
}
// ----------------
func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeBool(rv.Bool())
}
func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeTime(rv2i(rv).(time.Time))
}
func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeString(cUTF8, rv.String())
}
func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeFloat64(rv.Float())
}
func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeFloat32(float32(rv.Float()))
}
func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeInt(rv.Int())
}
func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeInt(rv.Int())
}
func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeInt(rv.Int())
}
func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeInt(rv.Int())
}
func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeInt(rv.Int())
}
func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeUint(rv.Uint())
}
func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeUint(rv.Uint())
}
func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeUint(rv.Uint())
}
func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeUint(rv.Uint())
}
func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeUint(rv.Uint())
}
func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
e.e.EncodeUint(rv.Uint())
}
// // keepAlive4BytesView maintains a reference to the input parameter for bytesView.
// //
// // Usage: call this at point where done with the bytes view.
// func keepAlive4BytesView(v string) {}
// // keepAlive4BytesView maintains a reference to the input parameter for stringView.
// //
// // Usage: call this at point where done with the string view.
// func keepAlive4StringView(v []byte) {}
// func definitelyNil(v interface{}) bool {
// rv := reflect.ValueOf(v)
// switch rv.Kind() {
// case reflect.Invalid:
// return true
// case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Slice, reflect.Map, reflect.Func:
// return rv.IsNil()
// default:
// return false
// }
// }

View File

@ -1,45 +1,639 @@
//+build unsafe // +build !safe
// +build !appengine
// +build go1.7
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
package codec package codec
import ( import (
"reflect"
"sync/atomic"
"time"
"unsafe" "unsafe"
) )
// This file has unsafe variants of some helper methods. // This file has unsafe variants of some helper methods.
// NOTE: See helper_not_unsafe.go for the usage information.
// var zeroRTv [4]uintptr
const safeMode = false
const unsafeFlagIndir = 1 << 7 // keep in sync with GO_ROOT/src/reflect/value.go
type unsafeString struct { type unsafeString struct {
Data uintptr Data unsafe.Pointer
Len int Len int
} }
type unsafeBytes struct { type unsafeSlice struct {
Data uintptr Data unsafe.Pointer
Len int Len int
Cap int Cap int
} }
// stringView returns a view of the []byte as a string. type unsafeIntf struct {
// In unsafe mode, it doesn't incur allocation and copying caused by conversion. typ unsafe.Pointer
// In regular safe mode, it is an allocation and copy. word unsafe.Pointer
}
type unsafeReflectValue struct {
typ unsafe.Pointer
ptr unsafe.Pointer
flag uintptr
}
func stringView(v []byte) string { func stringView(v []byte) string {
if len(v) == 0 { if len(v) == 0 {
return "" return ""
} }
x := unsafeString{uintptr(unsafe.Pointer(&v[0])), len(v)} bx := (*unsafeSlice)(unsafe.Pointer(&v))
return *(*string)(unsafe.Pointer(&x)) return *(*string)(unsafe.Pointer(&unsafeString{bx.Data, bx.Len}))
} }
// bytesView returns a view of the string as a []byte.
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
// In regular safe mode, it is an allocation and copy.
func bytesView(v string) []byte { func bytesView(v string) []byte {
if len(v) == 0 { if len(v) == 0 {
return zeroByteSlice return zeroByteSlice
} }
x := unsafeBytes{uintptr(unsafe.Pointer(&v)), len(v), len(v)} sx := (*unsafeString)(unsafe.Pointer(&v))
return *(*[]byte)(unsafe.Pointer(&x)) return *(*[]byte)(unsafe.Pointer(&unsafeSlice{sx.Data, sx.Len, sx.Len}))
} }
func definitelyNil(v interface{}) bool {
// There is no global way of checking if an interface is nil.
// For true references (map, ptr, func, chan), you can just look
// at the word of the interface. However, for slices, you have to dereference
// the word, and get a pointer to the 3-word interface value.
//
// However, the following are cheap calls
// - TypeOf(interface): cheap 2-line call.
// - ValueOf(interface{}): expensive
// - type.Kind: cheap call through an interface
// - Value.Type(): cheap call
// except it's a method value (e.g. r.Read, which implies that it is a Func)
return ((*unsafeIntf)(unsafe.Pointer(&v))).word == nil
}
func rv2i(rv reflect.Value) interface{} {
// TODO: consider a more generally-known optimization for reflect.Value ==> Interface
//
// Currently, we use this fragile method that taps into implememtation details from
// the source go stdlib reflect/value.go, and trims the implementation.
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// true references (map, func, chan, ptr - NOT slice) may be double-referenced as flagIndir
var ptr unsafe.Pointer
if refBitset.isset(byte(urv.flag&(1<<5-1))) && urv.flag&unsafeFlagIndir != 0 {
ptr = *(*unsafe.Pointer)(urv.ptr)
} else {
ptr = urv.ptr
}
return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: ptr}))
}
func rt2id(rt reflect.Type) uintptr {
return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
}
func rv2rtid(rv reflect.Value) uintptr {
return uintptr((*unsafeReflectValue)(unsafe.Pointer(&rv)).typ)
}
func i2rtid(i interface{}) uintptr {
return uintptr(((*unsafeIntf)(unsafe.Pointer(&i))).typ)
}
// --------------------------
func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool {
urv := (*unsafeReflectValue)(unsafe.Pointer(&v))
if urv.flag == 0 {
return true
}
switch v.Kind() {
case reflect.Invalid:
return true
case reflect.String:
return (*unsafeString)(urv.ptr).Len == 0
case reflect.Slice:
return (*unsafeSlice)(urv.ptr).Len == 0
case reflect.Bool:
return !*(*bool)(urv.ptr)
case reflect.Int:
return *(*int)(urv.ptr) == 0
case reflect.Int8:
return *(*int8)(urv.ptr) == 0
case reflect.Int16:
return *(*int16)(urv.ptr) == 0
case reflect.Int32:
return *(*int32)(urv.ptr) == 0
case reflect.Int64:
return *(*int64)(urv.ptr) == 0
case reflect.Uint:
return *(*uint)(urv.ptr) == 0
case reflect.Uint8:
return *(*uint8)(urv.ptr) == 0
case reflect.Uint16:
return *(*uint16)(urv.ptr) == 0
case reflect.Uint32:
return *(*uint32)(urv.ptr) == 0
case reflect.Uint64:
return *(*uint64)(urv.ptr) == 0
case reflect.Uintptr:
return *(*uintptr)(urv.ptr) == 0
case reflect.Float32:
return *(*float32)(urv.ptr) == 0
case reflect.Float64:
return *(*float64)(urv.ptr) == 0
case reflect.Interface:
isnil := urv.ptr == nil || *(*unsafe.Pointer)(urv.ptr) == nil
if deref {
if isnil {
return true
}
return isEmptyValue(v.Elem(), tinfos, deref, checkStruct)
}
return isnil
case reflect.Ptr:
// isnil := urv.ptr == nil (not sufficient, as a pointer value encodes the type)
isnil := urv.ptr == nil || *(*unsafe.Pointer)(urv.ptr) == nil
if deref {
if isnil {
return true
}
return isEmptyValue(v.Elem(), tinfos, deref, checkStruct)
}
return isnil
case reflect.Struct:
return isEmptyStruct(v, tinfos, deref, checkStruct)
case reflect.Map, reflect.Array, reflect.Chan:
return v.Len() == 0
}
return false
}
// --------------------------
// atomicTypeInfoSlice contains length and pointer to the array for a slice.
// It is expected to be 2 words.
//
// Previously, we atomically loaded and stored the length and array pointer separately,
// which could lead to some races.
// We now just atomically store and load the pointer to the value directly.
type atomicTypeInfoSlice struct { // expected to be 2 words
l int // length of the data array (must be first in struct, for 64-bit alignment necessary for 386)
v unsafe.Pointer // data array - Pointer (not uintptr) to maintain GC reference
}
func (x *atomicTypeInfoSlice) load() []rtid2ti {
xp := unsafe.Pointer(x)
x2 := *(*atomicTypeInfoSlice)(atomic.LoadPointer(&xp))
if x2.l == 0 {
return nil
}
return *(*[]rtid2ti)(unsafe.Pointer(&unsafeSlice{Data: x2.v, Len: x2.l, Cap: x2.l}))
}
func (x *atomicTypeInfoSlice) store(p []rtid2ti) {
s := (*unsafeSlice)(unsafe.Pointer(&p))
xp := unsafe.Pointer(x)
atomic.StorePointer(&xp, unsafe.Pointer(&atomicTypeInfoSlice{l: s.Len, v: s.Data}))
}
// --------------------------
func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*[]byte)(urv.ptr) = d.rawBytes()
}
func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*string)(urv.ptr) = d.d.DecodeString()
}
func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*bool)(urv.ptr) = d.d.DecodeBool()
}
func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*time.Time)(urv.ptr) = d.d.DecodeTime()
}
func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
fv := d.d.DecodeFloat64()
if chkOvf.Float32(fv) {
d.errorf("float32 overflow: %v", fv)
}
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*float32)(urv.ptr) = float32(fv)
}
func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*float64)(urv.ptr) = d.d.DecodeFloat64()
}
func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int)(urv.ptr) = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))
}
func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int8)(urv.ptr) = int8(chkOvf.IntV(d.d.DecodeInt64(), 8))
}
func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int16)(urv.ptr) = int16(chkOvf.IntV(d.d.DecodeInt64(), 16))
}
func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int32)(urv.ptr) = int32(chkOvf.IntV(d.d.DecodeInt64(), 32))
}
func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int64)(urv.ptr) = d.d.DecodeInt64()
}
func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint)(urv.ptr) = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
}
func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uintptr)(urv.ptr) = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
}
func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint8)(urv.ptr) = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8))
}
func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint16)(urv.ptr) = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16))
}
func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint32)(urv.ptr) = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32))
}
func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint64)(urv.ptr) = d.d.DecodeUint64()
}
// ------------
func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeBool(*(*bool)(v.ptr))
}
func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeTime(*(*time.Time)(v.ptr))
}
func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeString(cUTF8, *(*string)(v.ptr))
}
func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeFloat64(*(*float64)(v.ptr))
}
func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeFloat32(*(*float32)(v.ptr))
}
func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeInt(int64(*(*int)(v.ptr)))
}
func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeInt(int64(*(*int8)(v.ptr)))
}
func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeInt(int64(*(*int16)(v.ptr)))
}
func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeInt(int64(*(*int32)(v.ptr)))
}
func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeInt(int64(*(*int64)(v.ptr)))
}
func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeUint(uint64(*(*uint)(v.ptr)))
}
func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeUint(uint64(*(*uint8)(v.ptr)))
}
func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeUint(uint64(*(*uint16)(v.ptr)))
}
func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeUint(uint64(*(*uint32)(v.ptr)))
}
func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeUint(uint64(*(*uint64)(v.ptr)))
}
func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
e.e.EncodeUint(uint64(*(*uintptr)(v.ptr)))
}
// ------------
// func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) {
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // if urv.flag&unsafeFlagIndir != 0 {
// // urv.ptr = *(*unsafe.Pointer)(urv.ptr)
// // }
// *(*[]byte)(urv.ptr) = d.rawBytes()
// }
// func rv0t(rt reflect.Type) reflect.Value {
// ut := (*unsafeIntf)(unsafe.Pointer(&rt))
// // we need to determine whether ifaceIndir, and then whether to just pass 0 as the ptr
// uv := unsafeReflectValue{ut.word, &zeroRTv, flag(rt.Kind())}
// return *(*reflect.Value)(unsafe.Pointer(&uv})
// }
// func rv2i(rv reflect.Value) interface{} {
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // true references (map, func, chan, ptr - NOT slice) may be double-referenced as flagIndir
// var ptr unsafe.Pointer
// // kk := reflect.Kind(urv.flag & (1<<5 - 1))
// // if (kk == reflect.Map || kk == reflect.Ptr || kk == reflect.Chan || kk == reflect.Func) && urv.flag&unsafeFlagIndir != 0 {
// if refBitset.isset(byte(urv.flag&(1<<5-1))) && urv.flag&unsafeFlagIndir != 0 {
// ptr = *(*unsafe.Pointer)(urv.ptr)
// } else {
// ptr = urv.ptr
// }
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: ptr}))
// // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// }
// func definitelyNil(v interface{}) bool {
// var ui *unsafeIntf = (*unsafeIntf)(unsafe.Pointer(&v))
// if ui.word == nil {
// return true
// }
// var tk = reflect.TypeOf(v).Kind()
// return (tk == reflect.Interface || tk == reflect.Slice) && *(*unsafe.Pointer)(ui.word) == nil
// fmt.Printf(">>>> definitely nil: isnil: %v, TYPE: \t%T, word: %v, *word: %v, type: %v, nil: %v\n",
// v == nil, v, word, *((*unsafe.Pointer)(word)), ui.typ, nil)
// }
// func keepAlive4BytesView(v string) {
// runtime.KeepAlive(v)
// }
// func keepAlive4StringView(v []byte) {
// runtime.KeepAlive(v)
// }
// func rt2id(rt reflect.Type) uintptr {
// return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
// // var i interface{} = rt
// // // ui := (*unsafeIntf)(unsafe.Pointer(&i))
// // return ((*unsafeIntf)(unsafe.Pointer(&i))).word
// }
// func rv2i(rv reflect.Value) interface{} {
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // non-reference type: already indir
// // reference type: depend on flagIndir property ('cos maybe was double-referenced)
// // const (unsafeRvFlagKindMask = 1<<5 - 1 , unsafeRvFlagIndir = 1 << 7 )
// // rvk := reflect.Kind(urv.flag & (1<<5 - 1))
// // if (rvk == reflect.Chan ||
// // rvk == reflect.Func ||
// // rvk == reflect.Interface ||
// // rvk == reflect.Map ||
// // rvk == reflect.Ptr ||
// // rvk == reflect.UnsafePointer) && urv.flag&(1<<8) != 0 {
// // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type())
// // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// // }
// if urv.flag&(1<<5-1) == uintptr(reflect.Map) && urv.flag&(1<<7) != 0 {
// // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type())
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// }
// // fmt.Printf(">>>>> ++++ direct reference: %v, %v\n", rvk, rv.Type())
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// }
// const (
// unsafeRvFlagKindMask = 1<<5 - 1
// unsafeRvKindDirectIface = 1 << 5
// unsafeRvFlagIndir = 1 << 7
// unsafeRvFlagAddr = 1 << 8
// unsafeRvFlagMethod = 1 << 9
// _USE_RV_INTERFACE bool = false
// _UNSAFE_RV_DEBUG = true
// )
// type unsafeRtype struct {
// _ [2]uintptr
// _ uint32
// _ uint8
// _ uint8
// _ uint8
// kind uint8
// _ [2]uintptr
// _ int32
// }
// func _rv2i(rv reflect.Value) interface{} {
// // Note: From use,
// // - it's never an interface
// // - the only calls here are for ifaceIndir types.
// // (though that conditional is wrong)
// // To know for sure, we need the value of t.kind (which is not exposed).
// //
// // Need to validate the path: type is indirect ==> only value is indirect ==> default (value is direct)
// // - Type indirect, Value indirect: ==> numbers, boolean, slice, struct, array, string
// // - Type Direct, Value indirect: ==> map???
// // - Type Direct, Value direct: ==> pointers, unsafe.Pointer, func, chan, map
// //
// // TRANSLATES TO:
// // if typeIndirect { } else if valueIndirect { } else { }
// //
// // Since we don't deal with funcs, then "flagNethod" is unset, and can be ignored.
// if _USE_RV_INTERFACE {
// return rv.Interface()
// }
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // if urv.flag&unsafeRvFlagMethod != 0 || urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) {
// // println("***** IS flag method or interface: delegating to rv.Interface()")
// // return rv.Interface()
// // }
// // if urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) {
// // println("***** IS Interface: delegate to rv.Interface")
// // return rv.Interface()
// // }
// // if urv.flag&unsafeRvFlagKindMask&unsafeRvKindDirectIface == 0 {
// // if urv.flag&unsafeRvFlagAddr == 0 {
// // println("***** IS ifaceIndir typ")
// // // ui := unsafeIntf{word: urv.ptr, typ: urv.typ}
// // // return *(*interface{})(unsafe.Pointer(&ui))
// // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// // }
// // } else if urv.flag&unsafeRvFlagIndir != 0 {
// // println("***** IS flagindir")
// // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// // } else {
// // println("***** NOT flagindir")
// // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// // }
// // println("***** default: delegate to rv.Interface")
// urt := (*unsafeRtype)(unsafe.Pointer(urv.typ))
// if _UNSAFE_RV_DEBUG {
// fmt.Printf(">>>> start: %v: ", rv.Type())
// fmt.Printf("%v - %v\n", *urv, *urt)
// }
// if urt.kind&unsafeRvKindDirectIface == 0 {
// if _UNSAFE_RV_DEBUG {
// fmt.Printf("**** +ifaceIndir type: %v\n", rv.Type())
// }
// // println("***** IS ifaceIndir typ")
// // if true || urv.flag&unsafeRvFlagAddr == 0 {
// // // println(" ***** IS NOT addr")
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// // }
// } else if urv.flag&unsafeRvFlagIndir != 0 {
// if _UNSAFE_RV_DEBUG {
// fmt.Printf("**** +flagIndir type: %v\n", rv.Type())
// }
// // println("***** IS flagindir")
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// } else {
// if _UNSAFE_RV_DEBUG {
// fmt.Printf("**** -flagIndir type: %v\n", rv.Type())
// }
// // println("***** NOT flagindir")
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// }
// // println("***** default: delegating to rv.Interface()")
// // return rv.Interface()
// }
// var staticM0 = make(map[string]uint64)
// var staticI0 = (int32)(-5)
// func staticRv2iTest() {
// i0 := (int32)(-5)
// m0 := make(map[string]uint16)
// m0["1"] = 1
// for _, i := range []interface{}{
// (int)(7),
// (uint)(8),
// (int16)(-9),
// (uint16)(19),
// (uintptr)(77),
// (bool)(true),
// float32(-32.7),
// float64(64.9),
// complex(float32(19), 5),
// complex(float64(-32), 7),
// [4]uint64{1, 2, 3, 4},
// (chan<- int)(nil), // chan,
// rv2i, // func
// io.Writer(ioutil.Discard),
// make(map[string]uint),
// (map[string]uint)(nil),
// staticM0,
// m0,
// &m0,
// i0,
// &i0,
// &staticI0,
// &staticM0,
// []uint32{6, 7, 8},
// "abc",
// Raw{},
// RawExt{},
// &Raw{},
// &RawExt{},
// unsafe.Pointer(&i0),
// } {
// i2 := rv2i(reflect.ValueOf(i))
// eq := reflect.DeepEqual(i, i2)
// fmt.Printf(">>>> %v == %v? %v\n", i, i2, eq)
// }
// // os.Exit(0)
// }
// func init() {
// staticRv2iTest()
// }
// func rv2i(rv reflect.Value) interface{} {
// if _USE_RV_INTERFACE || rv.Kind() == reflect.Interface || rv.CanAddr() {
// return rv.Interface()
// }
// // var i interface{}
// // ui := (*unsafeIntf)(unsafe.Pointer(&i))
// var ui unsafeIntf
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // fmt.Printf("urv: flag: %b, typ: %b, ptr: %b\n", urv.flag, uintptr(urv.typ), uintptr(urv.ptr))
// if (urv.flag&unsafeRvFlagKindMask)&unsafeRvKindDirectIface == 0 {
// if urv.flag&unsafeRvFlagAddr != 0 {
// println("***** indirect and addressable! Needs typed move - delegate to rv.Interface()")
// return rv.Interface()
// }
// println("****** indirect type/kind")
// ui.word = urv.ptr
// } else if urv.flag&unsafeRvFlagIndir != 0 {
// println("****** unsafe rv flag indir")
// ui.word = *(*unsafe.Pointer)(urv.ptr)
// } else {
// println("****** default: assign prt to word directly")
// ui.word = urv.ptr
// }
// // ui.word = urv.ptr
// ui.typ = urv.typ
// // fmt.Printf("(pointers) ui.typ: %p, word: %p\n", ui.typ, ui.word)
// // fmt.Printf("(binary) ui.typ: %b, word: %b\n", uintptr(ui.typ), uintptr(ui.word))
// return *(*interface{})(unsafe.Pointer(&ui))
// // return i
// }

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
/* /*
@ -15,8 +15,8 @@ For compatibility with behaviour of msgpack-c reference implementation:
- Go intX (<0) - Go intX (<0)
IS ENCODED AS IS ENCODED AS
msgpack -ve fixnum, signed msgpack -ve fixnum, signed
*/ */
package codec package codec
import ( import (
@ -25,6 +25,7 @@ import (
"math" "math"
"net/rpc" "net/rpc"
"reflect" "reflect"
"time"
) )
const ( const (
@ -78,6 +79,89 @@ const (
mpNegFixNumMax = 0xff mpNegFixNumMax = 0xff
) )
var mpTimeExtTag int8 = -1
var mpTimeExtTagU = uint8(mpTimeExtTag)
// var mpdesc = map[byte]string{
// mpPosFixNumMin: "PosFixNumMin",
// mpPosFixNumMax: "PosFixNumMax",
// mpFixMapMin: "FixMapMin",
// mpFixMapMax: "FixMapMax",
// mpFixArrayMin: "FixArrayMin",
// mpFixArrayMax: "FixArrayMax",
// mpFixStrMin: "FixStrMin",
// mpFixStrMax: "FixStrMax",
// mpNil: "Nil",
// mpFalse: "False",
// mpTrue: "True",
// mpFloat: "Float",
// mpDouble: "Double",
// mpUint8: "Uint8",
// mpUint16: "Uint16",
// mpUint32: "Uint32",
// mpUint64: "Uint64",
// mpInt8: "Int8",
// mpInt16: "Int16",
// mpInt32: "Int32",
// mpInt64: "Int64",
// mpBin8: "Bin8",
// mpBin16: "Bin16",
// mpBin32: "Bin32",
// mpExt8: "Ext8",
// mpExt16: "Ext16",
// mpExt32: "Ext32",
// mpFixExt1: "FixExt1",
// mpFixExt2: "FixExt2",
// mpFixExt4: "FixExt4",
// mpFixExt8: "FixExt8",
// mpFixExt16: "FixExt16",
// mpStr8: "Str8",
// mpStr16: "Str16",
// mpStr32: "Str32",
// mpArray16: "Array16",
// mpArray32: "Array32",
// mpMap16: "Map16",
// mpMap32: "Map32",
// mpNegFixNumMin: "NegFixNumMin",
// mpNegFixNumMax: "NegFixNumMax",
// }
func mpdesc(bd byte) string {
switch bd {
case mpNil:
return "nil"
case mpFalse:
return "false"
case mpTrue:
return "true"
case mpFloat, mpDouble:
return "float"
case mpUint8, mpUint16, mpUint32, mpUint64:
return "uint"
case mpInt8, mpInt16, mpInt32, mpInt64:
return "int"
default:
switch {
case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax:
return "int"
case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax:
return "int"
case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax:
return "string|bytes"
case bd == mpBin8, bd == mpBin16, bd == mpBin32:
return "bytes"
case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
return "array"
case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax:
return "map"
case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32:
return "ext"
default:
return "unknown"
}
}
}
// MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec // MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec
// that the backend RPC service takes multiple arguments, which have been arranged // that the backend RPC service takes multiple arguments, which have been arranged
// in sequence in the slice. // in sequence in the slice.
@ -94,21 +178,31 @@ type msgpackContainerType struct {
} }
var ( var (
msgpackContainerStr = msgpackContainerType{32, mpFixStrMin, mpStr8, mpStr16, mpStr32, true, true, false} msgpackContainerStr = msgpackContainerType{
msgpackContainerBin = msgpackContainerType{0, 0, mpBin8, mpBin16, mpBin32, false, true, true} 32, mpFixStrMin, mpStr8, mpStr16, mpStr32, true, true, false,
msgpackContainerList = msgpackContainerType{16, mpFixArrayMin, 0, mpArray16, mpArray32, true, false, false} }
msgpackContainerMap = msgpackContainerType{16, mpFixMapMin, 0, mpMap16, mpMap32, true, false, false} msgpackContainerBin = msgpackContainerType{
0, 0, mpBin8, mpBin16, mpBin32, false, true, true,
}
msgpackContainerList = msgpackContainerType{
16, mpFixArrayMin, 0, mpArray16, mpArray32, true, false, false,
}
msgpackContainerMap = msgpackContainerType{
16, mpFixMapMin, 0, mpMap16, mpMap32, true, false, false,
}
) )
//--------------------------------------------- //---------------------------------------------
type msgpackEncDriver struct { type msgpackEncDriver struct {
noBuiltInTypes noBuiltInTypes
encNoSeparator encDriverNoopContainerWriter
// encNoSeparator
e *Encoder e *Encoder
w encWriter w encWriter
h *MsgpackHandle h *MsgpackHandle
x [8]byte x [8]byte
// _ [3]uint64 // padding
} }
func (e *msgpackEncDriver) EncodeNil() { func (e *msgpackEncDriver) EncodeNil() {
@ -116,10 +210,25 @@ func (e *msgpackEncDriver) EncodeNil() {
} }
func (e *msgpackEncDriver) EncodeInt(i int64) { func (e *msgpackEncDriver) EncodeInt(i int64) {
if i >= 0 { if e.h.PositiveIntUnsigned && i >= 0 {
e.EncodeUint(uint64(i)) e.EncodeUint(uint64(i))
} else if i > math.MaxInt8 {
if i <= math.MaxInt16 {
e.w.writen1(mpInt16)
bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i))
} else if i <= math.MaxInt32 {
e.w.writen1(mpInt32)
bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i))
} else {
e.w.writen1(mpInt64)
bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i))
}
} else if i >= -32 { } else if i >= -32 {
e.w.writen1(byte(i)) if e.h.NoFixedNum {
e.w.writen2(mpInt8, byte(i))
} else {
e.w.writen1(byte(i))
}
} else if i >= math.MinInt8 { } else if i >= math.MinInt8 {
e.w.writen2(mpInt8, byte(i)) e.w.writen2(mpInt8, byte(i))
} else if i >= math.MinInt16 { } else if i >= math.MinInt16 {
@ -136,7 +245,11 @@ func (e *msgpackEncDriver) EncodeInt(i int64) {
func (e *msgpackEncDriver) EncodeUint(i uint64) { func (e *msgpackEncDriver) EncodeUint(i uint64) {
if i <= math.MaxInt8 { if i <= math.MaxInt8 {
e.w.writen1(byte(i)) if e.h.NoFixedNum {
e.w.writen2(mpUint8, byte(i))
} else {
e.w.writen1(byte(i))
}
} else if i <= math.MaxUint8 { } else if i <= math.MaxUint8 {
e.w.writen2(mpUint8, byte(i)) e.w.writen2(mpUint8, byte(i))
} else if i <= math.MaxUint16 { } else if i <= math.MaxUint16 {
@ -169,6 +282,39 @@ func (e *msgpackEncDriver) EncodeFloat64(f float64) {
bigenHelper{e.x[:8], e.w}.writeUint64(math.Float64bits(f)) bigenHelper{e.x[:8], e.w}.writeUint64(math.Float64bits(f))
} }
func (e *msgpackEncDriver) EncodeTime(t time.Time) {
if t.IsZero() {
e.EncodeNil()
return
}
t = t.UTC()
sec, nsec := t.Unix(), uint64(t.Nanosecond())
var data64 uint64
var l = 4
if sec >= 0 && sec>>34 == 0 {
data64 = (nsec << 34) | uint64(sec)
if data64&0xffffffff00000000 != 0 {
l = 8
}
} else {
l = 12
}
if e.h.WriteExt {
e.encodeExtPreamble(mpTimeExtTagU, l)
} else {
e.writeContainerLen(msgpackContainerStr, l)
}
switch l {
case 4:
bigenHelper{e.x[:4], e.w}.writeUint32(uint32(data64))
case 8:
bigenHelper{e.x[:8], e.w}.writeUint64(data64)
case 12:
bigenHelper{e.x[:4], e.w}.writeUint32(uint32(nsec))
bigenHelper{e.x[:8], e.w}.writeUint64(uint64(sec))
}
}
func (e *msgpackEncDriver) EncodeExt(v interface{}, xtag uint64, ext Ext, _ *Encoder) { func (e *msgpackEncDriver) EncodeExt(v interface{}, xtag uint64, ext Ext, _ *Encoder) {
bs := ext.WriteExt(v) bs := ext.WriteExt(v)
if bs == nil { if bs == nil {
@ -179,7 +325,7 @@ func (e *msgpackEncDriver) EncodeExt(v interface{}, xtag uint64, ext Ext, _ *Enc
e.encodeExtPreamble(uint8(xtag), len(bs)) e.encodeExtPreamble(uint8(xtag), len(bs))
e.w.writeb(bs) e.w.writeb(bs)
} else { } else {
e.EncodeStringBytes(c_RAW, bs) e.EncodeStringBytes(cRAW, bs)
} }
} }
@ -213,36 +359,38 @@ func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) {
} }
} }
func (e *msgpackEncDriver) EncodeArrayStart(length int) { func (e *msgpackEncDriver) WriteArrayStart(length int) {
e.writeContainerLen(msgpackContainerList, length) e.writeContainerLen(msgpackContainerList, length)
} }
func (e *msgpackEncDriver) EncodeMapStart(length int) { func (e *msgpackEncDriver) WriteMapStart(length int) {
e.writeContainerLen(msgpackContainerMap, length) e.writeContainerLen(msgpackContainerMap, length)
} }
func (e *msgpackEncDriver) EncodeString(c charEncoding, s string) { func (e *msgpackEncDriver) EncodeString(c charEncoding, s string) {
if c == c_RAW && e.h.WriteExt { slen := len(s)
e.writeContainerLen(msgpackContainerBin, len(s)) if c == cRAW && e.h.WriteExt {
e.writeContainerLen(msgpackContainerBin, slen)
} else { } else {
e.writeContainerLen(msgpackContainerStr, len(s)) e.writeContainerLen(msgpackContainerStr, slen)
} }
if len(s) > 0 { if slen > 0 {
e.w.writestr(s) e.w.writestr(s)
} }
} }
func (e *msgpackEncDriver) EncodeSymbol(v string) {
e.EncodeString(c_UTF8, v)
}
func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) { func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) {
if c == c_RAW && e.h.WriteExt { if bs == nil {
e.writeContainerLen(msgpackContainerBin, len(bs)) e.EncodeNil()
} else { return
e.writeContainerLen(msgpackContainerStr, len(bs))
} }
if len(bs) > 0 { slen := len(bs)
if c == cRAW && e.h.WriteExt {
e.writeContainerLen(msgpackContainerBin, slen)
} else {
e.writeContainerLen(msgpackContainerStr, slen)
}
if slen > 0 {
e.w.writeb(bs) e.w.writeb(bs)
} }
} }
@ -264,16 +412,18 @@ func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
//--------------------------------------------- //---------------------------------------------
type msgpackDecDriver struct { type msgpackDecDriver struct {
d *Decoder d *Decoder
r decReader // *Decoder decReader decReaderT r decReader
h *MsgpackHandle h *MsgpackHandle
b [scratchByteArrayLen]byte // b [scratchByteArrayLen]byte
bd byte bd byte
bdRead bool bdRead bool
br bool // bytes reader br bool // bytes reader
noBuiltInTypes noBuiltInTypes
noStreamingCodec // noStreamingCodec
decNoSeparator // decNoSeparator
decDriverNoopContainerReader
// _ [3]uint64 // padding
} }
// Note: This returns either a primitive (int, bool, etc) for non-containers, // Note: This returns either a primitive (int, bool, etc) for non-containers,
@ -286,7 +436,7 @@ func (d *msgpackDecDriver) DecodeNaked() {
d.readNextBd() d.readNextBd()
} }
bd := d.bd bd := d.bd
n := &d.d.n n := d.d.n
var decodeFurther bool var decodeFurther bool
switch bd { switch bd {
@ -349,11 +499,11 @@ func (d *msgpackDecDriver) DecodeNaked() {
n.s = d.DecodeString() n.s = d.DecodeString()
} else { } else {
n.v = valueTypeBytes n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false)
} }
case bd == mpBin8, bd == mpBin16, bd == mpBin32: case bd == mpBin8, bd == mpBin16, bd == mpBin32:
n.v = valueTypeBytes n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false)
case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
n.v = valueTypeArray n.v = valueTypeArray
decodeFurther = true decodeFurther = true
@ -364,9 +514,14 @@ func (d *msgpackDecDriver) DecodeNaked() {
n.v = valueTypeExt n.v = valueTypeExt
clen := d.readExtLen() clen := d.readExtLen()
n.u = uint64(d.r.readn1()) n.u = uint64(d.r.readn1())
n.l = d.r.readx(clen) if n.u == uint64(mpTimeExtTagU) {
n.v = valueTypeTime
n.t = d.decodeTime(clen)
} else {
n.l = d.r.readx(clen)
}
default: default:
d.d.errorf("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd) d.d.errorf("cannot infer value: %s: Ox%x/%d/%s", msgBadDesc, bd, bd, mpdesc(bd))
} }
} }
if !decodeFurther { if !decodeFurther {
@ -380,7 +535,7 @@ func (d *msgpackDecDriver) DecodeNaked() {
} }
// int can be decoded from msgpack type: intXXX or uintXXX // int can be decoded from msgpack type: intXXX or uintXXX
func (d *msgpackDecDriver) DecodeInt(bitsize uint8) (i int64) { func (d *msgpackDecDriver) DecodeInt64() (i int64) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -408,14 +563,7 @@ func (d *msgpackDecDriver) DecodeInt(bitsize uint8) (i int64) {
case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
i = int64(int8(d.bd)) i = int64(int8(d.bd))
default: default:
d.d.errorf("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd) d.d.errorf("cannot decode signed integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd))
return
}
}
// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
if bitsize > 0 {
if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc {
d.d.errorf("Overflow int value: %v", i)
return return
} }
} }
@ -424,7 +572,7 @@ func (d *msgpackDecDriver) DecodeInt(bitsize uint8) (i int64) {
} }
// uint can be decoded from msgpack type: intXXX or uintXXX // uint can be decoded from msgpack type: intXXX or uintXXX
func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) { func (d *msgpackDecDriver) DecodeUint64() (ui uint64) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -441,28 +589,28 @@ func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
if i := int64(int8(d.r.readn1())); i >= 0 { if i := int64(int8(d.r.readn1())); i >= 0 {
ui = uint64(i) ui = uint64(i)
} else { } else {
d.d.errorf("Assigning negative signed value: %v, to unsigned type", i) d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
return return
} }
case mpInt16: case mpInt16:
if i := int64(int16(bigen.Uint16(d.r.readx(2)))); i >= 0 { if i := int64(int16(bigen.Uint16(d.r.readx(2)))); i >= 0 {
ui = uint64(i) ui = uint64(i)
} else { } else {
d.d.errorf("Assigning negative signed value: %v, to unsigned type", i) d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
return return
} }
case mpInt32: case mpInt32:
if i := int64(int32(bigen.Uint32(d.r.readx(4)))); i >= 0 { if i := int64(int32(bigen.Uint32(d.r.readx(4)))); i >= 0 {
ui = uint64(i) ui = uint64(i)
} else { } else {
d.d.errorf("Assigning negative signed value: %v, to unsigned type", i) d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
return return
} }
case mpInt64: case mpInt64:
if i := int64(bigen.Uint64(d.r.readx(8))); i >= 0 { if i := int64(bigen.Uint64(d.r.readx(8))); i >= 0 {
ui = uint64(i) ui = uint64(i)
} else { } else {
d.d.errorf("Assigning negative signed value: %v, to unsigned type", i) d.d.errorf("assigning negative signed value: %v, to unsigned type", i)
return return
} }
default: default:
@ -470,17 +618,10 @@ func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax: case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax:
ui = uint64(d.bd) ui = uint64(d.bd)
case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
d.d.errorf("Assigning negative signed value: %v, to unsigned type", int(d.bd)) d.d.errorf("assigning negative signed value: %v, to unsigned type", int(d.bd))
return return
default: default:
d.d.errorf("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd) d.d.errorf("cannot decode unsigned integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd))
return
}
}
// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
if bitsize > 0 {
if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc {
d.d.errorf("Overflow uint value: %v", ui)
return return
} }
} }
@ -489,7 +630,7 @@ func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
} }
// float can either be decoded from msgpack type: float, double or intX // float can either be decoded from msgpack type: float, double or intX
func (d *msgpackDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { func (d *msgpackDecDriver) DecodeFloat64() (f float64) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -498,11 +639,7 @@ func (d *msgpackDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
} else if d.bd == mpDouble { } else if d.bd == mpDouble {
f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
} else { } else {
f = float64(d.DecodeInt(0)) f = float64(d.DecodeInt64())
}
if chkOverflow32 && chkOvf.Float32(f) {
d.d.errorf("msgpack: float32 overflow: %v", f)
return
} }
d.bdRead = false d.bdRead = false
return return
@ -518,25 +655,45 @@ func (d *msgpackDecDriver) DecodeBool() (b bool) {
} else if d.bd == mpTrue || d.bd == 1 { } else if d.bd == mpTrue || d.bd == 1 {
b = true b = true
} else { } else {
d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd) d.d.errorf("cannot decode bool: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd))
return return
} }
d.bdRead = false d.bdRead = false
return return
} }
func (d *msgpackDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) { func (d *msgpackDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
// check if an "array" of uint8's (see ContainerType for how to infer if an array)
bd := d.bd
// DecodeBytes could be from: bin str fixstr fixarray array ...
var clen int var clen int
// ignore isstring. Expect that the bytes may be found from msgpackContainerStr or msgpackContainerBin vt := d.ContainerType()
if bd := d.bd; bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { switch vt {
clen = d.readContainerLen(msgpackContainerBin) case valueTypeBytes:
} else { // valueTypeBytes may be a mpBin or an mpStr container
if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
clen = d.readContainerLen(msgpackContainerBin)
} else {
clen = d.readContainerLen(msgpackContainerStr)
}
case valueTypeString:
clen = d.readContainerLen(msgpackContainerStr) clen = d.readContainerLen(msgpackContainerStr)
case valueTypeArray:
if zerocopy && len(bs) == 0 {
bs = d.d.b[:]
}
bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d)
return
default:
d.d.errorf("invalid container type: expecting bin|str|array, got: 0x%x", uint8(vt))
return
} }
// println("DecodeBytes: clen: ", clen)
// these are (bin|str)(8|16|32)
d.bdRead = false d.bdRead = false
// bytes may be nil, so handle it. if nil, clen=-1. // bytes may be nil, so handle it. if nil, clen=-1.
if clen < 0 { if clen < 0 {
@ -546,14 +703,18 @@ func (d *msgpackDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOu
if d.br { if d.br {
return d.r.readx(clen) return d.r.readx(clen)
} else if len(bs) == 0 { } else if len(bs) == 0 {
bs = d.b[:] bs = d.d.b[:]
} }
} }
return decByteSlice(d.r, clen, bs) return decByteSlice(d.r, clen, d.h.MaxInitLen, bs)
} }
func (d *msgpackDecDriver) DecodeString() (s string) { func (d *msgpackDecDriver) DecodeString() (s string) {
return string(d.DecodeBytes(d.b[:], true, true)) return string(d.DecodeBytes(d.d.b[:], true))
}
func (d *msgpackDecDriver) DecodeStringAsBytes() (s []byte) {
return d.DecodeBytes(d.d.b[:], true)
} }
func (d *msgpackDecDriver) readNextBd() { func (d *msgpackDecDriver) readNextBd() {
@ -561,7 +722,17 @@ func (d *msgpackDecDriver) readNextBd() {
d.bdRead = true d.bdRead = true
} }
func (d *msgpackDecDriver) uncacheRead() {
if d.bdRead {
d.r.unreadn1()
d.bdRead = false
}
}
func (d *msgpackDecDriver) ContainerType() (vt valueType) { func (d *msgpackDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
bd := d.bd bd := d.bd
if bd == mpNil { if bd == mpNil {
return valueTypeNil return valueTypeNil
@ -576,9 +747,10 @@ func (d *msgpackDecDriver) ContainerType() (vt valueType) {
return valueTypeArray return valueTypeArray
} else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) { } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) {
return valueTypeMap return valueTypeMap
} else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
} }
// else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
// }
return valueTypeUnset return valueTypeUnset
} }
@ -588,7 +760,7 @@ func (d *msgpackDecDriver) TryDecodeAsNil() (v bool) {
} }
if d.bd == mpNil { if d.bd == mpNil {
d.bdRead = false d.bdRead = false
v = true return true
} }
return return
} }
@ -606,7 +778,7 @@ func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int)
} else if (ct.bFixMin & bd) == ct.bFixMin { } else if (ct.bFixMin & bd) == ct.bFixMin {
clen = int(ct.bFixMin ^ bd) clen = int(ct.bFixMin ^ bd)
} else { } else {
d.d.errorf("readContainerLen: %s: hex: %x, decimal: %d", msgBadDesc, bd, bd) d.d.errorf("cannot read container length: %s: hex: %x, decimal: %d", msgBadDesc, bd, bd)
return return
} }
d.bdRead = false d.bdRead = false
@ -614,10 +786,16 @@ func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int)
} }
func (d *msgpackDecDriver) ReadMapStart() int { func (d *msgpackDecDriver) ReadMapStart() int {
if !d.bdRead {
d.readNextBd()
}
return d.readContainerLen(msgpackContainerMap) return d.readContainerLen(msgpackContainerMap)
} }
func (d *msgpackDecDriver) ReadArrayStart() int { func (d *msgpackDecDriver) ReadArrayStart() int {
if !d.bdRead {
d.readNextBd()
}
return d.readContainerLen(msgpackContainerList) return d.readContainerLen(msgpackContainerList)
} }
@ -648,9 +826,60 @@ func (d *msgpackDecDriver) readExtLen() (clen int) {
return return
} }
func (d *msgpackDecDriver) DecodeTime() (t time.Time) {
// decode time from string bytes or ext
if !d.bdRead {
d.readNextBd()
}
if d.bd == mpNil {
d.bdRead = false
return
}
var clen int
switch d.ContainerType() {
case valueTypeBytes, valueTypeString:
clen = d.readContainerLen(msgpackContainerStr)
default:
// expect to see mpFixExt4,-1 OR mpFixExt8,-1 OR mpExt8,12,-1
d.bdRead = false
b2 := d.r.readn1()
if d.bd == mpFixExt4 && b2 == mpTimeExtTagU {
clen = 4
} else if d.bd == mpFixExt8 && b2 == mpTimeExtTagU {
clen = 8
} else if d.bd == mpExt8 && b2 == 12 && d.r.readn1() == mpTimeExtTagU {
clen = 12
} else {
d.d.errorf("invalid bytes for decoding time as extension: got 0x%x, 0x%x", d.bd, b2)
return
}
}
return d.decodeTime(clen)
}
func (d *msgpackDecDriver) decodeTime(clen int) (t time.Time) {
// bs = d.r.readx(clen)
d.bdRead = false
switch clen {
case 4:
t = time.Unix(int64(bigen.Uint32(d.r.readx(4))), 0).UTC()
case 8:
tv := bigen.Uint64(d.r.readx(8))
t = time.Unix(int64(tv&0x00000003ffffffff), int64(tv>>34)).UTC()
case 12:
nsec := bigen.Uint32(d.r.readx(4))
sec := bigen.Uint64(d.r.readx(8))
t = time.Unix(int64(sec), int64(nsec)).UTC()
default:
d.d.errorf("invalid length of bytes for decoding time - expecting 4 or 8 or 12, got %d", clen)
return
}
return
}
func (d *msgpackDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { func (d *msgpackDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
if xtag > 0xff { if xtag > 0xff {
d.d.errorf("decodeExt: tag must be <= 0xff; got: %v", xtag) d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag)
return return
} }
realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag)) realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag))
@ -671,15 +900,15 @@ func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs
} }
xbd := d.bd xbd := d.bd
if xbd == mpBin8 || xbd == mpBin16 || xbd == mpBin32 { if xbd == mpBin8 || xbd == mpBin16 || xbd == mpBin32 {
xbs = d.DecodeBytes(nil, false, true) xbs = d.DecodeBytes(nil, true)
} else if xbd == mpStr8 || xbd == mpStr16 || xbd == mpStr32 || } else if xbd == mpStr8 || xbd == mpStr16 || xbd == mpStr32 ||
(xbd >= mpFixStrMin && xbd <= mpFixStrMax) { (xbd >= mpFixStrMin && xbd <= mpFixStrMax) {
xbs = d.DecodeBytes(nil, true, true) xbs = d.DecodeStringAsBytes()
} else { } else {
clen := d.readExtLen() clen := d.readExtLen()
xtag = d.r.readn1() xtag = d.r.readn1()
if verifyTag && xtag != tag { if verifyTag && xtag != tag {
d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", xtag, tag) d.d.errorf("wrong extension tag - got %b, expecting %v", xtag, tag)
return return
} }
xbs = d.r.readx(clen) xbs = d.r.readx(clen)
@ -697,6 +926,9 @@ type MsgpackHandle struct {
// RawToString controls how raw bytes are decoded into a nil interface{}. // RawToString controls how raw bytes are decoded into a nil interface{}.
RawToString bool RawToString bool
// NoFixedNum says to output all signed integers as 2-bytes, never as 1-byte fixednum.
NoFixedNum bool
// WriteExt flag supports encoding configured extensions with extension tags. // WriteExt flag supports encoding configured extensions with extension tags.
// It also controls whether other elements of the new spec are encoded (ie Str8). // It also controls whether other elements of the new spec are encoded (ie Str8).
// //
@ -708,11 +940,22 @@ type MsgpackHandle struct {
// type is provided (e.g. decoding into a nil interface{}), you get back // type is provided (e.g. decoding into a nil interface{}), you get back
// a []byte or string based on the setting of RawToString. // a []byte or string based on the setting of RawToString.
WriteExt bool WriteExt bool
// PositiveIntUnsigned says to encode positive integers as unsigned.
PositiveIntUnsigned bool
binaryEncodingType binaryEncodingType
noElemSeparators
// _ [1]uint64 // padding
} }
// Name returns the name of the handle: msgpack
func (h *MsgpackHandle) Name() string { return "msgpack" }
// SetBytesExt sets an extension
func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{b: ext}) return h.SetExt(rt, tag, &extWrapper{ext, interfaceExtFailer{}})
} }
func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver { func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver {
@ -720,7 +963,7 @@ func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver {
} }
func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver { func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver {
return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &msgpackDecDriver{d: d, h: h, r: d.r, br: d.bytes}
} }
func (e *msgpackEncDriver) reset() { func (e *msgpackEncDriver) reset() {
@ -728,7 +971,7 @@ func (e *msgpackEncDriver) reset() {
} }
func (d *msgpackDecDriver) reset() { func (d *msgpackDecDriver) reset() {
d.r = d.d.r d.r, d.br = d.d.r, d.d.bytes
d.bd, d.bdRead = 0, false d.bd, d.bdRead = 0, false
} }
@ -750,7 +993,7 @@ func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) err
bodyArr = []interface{}{body} bodyArr = []interface{}{body}
} }
r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr} r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr}
return c.write(r2, nil, false, true) return c.write(r2, nil, false)
} }
func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error {
@ -762,7 +1005,7 @@ func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) e
body = nil body = nil
} }
r2 := []interface{}{1, uint32(r.Seq), moe, body} r2 := []interface{}{1, uint32(r.Seq), moe, body}
return c.write(r2, nil, false, true) return c.write(r2, nil, false)
} }
func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error { func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error {
@ -782,7 +1025,6 @@ func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error {
} }
func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) { func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) {
if c.isClosed() { if c.isClosed() {
return io.EOF return io.EOF
} }
@ -796,28 +1038,34 @@ func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint
// err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, bs1) // err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, bs1)
// return // return
// } // }
var b byte var ba [1]byte
b, err = c.br.ReadByte() var n int
if err != nil { for {
return n, err = c.r.Read(ba[:])
} if err != nil {
if b != fia { return
err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, b) }
return if n == 1 {
break
}
} }
if err = c.read(&b); err != nil { var b = ba[0]
return if b != fia {
} err = fmt.Errorf("not array - %s %x/%s", msgBadDesc, b, mpdesc(b))
if b != expectTypeByte { } else {
err = fmt.Errorf("Unexpected byte descriptor in header. Expecting %v. Received %v", expectTypeByte, b) err = c.read(&b)
return if err == nil {
} if b != expectTypeByte {
if err = c.read(msgid); err != nil { err = fmt.Errorf("%s - expecting %v but got %x/%s",
return msgBadDesc, expectTypeByte, b, mpdesc(b))
} } else {
if err = c.read(methodOrError); err != nil { err = c.read(msgid)
return if err == nil {
err = c.read(methodOrError)
}
}
}
} }
return return
} }
@ -830,7 +1078,8 @@ type msgpackSpecRpc struct{}
// MsgpackSpecRpc implements Rpc using the communication protocol defined in // MsgpackSpecRpc implements Rpc using the communication protocol defined in
// the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md . // the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md .
// Its methods (ServerCodec and ClientCodec) return values that implement RpcCodecBuffered. //
// See GoRpc documentation, for information on buffering for better performance.
var MsgpackSpecRpc msgpackSpecRpc var MsgpackSpecRpc msgpackSpecRpc
func (x msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { func (x msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {

View File

@ -1,213 +0,0 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
package codec
import (
"math/rand"
"time"
)
// NoopHandle returns a no-op handle. It basically does nothing.
// It is only useful for benchmarking, as it gives an idea of the
// overhead from the codec framework.
//
// LIBRARY USERS: *** DO NOT USE ***
func NoopHandle(slen int) *noopHandle {
h := noopHandle{}
h.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
h.B = make([][]byte, slen)
h.S = make([]string, slen)
for i := 0; i < len(h.S); i++ {
b := make([]byte, i+1)
for j := 0; j < len(b); j++ {
b[j] = 'a' + byte(i)
}
h.B[i] = b
h.S[i] = string(b)
}
return &h
}
// noopHandle does nothing.
// It is used to simulate the overhead of the codec framework.
type noopHandle struct {
BasicHandle
binaryEncodingType
noopDrv // noopDrv is unexported here, so we can get a copy of it when needed.
}
type noopDrv struct {
d *Decoder
e *Encoder
i int
S []string
B [][]byte
mks []bool // stack. if map (true), else if array (false)
mk bool // top of stack. what container are we on? map or array?
ct valueType // last response for IsContainerType.
cb int // counter for ContainerType
rand *rand.Rand
}
func (h *noopDrv) r(v int) int { return h.rand.Intn(v) }
func (h *noopDrv) m(v int) int { h.i++; return h.i % v }
func (h *noopDrv) newEncDriver(e *Encoder) encDriver { h.e = e; return h }
func (h *noopDrv) newDecDriver(d *Decoder) decDriver { h.d = d; return h }
func (h *noopDrv) reset() {}
func (h *noopDrv) uncacheRead() {}
// --- encDriver
// stack functions (for map and array)
func (h *noopDrv) start(b bool) {
// println("start", len(h.mks)+1)
h.mks = append(h.mks, b)
h.mk = b
}
func (h *noopDrv) end() {
// println("end: ", len(h.mks)-1)
h.mks = h.mks[:len(h.mks)-1]
if len(h.mks) > 0 {
h.mk = h.mks[len(h.mks)-1]
} else {
h.mk = false
}
}
func (h *noopDrv) EncodeBuiltin(rt uintptr, v interface{}) {}
func (h *noopDrv) EncodeNil() {}
func (h *noopDrv) EncodeInt(i int64) {}
func (h *noopDrv) EncodeUint(i uint64) {}
func (h *noopDrv) EncodeBool(b bool) {}
func (h *noopDrv) EncodeFloat32(f float32) {}
func (h *noopDrv) EncodeFloat64(f float64) {}
func (h *noopDrv) EncodeRawExt(re *RawExt, e *Encoder) {}
func (h *noopDrv) EncodeArrayStart(length int) { h.start(true) }
func (h *noopDrv) EncodeMapStart(length int) { h.start(false) }
func (h *noopDrv) EncodeEnd() { h.end() }
func (h *noopDrv) EncodeString(c charEncoding, v string) {}
func (h *noopDrv) EncodeSymbol(v string) {}
func (h *noopDrv) EncodeStringBytes(c charEncoding, v []byte) {}
func (h *noopDrv) EncodeExt(rv interface{}, xtag uint64, ext Ext, e *Encoder) {}
// ---- decDriver
func (h *noopDrv) initReadNext() {}
func (h *noopDrv) CheckBreak() bool { return false }
func (h *noopDrv) IsBuiltinType(rt uintptr) bool { return false }
func (h *noopDrv) DecodeBuiltin(rt uintptr, v interface{}) {}
func (h *noopDrv) DecodeInt(bitsize uint8) (i int64) { return int64(h.m(15)) }
func (h *noopDrv) DecodeUint(bitsize uint8) (ui uint64) { return uint64(h.m(35)) }
func (h *noopDrv) DecodeFloat(chkOverflow32 bool) (f float64) { return float64(h.m(95)) }
func (h *noopDrv) DecodeBool() (b bool) { return h.m(2) == 0 }
func (h *noopDrv) DecodeString() (s string) { return h.S[h.m(8)] }
// func (h *noopDrv) DecodeStringAsBytes(bs []byte) []byte { return h.DecodeBytes(bs) }
func (h *noopDrv) DecodeBytes(bs []byte, isstring, zerocopy bool) []byte { return h.B[h.m(len(h.B))] }
func (h *noopDrv) ReadEnd() { h.end() }
// toggle map/slice
func (h *noopDrv) ReadMapStart() int { h.start(true); return h.m(10) }
func (h *noopDrv) ReadArrayStart() int { h.start(false); return h.m(10) }
func (h *noopDrv) ContainerType() (vt valueType) {
// return h.m(2) == 0
// handle kStruct, which will bomb is it calls this and doesn't get back a map or array.
// consequently, if the return value is not map or array, reset it to one of them based on h.m(7) % 2
// for kstruct: at least one out of every 2 times, return one of valueTypeMap or Array (else kstruct bombs)
// however, every 10th time it is called, we just return something else.
var vals = [...]valueType{valueTypeArray, valueTypeMap}
// ------------ TAKE ------------
// if h.cb%2 == 0 {
// if h.ct == valueTypeMap || h.ct == valueTypeArray {
// } else {
// h.ct = vals[h.m(2)]
// }
// } else if h.cb%5 == 0 {
// h.ct = valueType(h.m(8))
// } else {
// h.ct = vals[h.m(2)]
// }
// ------------ TAKE ------------
// if h.cb%16 == 0 {
// h.ct = valueType(h.cb % 8)
// } else {
// h.ct = vals[h.cb%2]
// }
h.ct = vals[h.cb%2]
h.cb++
return h.ct
// if h.ct == valueTypeNil || h.ct == valueTypeString || h.ct == valueTypeBytes {
// return h.ct
// }
// return valueTypeUnset
// TODO: may need to tweak this so it works.
// if h.ct == valueTypeMap && vt == valueTypeArray || h.ct == valueTypeArray && vt == valueTypeMap {
// h.cb = !h.cb
// h.ct = vt
// return h.cb
// }
// // go in a loop and check it.
// h.ct = vt
// h.cb = h.m(7) == 0
// return h.cb
}
func (h *noopDrv) TryDecodeAsNil() bool {
if h.mk {
return false
} else {
return h.m(8) == 0
}
}
func (h *noopDrv) DecodeExt(rv interface{}, xtag uint64, ext Ext) uint64 {
return 0
}
func (h *noopDrv) DecodeNaked() {
// use h.r (random) not h.m() because h.m() could cause the same value to be given.
var sk int
if h.mk {
// if mapkey, do not support values of nil OR bytes, array, map or rawext
sk = h.r(7) + 1
} else {
sk = h.r(12)
}
n := &h.d.n
switch sk {
case 0:
n.v = valueTypeNil
case 1:
n.v, n.b = valueTypeBool, false
case 2:
n.v, n.b = valueTypeBool, true
case 3:
n.v, n.i = valueTypeInt, h.DecodeInt(64)
case 4:
n.v, n.u = valueTypeUint, h.DecodeUint(64)
case 5:
n.v, n.f = valueTypeFloat, h.DecodeFloat(true)
case 6:
n.v, n.f = valueTypeFloat, h.DecodeFloat(false)
case 7:
n.v, n.s = valueTypeString, h.DecodeString()
case 8:
n.v, n.l = valueTypeBytes, h.B[h.m(len(h.B))]
case 9:
n.v = valueTypeArray
case 10:
n.v = valueTypeMap
default:
n.v = valueTypeExt
n.u = h.DecodeUint(64)
n.l = h.B[h.m(len(h.B))]
}
h.ct = n.v
return
}

View File

@ -1,3 +0,0 @@
package codec
//go:generate bash prebuild.sh

View File

@ -1,199 +0,0 @@
#!/bin/bash
# _needgen is a helper function to tell if we need to generate files for msgp, codecgen.
_needgen() {
local a="$1"
zneedgen=0
if [[ ! -e "$a" ]]
then
zneedgen=1
echo 1
return 0
fi
for i in `ls -1 *.go.tmpl gen.go values_test.go`
do
if [[ "$a" -ot "$i" ]]
then
zneedgen=1
echo 1
return 0
fi
done
echo 0
}
# _build generates fast-path.go and gen-helper.go.
#
# It is needed because there is some dependency between the generated code
# and the other classes. Consequently, we have to totally remove the
# generated files and put stubs in place, before calling "go run" again
# to recreate them.
_build() {
if ! [[ "${zforce}" == "1" ||
"1" == $( _needgen "fast-path.generated.go" ) ||
"1" == $( _needgen "gen-helper.generated.go" ) ||
"1" == $( _needgen "gen.generated.go" ) ||
1 == 0 ]]
then
return 0
fi
# echo "Running prebuild"
if [ "${zbak}" == "1" ]
then
# echo "Backing up old generated files"
_zts=`date '+%m%d%Y_%H%M%S'`
_gg=".generated.go"
[ -e "gen-helper${_gg}" ] && mv gen-helper${_gg} gen-helper${_gg}__${_zts}.bak
[ -e "fast-path${_gg}" ] && mv fast-path${_gg} fast-path${_gg}__${_zts}.bak
# [ -e "safe${_gg}" ] && mv safe${_gg} safe${_gg}__${_zts}.bak
# [ -e "unsafe${_gg}" ] && mv unsafe${_gg} unsafe${_gg}__${_zts}.bak
else
rm -f fast-path.generated.go gen.generated.go gen-helper.generated.go \
*safe.generated.go *_generated_test.go *.generated_ffjson_expose.go
fi
cat > gen.generated.go <<EOF
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
package codec
// DO NOT EDIT. THIS FILE IS AUTO-GENERATED FROM gen-dec-(map|array).go.tmpl
const genDecMapTmpl = \`
EOF
cat >> gen.generated.go < gen-dec-map.go.tmpl
cat >> gen.generated.go <<EOF
\`
const genDecListTmpl = \`
EOF
cat >> gen.generated.go < gen-dec-array.go.tmpl
cat >> gen.generated.go <<EOF
\`
EOF
cat > gen-from-tmpl.codec.generated.go <<EOF
package codec
import "io"
func GenInternalGoFile(r io.Reader, w io.Writer, safe bool) error {
return genInternalGoFile(r, w, safe)
}
EOF
cat > gen-from-tmpl.generated.go <<EOF
//+build ignore
package main
//import "flag"
import "ugorji.net/codec"
import "os"
func run(fnameIn, fnameOut string, safe bool) {
fin, err := os.Open(fnameIn)
if err != nil { panic(err) }
defer fin.Close()
fout, err := os.Create(fnameOut)
if err != nil { panic(err) }
defer fout.Close()
err = codec.GenInternalGoFile(fin, fout, safe)
if err != nil { panic(err) }
}
func main() {
// do not make safe/unsafe variants.
// Instead, depend on escape analysis, and place string creation and usage appropriately.
// run("unsafe.go.tmpl", "safe.generated.go", true)
// run("unsafe.go.tmpl", "unsafe.generated.go", false)
run("fast-path.go.tmpl", "fast-path.generated.go", false)
run("gen-helper.go.tmpl", "gen-helper.generated.go", false)
}
EOF
go run -tags=notfastpath gen-from-tmpl.generated.go && \
rm -f gen-from-tmpl.*generated.go
}
_codegenerators() {
if [[ $zforce == "1" ||
"1" == $( _needgen "values_codecgen${zsfx}" ) ||
"1" == $( _needgen "values_msgp${zsfx}" ) ||
"1" == $( _needgen "values_ffjson${zsfx}" ) ||
1 == 0 ]]
then
# codecgen creates some temporary files in the directory (main, pkg).
# Consequently, we should start msgp and ffjson first, and also put a small time latency before
# starting codecgen.
# Without this, ffjson chokes on one of the temporary files from codecgen.
if [[ $zexternal == "1" ]]
then
echo "ffjson ... " && \
ffjson -w values_ffjson${zsfx} $zfin &
zzzIdFF=$!
echo "msgp ... " && \
msgp -tests=false -o=values_msgp${zsfx} -file=$zfin &
zzzIdMsgp=$!
sleep 1 # give ffjson and msgp some buffer time. see note above.
fi
echo "codecgen - !unsafe ... " && \
codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 19780 $zfin &
zzzIdC=$!
echo "codecgen - unsafe ... " && \
codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} -d 19781 $zfin &
zzzIdCU=$!
wait $zzzIdC $zzzIdCU $zzzIdMsgp $zzzIdFF && \
# remove (M|Unm)arshalJSON implementations, so they don't conflict with encoding/json bench \
if [[ $zexternal == "1" ]]
then
sed -i 's+ MarshalJSON(+ _MarshalJSON(+g' values_ffjson${zsfx} && \
sed -i 's+ UnmarshalJSON(+ _UnmarshalJSON(+g' values_ffjson${zsfx}
fi && \
echo "generators done!" && \
true
fi
}
# _init reads the arguments and sets up the flags
_init() {
OPTIND=1
while getopts "fbx" flag
do
case "x$flag" in
'xf') zforce=1;;
'xb') zbak=1;;
'xx') zexternal=1;;
*) echo "prebuild.sh accepts [-fbx] only"; return 1;;
esac
done
shift $((OPTIND-1))
OPTIND=1
}
# main script.
# First ensure that this is being run from the basedir (i.e. dirname of script is .)
if [ "." = `dirname $0` ]
then
zmydir=`pwd`
zfin="test_values.generated.go"
zsfx="_generated_test.go"
# rm -f *_generated_test.go
rm -f codecgen-*.go && \
_init "$@" && \
_build && \
cp $zmydir/values_test.go $zmydir/$zfin && \
_codegenerators && \
echo prebuild done successfully
rm -f $zmydir/$zfin
else
echo "Script must be run from the directory it resides in"
fi

View File

@ -1,127 +1,152 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
package codec package codec
import ( import (
"bufio" "bufio"
"errors"
"io" "io"
"net/rpc" "net/rpc"
"sync" "sync"
) )
// rpcEncodeTerminator allows a handler specify a []byte terminator to send after each Encode.
//
// Some codecs like json need to put a space after each encoded value, to serve as a
// delimiter for things like numbers (else json codec will continue reading till EOF).
type rpcEncodeTerminator interface {
rpcEncodeTerminate() []byte
}
// Rpc provides a rpc Server or Client Codec for rpc communication. // Rpc provides a rpc Server or Client Codec for rpc communication.
type Rpc interface { type Rpc interface {
ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec
ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec
} }
// RpcCodecBuffered allows access to the underlying bufio.Reader/Writer // RPCOptions holds options specific to rpc functionality
// used by the rpc connection. It accomodates use-cases where the connection type RPCOptions struct {
// should be used by rpc and non-rpc functions, e.g. streaming a file after // RPCNoBuffer configures whether we attempt to buffer reads and writes during RPC calls.
// sending an rpc response. //
type RpcCodecBuffered interface { // Set RPCNoBuffer=true to turn buffering off.
BufferedReader() *bufio.Reader // Buffering can still be done if buffered connections are passed in, or
BufferedWriter() *bufio.Writer // buffering is configured on the handle.
RPCNoBuffer bool
} }
// -------------------------------------
// rpcCodec defines the struct members and common methods. // rpcCodec defines the struct members and common methods.
type rpcCodec struct { type rpcCodec struct {
rwc io.ReadWriteCloser c io.Closer
r io.Reader
w io.Writer
f ioFlusher
dec *Decoder dec *Decoder
enc *Encoder enc *Encoder
bw *bufio.Writer // bw *bufio.Writer
br *bufio.Reader // br *bufio.Reader
mu sync.Mutex mu sync.Mutex
h Handle h Handle
cls bool cls bool
clsmu sync.RWMutex clsmu sync.RWMutex
clsErr error
} }
func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec { func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec {
bw := bufio.NewWriter(conn) // return newRPCCodec2(bufio.NewReader(conn), bufio.NewWriter(conn), conn, h)
br := bufio.NewReader(conn) return newRPCCodec2(conn, conn, conn, h)
}
func newRPCCodec2(r io.Reader, w io.Writer, c io.Closer, h Handle) rpcCodec {
// defensive: ensure that jsonH has TermWhitespace turned on.
if jsonH, ok := h.(*JsonHandle); ok && !jsonH.TermWhitespace {
panic(errors.New("rpc requires a JsonHandle with TermWhitespace set to true"))
}
// always ensure that we use a flusher, and always flush what was written to the connection.
// we lose nothing by using a buffered writer internally.
f, ok := w.(ioFlusher)
bh := h.getBasicHandle()
if !bh.RPCNoBuffer {
if bh.WriterBufferSize <= 0 {
if !ok {
bw := bufio.NewWriter(w)
f, w = bw, bw
}
}
if bh.ReaderBufferSize <= 0 {
if _, ok = w.(ioPeeker); !ok {
if _, ok = w.(ioBuffered); !ok {
br := bufio.NewReader(r)
r = br
}
}
}
}
return rpcCodec{ return rpcCodec{
rwc: conn, c: c,
bw: bw, w: w,
br: br, r: r,
enc: NewEncoder(bw, h), f: f,
dec: NewDecoder(br, h),
h: h, h: h,
enc: NewEncoder(w, h),
dec: NewDecoder(r, h),
} }
} }
func (c *rpcCodec) BufferedReader() *bufio.Reader { func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2 bool) (err error) {
return c.br
}
func (c *rpcCodec) BufferedWriter() *bufio.Writer {
return c.bw
}
func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err error) {
if c.isClosed() { if c.isClosed() {
return io.EOF return c.clsErr
} }
if err = c.enc.Encode(obj1); err != nil { err = c.enc.Encode(obj1)
return if err == nil {
} if writeObj2 {
t, tOk := c.h.(rpcEncodeTerminator) err = c.enc.Encode(obj2)
if tOk {
c.bw.Write(t.rpcEncodeTerminate())
}
if writeObj2 {
if err = c.enc.Encode(obj2); err != nil {
return
}
if tOk {
c.bw.Write(t.rpcEncodeTerminate())
} }
// if err == nil && c.f != nil {
// err = c.f.Flush()
// }
} }
if doFlush { if c.f != nil {
return c.bw.Flush() if err == nil {
err = c.f.Flush()
} else {
_ = c.f.Flush() // swallow flush error, so we maintain prior error on write
}
} }
return return
} }
func (c *rpcCodec) swallow(err *error) {
defer panicToErr(c.dec, err)
c.dec.swallow()
}
func (c *rpcCodec) read(obj interface{}) (err error) { func (c *rpcCodec) read(obj interface{}) (err error) {
if c.isClosed() { if c.isClosed() {
return io.EOF return c.clsErr
} }
//If nil is passed in, we should still attempt to read content to nowhere. //If nil is passed in, we should read and discard
if obj == nil { if obj == nil {
var obj2 interface{} // var obj2 interface{}
return c.dec.Decode(&obj2) // return c.dec.Decode(&obj2)
c.swallow(&err)
return
} }
return c.dec.Decode(obj) return c.dec.Decode(obj)
} }
func (c *rpcCodec) isClosed() bool { func (c *rpcCodec) isClosed() (b bool) {
c.clsmu.RLock() if c.c != nil {
x := c.cls c.clsmu.RLock()
c.clsmu.RUnlock() b = c.cls
return x c.clsmu.RUnlock()
}
return
} }
func (c *rpcCodec) Close() error { func (c *rpcCodec) Close() error {
if c.isClosed() { if c.c == nil || c.isClosed() {
return io.EOF return c.clsErr
} }
c.clsmu.Lock() c.clsmu.Lock()
c.cls = true c.cls = true
c.clsErr = c.c.Close()
c.clsmu.Unlock() c.clsmu.Unlock()
return c.rwc.Close() return c.clsErr
} }
func (c *rpcCodec) ReadResponseBody(body interface{}) error { func (c *rpcCodec) ReadResponseBody(body interface{}) error {
@ -138,13 +163,13 @@ func (c *goRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error {
// Must protect for concurrent access as per API // Must protect for concurrent access as per API
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
return c.write(r, body, true, true) return c.write(r, body, true)
} }
func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
return c.write(r, body, true, true) return c.write(r, body, true)
} }
func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error { func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error {
@ -166,7 +191,36 @@ func (c *goRpcCodec) ReadRequestBody(body interface{}) error {
type goRpc struct{} type goRpc struct{}
// GoRpc implements Rpc using the communication protocol defined in net/rpc package. // GoRpc implements Rpc using the communication protocol defined in net/rpc package.
// Its methods (ServerCodec and ClientCodec) return values that implement RpcCodecBuffered. //
// Note: network connection (from net.Dial, of type io.ReadWriteCloser) is not buffered.
//
// For performance, you should configure WriterBufferSize and ReaderBufferSize on the handle.
// This ensures we use an adequate buffer during reading and writing.
// If not configured, we will internally initialize and use a buffer during reads and writes.
// This can be turned off via the RPCNoBuffer option on the Handle.
// var handle codec.JsonHandle
// handle.RPCNoBuffer = true // turns off attempt by rpc module to initialize a buffer
//
// Example 1: one way of configuring buffering explicitly:
// var handle codec.JsonHandle // codec handle
// handle.ReaderBufferSize = 1024
// handle.WriterBufferSize = 1024
// var conn io.ReadWriteCloser // connection got from a socket
// var serverCodec = GoRpc.ServerCodec(conn, handle)
// var clientCodec = GoRpc.ClientCodec(conn, handle)
//
// Example 2: you can also explicitly create a buffered connection yourself,
// and not worry about configuring the buffer sizes in the Handle.
// var handle codec.Handle // codec handle
// var conn io.ReadWriteCloser // connection got from a socket
// var bufconn = struct { // bufconn here is a buffered io.ReadWriteCloser
// io.Closer
// *bufio.Reader
// *bufio.Writer
// }{conn, bufio.NewReader(conn), bufio.NewWriter(conn)}
// var serverCodec = GoRpc.ServerCodec(bufconn, handle)
// var clientCodec = GoRpc.ClientCodec(bufconn, handle)
//
var GoRpc goRpc var GoRpc goRpc
func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
@ -176,5 +230,3 @@ func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec { func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec {
return &goRpcCodec{newRPCCodec(conn, h)} return &goRpcCodec{newRPCCodec(conn, h)}
} }
var _ RpcCodecBuffered = (*rpcCodec)(nil) // ensure *rpcCodec implements RpcCodecBuffered

View File

@ -1,4 +1,4 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file. // Use of this source code is governed by a MIT license found in the LICENSE file.
package codec package codec
@ -6,6 +6,7 @@ package codec
import ( import (
"math" "math"
"reflect" "reflect"
"time"
) )
const ( const (
@ -20,6 +21,8 @@ const (
simpleVdPosInt = 8 simpleVdPosInt = 8
simpleVdNegInt = 12 simpleVdNegInt = 12
simpleVdTime = 24
// containers: each lasts for 4 (ie n, n+1, n+2, ... n+7) // containers: each lasts for 4 (ie n, n+1, n+2, ... n+7)
simpleVdString = 216 simpleVdString = 216
simpleVdByteArray = 224 simpleVdByteArray = 224
@ -30,11 +33,15 @@ const (
type simpleEncDriver struct { type simpleEncDriver struct {
noBuiltInTypes noBuiltInTypes
encNoSeparator // encNoSeparator
e *Encoder e *Encoder
h *SimpleHandle h *SimpleHandle
w encWriter w encWriter
b [8]byte b [8]byte
// c containerState
encDriverTrackContainerWriter
// encDriverNoopContainerWriter
_ [3]uint64 // padding
} }
func (e *simpleEncDriver) EncodeNil() { func (e *simpleEncDriver) EncodeNil() {
@ -42,6 +49,10 @@ func (e *simpleEncDriver) EncodeNil() {
} }
func (e *simpleEncDriver) EncodeBool(b bool) { func (e *simpleEncDriver) EncodeBool(b bool) {
if e.h.EncZeroValuesAsNil && e.c != containerMapKey && !b {
e.EncodeNil()
return
}
if b { if b {
e.w.writen1(simpleVdTrue) e.w.writen1(simpleVdTrue)
} else { } else {
@ -50,11 +61,19 @@ func (e *simpleEncDriver) EncodeBool(b bool) {
} }
func (e *simpleEncDriver) EncodeFloat32(f float32) { func (e *simpleEncDriver) EncodeFloat32(f float32) {
if e.h.EncZeroValuesAsNil && e.c != containerMapKey && f == 0.0 {
e.EncodeNil()
return
}
e.w.writen1(simpleVdFloat32) e.w.writen1(simpleVdFloat32)
bigenHelper{e.b[:4], e.w}.writeUint32(math.Float32bits(f)) bigenHelper{e.b[:4], e.w}.writeUint32(math.Float32bits(f))
} }
func (e *simpleEncDriver) EncodeFloat64(f float64) { func (e *simpleEncDriver) EncodeFloat64(f float64) {
if e.h.EncZeroValuesAsNil && e.c != containerMapKey && f == 0.0 {
e.EncodeNil()
return
}
e.w.writen1(simpleVdFloat64) e.w.writen1(simpleVdFloat64)
bigenHelper{e.b[:8], e.w}.writeUint64(math.Float64bits(f)) bigenHelper{e.b[:8], e.w}.writeUint64(math.Float64bits(f))
} }
@ -72,6 +91,10 @@ func (e *simpleEncDriver) EncodeUint(v uint64) {
} }
func (e *simpleEncDriver) encUint(v uint64, bd uint8) { func (e *simpleEncDriver) encUint(v uint64, bd uint8) {
if e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == 0 {
e.EncodeNil()
return
}
if v <= math.MaxUint8 { if v <= math.MaxUint8 {
e.w.writen2(bd, uint8(v)) e.w.writen2(bd, uint8(v))
} else if v <= math.MaxUint16 { } else if v <= math.MaxUint16 {
@ -124,28 +147,55 @@ func (e *simpleEncDriver) encodeExtPreamble(xtag byte, length int) {
e.w.writen1(xtag) e.w.writen1(xtag)
} }
func (e *simpleEncDriver) EncodeArrayStart(length int) { func (e *simpleEncDriver) WriteArrayStart(length int) {
e.c = containerArrayStart
e.encLen(simpleVdArray, length) e.encLen(simpleVdArray, length)
} }
func (e *simpleEncDriver) EncodeMapStart(length int) { func (e *simpleEncDriver) WriteMapStart(length int) {
e.c = containerMapStart
e.encLen(simpleVdMap, length) e.encLen(simpleVdMap, length)
} }
func (e *simpleEncDriver) EncodeString(c charEncoding, v string) { func (e *simpleEncDriver) EncodeString(c charEncoding, v string) {
if false && e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == "" {
e.EncodeNil()
return
}
e.encLen(simpleVdString, len(v)) e.encLen(simpleVdString, len(v))
e.w.writestr(v) e.w.writestr(v)
} }
func (e *simpleEncDriver) EncodeSymbol(v string) { // func (e *simpleEncDriver) EncodeSymbol(v string) {
e.EncodeString(c_UTF8, v) // e.EncodeString(cUTF8, v)
} // }
func (e *simpleEncDriver) EncodeStringBytes(c charEncoding, v []byte) { func (e *simpleEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
// if e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == nil {
if v == nil {
e.EncodeNil()
return
}
e.encLen(simpleVdByteArray, len(v)) e.encLen(simpleVdByteArray, len(v))
e.w.writeb(v) e.w.writeb(v)
} }
func (e *simpleEncDriver) EncodeTime(t time.Time) {
// if e.h.EncZeroValuesAsNil && e.c != containerMapKey && t.IsZero() {
if t.IsZero() {
e.EncodeNil()
return
}
v, err := t.MarshalBinary()
if err != nil {
e.e.errorv(err)
return
}
// time.Time marshalbinary takes about 14 bytes.
e.w.writen2(simpleVdTime, uint8(len(v)))
e.w.writeb(v)
}
//------------------------------------ //------------------------------------
type simpleDecDriver struct { type simpleDecDriver struct {
@ -154,11 +204,13 @@ type simpleDecDriver struct {
r decReader r decReader
bdRead bool bdRead bool
bd byte bd byte
br bool // bytes reader br bool // a bytes reader?
c containerState
// b [scratchByteArrayLen]byte
noBuiltInTypes noBuiltInTypes
noStreamingCodec // noStreamingCodec
decNoSeparator decDriverNoopContainerReader
b [scratchByteArrayLen]byte // _ [3]uint64 // padding
} }
func (d *simpleDecDriver) readNextBd() { func (d *simpleDecDriver) readNextBd() {
@ -166,24 +218,38 @@ func (d *simpleDecDriver) readNextBd() {
d.bdRead = true d.bdRead = true
} }
func (d *simpleDecDriver) ContainerType() (vt valueType) { func (d *simpleDecDriver) uncacheRead() {
if d.bd == simpleVdNil { if d.bdRead {
return valueTypeNil d.r.unreadn1()
} else if d.bd == simpleVdByteArray || d.bd == simpleVdByteArray+1 || d.bdRead = false
d.bd == simpleVdByteArray+2 || d.bd == simpleVdByteArray+3 || d.bd == simpleVdByteArray+4 {
return valueTypeBytes
} else if d.bd == simpleVdString || d.bd == simpleVdString+1 ||
d.bd == simpleVdString+2 || d.bd == simpleVdString+3 || d.bd == simpleVdString+4 {
return valueTypeString
} else if d.bd == simpleVdArray || d.bd == simpleVdArray+1 ||
d.bd == simpleVdArray+2 || d.bd == simpleVdArray+3 || d.bd == simpleVdArray+4 {
return valueTypeArray
} else if d.bd == simpleVdMap || d.bd == simpleVdMap+1 ||
d.bd == simpleVdMap+2 || d.bd == simpleVdMap+3 || d.bd == simpleVdMap+4 {
return valueTypeMap
} else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
} }
}
func (d *simpleDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
switch d.bd {
case simpleVdNil:
return valueTypeNil
case simpleVdByteArray, simpleVdByteArray + 1,
simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
return valueTypeBytes
case simpleVdString, simpleVdString + 1,
simpleVdString + 2, simpleVdString + 3, simpleVdString + 4:
return valueTypeString
case simpleVdArray, simpleVdArray + 1,
simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4:
return valueTypeArray
case simpleVdMap, simpleVdMap + 1,
simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4:
return valueTypeMap
// case simpleVdTime:
// return valueTypeTime
}
// else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
// }
return valueTypeUnset return valueTypeUnset
} }
@ -224,7 +290,7 @@ func (d *simpleDecDriver) decCheckInteger() (ui uint64, neg bool) {
ui = uint64(bigen.Uint64(d.r.readx(8))) ui = uint64(bigen.Uint64(d.r.readx(8)))
neg = true neg = true
default: default:
d.d.errorf("decIntAny: Integer only valid from pos/neg integer1..8. Invalid descriptor: %v", d.bd) d.d.errorf("integer only valid from pos/neg integer1..8. Invalid descriptor: %v", d.bd)
return return
} }
// don't do this check, because callers may only want the unsigned value. // don't do this check, because callers may only want the unsigned value.
@ -235,39 +301,27 @@ func (d *simpleDecDriver) decCheckInteger() (ui uint64, neg bool) {
return return
} }
func (d *simpleDecDriver) DecodeInt(bitsize uint8) (i int64) { func (d *simpleDecDriver) DecodeInt64() (i int64) {
ui, neg := d.decCheckInteger() ui, neg := d.decCheckInteger()
i, overflow := chkOvf.SignedInt(ui) i = chkOvf.SignedIntV(ui)
if overflow {
d.d.errorf("simple: overflow converting %v to signed integer", ui)
return
}
if neg { if neg {
i = -i i = -i
} }
if chkOvf.Int(i, bitsize) {
d.d.errorf("simple: overflow integer: %v", i)
return
}
d.bdRead = false d.bdRead = false
return return
} }
func (d *simpleDecDriver) DecodeUint(bitsize uint8) (ui uint64) { func (d *simpleDecDriver) DecodeUint64() (ui uint64) {
ui, neg := d.decCheckInteger() ui, neg := d.decCheckInteger()
if neg { if neg {
d.d.errorf("Assigning negative signed value to unsigned type") d.d.errorf("assigning negative signed value to unsigned type")
return
}
if chkOvf.Uint(ui, bitsize) {
d.d.errorf("simple: overflow integer: %v", ui)
return return
} }
d.bdRead = false d.bdRead = false
return return
} }
func (d *simpleDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { func (d *simpleDecDriver) DecodeFloat64() (f float64) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -277,16 +331,12 @@ func (d *simpleDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
} else { } else {
if d.bd >= simpleVdPosInt && d.bd <= simpleVdNegInt+3 { if d.bd >= simpleVdPosInt && d.bd <= simpleVdNegInt+3 {
f = float64(d.DecodeInt(64)) f = float64(d.DecodeInt64())
} else { } else {
d.d.errorf("Float only valid from float32/64: Invalid descriptor: %v", d.bd) d.d.errorf("float only valid from float32/64: Invalid descriptor: %v", d.bd)
return return
} }
} }
if chkOverflow32 && chkOvf.Float32(f) {
d.d.errorf("msgpack: float32 overflow: %v", f)
return
}
d.bdRead = false d.bdRead = false
return return
} }
@ -300,7 +350,7 @@ func (d *simpleDecDriver) DecodeBool() (b bool) {
b = true b = true
} else if d.bd == simpleVdFalse { } else if d.bd == simpleVdFalse {
} else { } else {
d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd) d.d.errorf("cannot decode bool - %s: %x", msgBadDesc, d.bd)
return return
} }
d.bdRead = false d.bdRead = false
@ -308,15 +358,43 @@ func (d *simpleDecDriver) DecodeBool() (b bool) {
} }
func (d *simpleDecDriver) ReadMapStart() (length int) { func (d *simpleDecDriver) ReadMapStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false d.bdRead = false
d.c = containerMapStart
return d.decLen() return d.decLen()
} }
func (d *simpleDecDriver) ReadArrayStart() (length int) { func (d *simpleDecDriver) ReadArrayStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false d.bdRead = false
d.c = containerArrayStart
return d.decLen() return d.decLen()
} }
func (d *simpleDecDriver) ReadArrayElem() {
d.c = containerArrayElem
}
func (d *simpleDecDriver) ReadArrayEnd() {
d.c = containerArrayEnd
}
func (d *simpleDecDriver) ReadMapElemKey() {
d.c = containerMapKey
}
func (d *simpleDecDriver) ReadMapElemValue() {
d.c = containerMapValue
}
func (d *simpleDecDriver) ReadMapEnd() {
d.c = containerMapEnd
}
func (d *simpleDecDriver) decLen() int { func (d *simpleDecDriver) decLen() int {
switch d.bd % 8 { switch d.bd % 8 {
case 0: case 0:
@ -328,27 +406,31 @@ func (d *simpleDecDriver) decLen() int {
case 3: case 3:
ui := uint64(bigen.Uint32(d.r.readx(4))) ui := uint64(bigen.Uint32(d.r.readx(4)))
if chkOvf.Uint(ui, intBitsize) { if chkOvf.Uint(ui, intBitsize) {
d.d.errorf("simple: overflow integer: %v", ui) d.d.errorf("overflow integer: %v", ui)
return 0 return 0
} }
return int(ui) return int(ui)
case 4: case 4:
ui := bigen.Uint64(d.r.readx(8)) ui := bigen.Uint64(d.r.readx(8))
if chkOvf.Uint(ui, intBitsize) { if chkOvf.Uint(ui, intBitsize) {
d.d.errorf("simple: overflow integer: %v", ui) d.d.errorf("overflow integer: %v", ui)
return 0 return 0
} }
return int(ui) return int(ui)
} }
d.d.errorf("decLen: Cannot read length: bd%8 must be in range 0..4. Got: %d", d.bd%8) d.d.errorf("cannot read length: bd%%8 must be in range 0..4. Got: %d", d.bd%8)
return -1 return -1
} }
func (d *simpleDecDriver) DecodeString() (s string) { func (d *simpleDecDriver) DecodeString() (s string) {
return string(d.DecodeBytes(d.b[:], true, true)) return string(d.DecodeBytes(d.d.b[:], true))
} }
func (d *simpleDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) { func (d *simpleDecDriver) DecodeStringAsBytes() (s []byte) {
return d.DecodeBytes(d.d.b[:], true)
}
func (d *simpleDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
@ -356,21 +438,51 @@ func (d *simpleDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut
d.bdRead = false d.bdRead = false
return return
} }
// check if an "array" of uint8's (see ContainerType for how to infer if an array)
if d.bd >= simpleVdArray && d.bd <= simpleVdMap+4 {
if len(bs) == 0 && zerocopy {
bs = d.d.b[:]
}
bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d)
return
}
clen := d.decLen() clen := d.decLen()
d.bdRead = false d.bdRead = false
if zerocopy { if zerocopy {
if d.br { if d.br {
return d.r.readx(clen) return d.r.readx(clen)
} else if len(bs) == 0 { } else if len(bs) == 0 {
bs = d.b[:] bs = d.d.b[:]
} }
} }
return decByteSlice(d.r, clen, bs) return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs)
}
func (d *simpleDecDriver) DecodeTime() (t time.Time) {
if !d.bdRead {
d.readNextBd()
}
if d.bd == simpleVdNil {
d.bdRead = false
return
}
if d.bd != simpleVdTime {
d.d.errorf("invalid descriptor for time.Time - expect 0x%x, received 0x%x", simpleVdTime, d.bd)
return
}
d.bdRead = false
clen := int(d.r.readn1())
b := d.r.readx(clen)
if err := (&t).UnmarshalBinary(b); err != nil {
d.d.errorv(err)
}
return
} }
func (d *simpleDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { func (d *simpleDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
if xtag > 0xff { if xtag > 0xff {
d.d.errorf("decodeExt: tag must be <= 0xff; got: %v", xtag) d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag)
return return
} }
realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag)) realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag))
@ -394,14 +506,15 @@ func (d *simpleDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs [
l := d.decLen() l := d.decLen()
xtag = d.r.readn1() xtag = d.r.readn1()
if verifyTag && xtag != tag { if verifyTag && xtag != tag {
d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", xtag, tag) d.d.errorf("wrong extension tag. Got %b. Expecting: %v", xtag, tag)
return return
} }
xbs = d.r.readx(l) xbs = d.r.readx(l)
case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: case simpleVdByteArray, simpleVdByteArray + 1,
xbs = d.DecodeBytes(nil, false, true) simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
xbs = d.DecodeBytes(nil, true)
default: default:
d.d.errorf("Invalid d.bd for extensions (Expecting extensions or byte array). Got: 0x%x", d.bd) d.d.errorf("ext - %s - expecting extensions/bytearray, got: 0x%x", msgBadDesc, d.bd)
return return
} }
d.bdRead = false d.bdRead = false
@ -413,7 +526,7 @@ func (d *simpleDecDriver) DecodeNaked() {
d.readNextBd() d.readNextBd()
} }
n := &d.d.n n := d.d.n
var decodeFurther bool var decodeFurther bool
switch d.bd { switch d.bd {
@ -428,39 +541,45 @@ func (d *simpleDecDriver) DecodeNaked() {
case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3: case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3:
if d.h.SignedInteger { if d.h.SignedInteger {
n.v = valueTypeInt n.v = valueTypeInt
n.i = d.DecodeInt(64) n.i = d.DecodeInt64()
} else { } else {
n.v = valueTypeUint n.v = valueTypeUint
n.u = d.DecodeUint(64) n.u = d.DecodeUint64()
} }
case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3: case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3:
n.v = valueTypeInt n.v = valueTypeInt
n.i = d.DecodeInt(64) n.i = d.DecodeInt64()
case simpleVdFloat32: case simpleVdFloat32:
n.v = valueTypeFloat n.v = valueTypeFloat
n.f = d.DecodeFloat(true) n.f = d.DecodeFloat64()
case simpleVdFloat64: case simpleVdFloat64:
n.v = valueTypeFloat n.v = valueTypeFloat
n.f = d.DecodeFloat(false) n.f = d.DecodeFloat64()
case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4: case simpleVdTime:
n.v = valueTypeTime
n.t = d.DecodeTime()
case simpleVdString, simpleVdString + 1,
simpleVdString + 2, simpleVdString + 3, simpleVdString + 4:
n.v = valueTypeString n.v = valueTypeString
n.s = d.DecodeString() n.s = d.DecodeString()
case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: case simpleVdByteArray, simpleVdByteArray + 1,
simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
n.v = valueTypeBytes n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false)
case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4: case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
n.v = valueTypeExt n.v = valueTypeExt
l := d.decLen() l := d.decLen()
n.u = uint64(d.r.readn1()) n.u = uint64(d.r.readn1())
n.l = d.r.readx(l) n.l = d.r.readx(l)
case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4: case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2,
simpleVdArray + 3, simpleVdArray + 4:
n.v = valueTypeArray n.v = valueTypeArray
decodeFurther = true decodeFurther = true
case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4: case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4:
n.v = valueTypeMap n.v = valueTypeMap
decodeFurther = true decodeFurther = true
default: default:
d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd) d.d.errorf("cannot infer value - %s 0x%x", msgBadDesc, d.bd)
} }
if !decodeFurther { if !decodeFurther {
@ -474,12 +593,12 @@ func (d *simpleDecDriver) DecodeNaked() {
// SimpleHandle is a Handle for a very simple encoding format. // SimpleHandle is a Handle for a very simple encoding format.
// //
// simple is a simplistic codec similar to binc, but not as compact. // simple is a simplistic codec similar to binc, but not as compact.
// - Encoding of a value is always preceeded by the descriptor byte (bd) // - Encoding of a value is always preceded by the descriptor byte (bd)
// - True, false, nil are encoded fully in 1 byte (the descriptor) // - True, false, nil are encoded fully in 1 byte (the descriptor)
// - Integers (intXXX, uintXXX) are encoded in 1, 2, 4 or 8 bytes (plus a descriptor byte). // - Integers (intXXX, uintXXX) are encoded in 1, 2, 4 or 8 bytes (plus a descriptor byte).
// There are positive (uintXXX and intXXX >= 0) and negative (intXXX < 0) integers. // There are positive (uintXXX and intXXX >= 0) and negative (intXXX < 0) integers.
// - Floats are encoded in 4 or 8 bytes (plus a descriptor byte) // - Floats are encoded in 4 or 8 bytes (plus a descriptor byte)
// - Lenght of containers (strings, bytes, array, map, extensions) // - Length of containers (strings, bytes, array, map, extensions)
// are encoded in 0, 1, 2, 4 or 8 bytes. // are encoded in 0, 1, 2, 4 or 8 bytes.
// Zero-length containers have no length encoded. // Zero-length containers have no length encoded.
// For others, the number of bytes is given by pow(2, bd%3) // For others, the number of bytes is given by pow(2, bd%3)
@ -487,31 +606,45 @@ func (d *simpleDecDriver) DecodeNaked() {
// - arrays are encoded as [bd] [length] [value]... // - arrays are encoded as [bd] [length] [value]...
// - extensions are encoded as [bd] [length] [tag] [byte]... // - extensions are encoded as [bd] [length] [tag] [byte]...
// - strings/bytearrays are encoded as [bd] [length] [byte]... // - strings/bytearrays are encoded as [bd] [length] [byte]...
// - time.Time are encoded as [bd] [length] [byte]...
// //
// The full spec will be published soon. // The full spec will be published soon.
type SimpleHandle struct { type SimpleHandle struct {
BasicHandle BasicHandle
binaryEncodingType binaryEncodingType
noElemSeparators
// EncZeroValuesAsNil says to encode zero values for numbers, bool, string, etc as nil
EncZeroValuesAsNil bool
// _ [1]uint64 // padding
} }
// Name returns the name of the handle: simple
func (h *SimpleHandle) Name() string { return "simple" }
// SetBytesExt sets an extension
func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{b: ext}) return h.SetExt(rt, tag, &extWrapper{ext, interfaceExtFailer{}})
} }
func (h *SimpleHandle) hasElemSeparators() bool { return true } // as it implements Write(Map|Array)XXX
func (h *SimpleHandle) newEncDriver(e *Encoder) encDriver { func (h *SimpleHandle) newEncDriver(e *Encoder) encDriver {
return &simpleEncDriver{e: e, w: e.w, h: h} return &simpleEncDriver{e: e, w: e.w, h: h}
} }
func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver { func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver {
return &simpleDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &simpleDecDriver{d: d, h: h, r: d.r, br: d.bytes}
} }
func (e *simpleEncDriver) reset() { func (e *simpleEncDriver) reset() {
e.c = 0
e.w = e.e.w e.w = e.e.w
} }
func (d *simpleDecDriver) reset() { func (d *simpleDecDriver) reset() {
d.r = d.d.r d.c = 0
d.r, d.br = d.d.r, d.d.bytes
d.bd, d.bdRead = 0, false d.bd, d.bdRead = 0, false
} }

View File

@ -34,7 +34,7 @@ def get_test_data_list():
True, True,
u"null", u"null",
None, None,
u"someday", u"some&day>some<day",
1328176922000002000, 1328176922000002000,
u"", u"",
-2206187877999998000, -2206187877999998000,
@ -84,7 +84,7 @@ def doRpcServer(port, stopTimeSec):
def EchoStruct(self, msg): def EchoStruct(self, msg):
return ("%s" % msg) return ("%s" % msg)
addr = msgpackrpc.Address('localhost', port) addr = msgpackrpc.Address('127.0.0.1', port)
server = msgpackrpc.Server(EchoHandler()) server = msgpackrpc.Server(EchoHandler())
server.listen(addr) server.listen(addr)
# run thread to stop it after stopTimeSec seconds if > 0 # run thread to stop it after stopTimeSec seconds if > 0
@ -96,14 +96,14 @@ def doRpcServer(port, stopTimeSec):
server.start() server.start()
def doRpcClientToPythonSvc(port): def doRpcClientToPythonSvc(port):
address = msgpackrpc.Address('localhost', port) address = msgpackrpc.Address('127.0.0.1', port)
client = msgpackrpc.Client(address, unpack_encoding='utf-8') client = msgpackrpc.Client(address, unpack_encoding='utf-8')
print client.call("Echo123", "A1", "B2", "C3") print client.call("Echo123", "A1", "B2", "C3")
print client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}) print client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})
def doRpcClientToGoSvc(port): def doRpcClientToGoSvc(port):
# print ">>>> port: ", port, " <<<<<" # print ">>>> port: ", port, " <<<<<"
address = msgpackrpc.Address('localhost', port) address = msgpackrpc.Address('127.0.0.1', port)
client = msgpackrpc.Client(address, unpack_encoding='utf-8') client = msgpackrpc.Client(address, unpack_encoding='utf-8')
print client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"]) print client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"])
print client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}) print client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})

View File

@ -1,80 +0,0 @@
#!/bin/bash
# Run all the different permutations of all the tests.
# This helps ensure that nothing gets broken.
_run() {
# 1. VARIATIONS: regular (t), canonical (c), IO R/W (i),
# binc-nosymbols (n), struct2array (s), intern string (e),
# json-indent (d), circular (l)
# 2. MODE: reflection (r), external (x), codecgen (g), unsafe (u), notfastpath (f)
# 3. OPTIONS: verbose (v), reset (z), must (m),
#
# Use combinations of mode to get exactly what you want,
# and then pass the variations you need.
ztags=""
zargs=""
local OPTIND
OPTIND=1
while getopts "_xurtcinsvgzmefdl" flag
do
case "x$flag" in
'xr') ;;
'xf') ztags="$ztags notfastpath" ;;
'xg') ztags="$ztags codecgen" ;;
'xx') ztags="$ztags x" ;;
'xu') ztags="$ztags unsafe" ;;
'xv') zargs="$zargs -tv" ;;
'xz') zargs="$zargs -tr" ;;
'xm') zargs="$zargs -tm" ;;
'xl') zargs="$zargs -tl" ;;
*) ;;
esac
done
# shift $((OPTIND-1))
printf '............. TAGS: %s .............\n' "$ztags"
# echo ">>>>>>> TAGS: $ztags"
OPTIND=1
while getopts "_xurtcinsvgzmefdl" flag
do
case "x$flag" in
'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;;
'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" $zargs -tc; sleep 2 ;;
'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" $zargs -ti; sleep 2 ;;
'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" -run=Binc $zargs -tn; sleep 2 ;;
'xs') printf ">>>>>>> TO_ARRAY : "; go test "-tags=$ztags" $zargs -ts; sleep 2 ;;
'xe') printf ">>>>>>> INTERN : "; go test "-tags=$ztags" $zargs -te; sleep 2 ;;
'xd') printf ">>>>>>> INDENT : ";
go test "-tags=$ztags" -run=JsonCodecsTable -td=-1 $zargs;
go test "-tags=$ztags" -run=JsonCodecsTable -td=8 $zargs;
sleep 2 ;;
*) ;;
esac
done
shift $((OPTIND-1))
OPTIND=1
}
# echo ">>>>>>> RUNNING VARIATIONS OF TESTS"
if [[ "x$@" = "x" ]]; then
# All: r, x, g, gu
_run "-_tcinsed_ml" # regular
_run "-_tcinsed_ml_z" # regular with reset
_run "-_tcinsed_ml_f" # regular with no fastpath (notfastpath)
_run "-x_tcinsed_ml" # external
_run "-gx_tcinsed_ml" # codecgen: requires external
_run "-gxu_tcinsed_ml" # codecgen + unsafe
elif [[ "x$@" = "x-Z" ]]; then
# Regular
_run "-_tcinsed_ml" # regular
_run "-_tcinsed_ml_z" # regular with reset
elif [[ "x$@" = "x-F" ]]; then
# regular with notfastpath
_run "-_tcinsed_ml_f" # regular
_run "-_tcinsed_ml_zf" # regular with reset
else
_run "$@"
fi

View File

@ -1,233 +0,0 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
package codec
import (
"fmt"
"reflect"
"time"
)
var (
timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
timeExtEncFn = func(rv reflect.Value) (bs []byte, err error) {
defer panicToErr(&err)
bs = timeExt{}.WriteExt(rv.Interface())
return
}
timeExtDecFn = func(rv reflect.Value, bs []byte) (err error) {
defer panicToErr(&err)
timeExt{}.ReadExt(rv.Interface(), bs)
return
}
)
type timeExt struct{}
func (x timeExt) WriteExt(v interface{}) (bs []byte) {
switch v2 := v.(type) {
case time.Time:
bs = encodeTime(v2)
case *time.Time:
bs = encodeTime(*v2)
default:
panic(fmt.Errorf("unsupported format for time conversion: expecting time.Time; got %T", v2))
}
return
}
func (x timeExt) ReadExt(v interface{}, bs []byte) {
tt, err := decodeTime(bs)
if err != nil {
panic(err)
}
*(v.(*time.Time)) = tt
}
func (x timeExt) ConvertExt(v interface{}) interface{} {
return x.WriteExt(v)
}
func (x timeExt) UpdateExt(v interface{}, src interface{}) {
x.ReadExt(v, src.([]byte))
}
// EncodeTime encodes a time.Time as a []byte, including
// information on the instant in time and UTC offset.
//
// Format Description
//
// A timestamp is composed of 3 components:
//
// - secs: signed integer representing seconds since unix epoch
// - nsces: unsigned integer representing fractional seconds as a
// nanosecond offset within secs, in the range 0 <= nsecs < 1e9
// - tz: signed integer representing timezone offset in minutes east of UTC,
// and a dst (daylight savings time) flag
//
// When encoding a timestamp, the first byte is the descriptor, which
// defines which components are encoded and how many bytes are used to
// encode secs and nsecs components. *If secs/nsecs is 0 or tz is UTC, it
// is not encoded in the byte array explicitly*.
//
// Descriptor 8 bits are of the form `A B C DDD EE`:
// A: Is secs component encoded? 1 = true
// B: Is nsecs component encoded? 1 = true
// C: Is tz component encoded? 1 = true
// DDD: Number of extra bytes for secs (range 0-7).
// If A = 1, secs encoded in DDD+1 bytes.
// If A = 0, secs is not encoded, and is assumed to be 0.
// If A = 1, then we need at least 1 byte to encode secs.
// DDD says the number of extra bytes beyond that 1.
// E.g. if DDD=0, then secs is represented in 1 byte.
// if DDD=2, then secs is represented in 3 bytes.
// EE: Number of extra bytes for nsecs (range 0-3).
// If B = 1, nsecs encoded in EE+1 bytes (similar to secs/DDD above)
//
// Following the descriptor bytes, subsequent bytes are:
//
// secs component encoded in `DDD + 1` bytes (if A == 1)
// nsecs component encoded in `EE + 1` bytes (if B == 1)
// tz component encoded in 2 bytes (if C == 1)
//
// secs and nsecs components are integers encoded in a BigEndian
// 2-complement encoding format.
//
// tz component is encoded as 2 bytes (16 bits). Most significant bit 15 to
// Least significant bit 0 are described below:
//
// Timezone offset has a range of -12:00 to +14:00 (ie -720 to +840 minutes).
// Bit 15 = have\_dst: set to 1 if we set the dst flag.
// Bit 14 = dst\_on: set to 1 if dst is in effect at the time, or 0 if not.
// Bits 13..0 = timezone offset in minutes. It is a signed integer in Big Endian format.
//
func encodeTime(t time.Time) []byte {
//t := rv.Interface().(time.Time)
tsecs, tnsecs := t.Unix(), t.Nanosecond()
var (
bd byte
btmp [8]byte
bs [16]byte
i int = 1
)
l := t.Location()
if l == time.UTC {
l = nil
}
if tsecs != 0 {
bd = bd | 0x80
bigen.PutUint64(btmp[:], uint64(tsecs))
f := pruneSignExt(btmp[:], tsecs >= 0)
bd = bd | (byte(7-f) << 2)
copy(bs[i:], btmp[f:])
i = i + (8 - f)
}
if tnsecs != 0 {
bd = bd | 0x40
bigen.PutUint32(btmp[:4], uint32(tnsecs))
f := pruneSignExt(btmp[:4], true)
bd = bd | byte(3-f)
copy(bs[i:], btmp[f:4])
i = i + (4 - f)
}
if l != nil {
bd = bd | 0x20
// Note that Go Libs do not give access to dst flag.
_, zoneOffset := t.Zone()
//zoneName, zoneOffset := t.Zone()
zoneOffset /= 60
z := uint16(zoneOffset)
bigen.PutUint16(btmp[:2], z)
// clear dst flags
bs[i] = btmp[0] & 0x3f
bs[i+1] = btmp[1]
i = i + 2
}
bs[0] = bd
return bs[0:i]
}
// DecodeTime decodes a []byte into a time.Time.
func decodeTime(bs []byte) (tt time.Time, err error) {
bd := bs[0]
var (
tsec int64
tnsec uint32
tz uint16
i byte = 1
i2 byte
n byte
)
if bd&(1<<7) != 0 {
var btmp [8]byte
n = ((bd >> 2) & 0x7) + 1
i2 = i + n
copy(btmp[8-n:], bs[i:i2])
//if first bit of bs[i] is set, then fill btmp[0..8-n] with 0xff (ie sign extend it)
if bs[i]&(1<<7) != 0 {
copy(btmp[0:8-n], bsAll0xff)
//for j,k := byte(0), 8-n; j < k; j++ { btmp[j] = 0xff }
}
i = i2
tsec = int64(bigen.Uint64(btmp[:]))
}
if bd&(1<<6) != 0 {
var btmp [4]byte
n = (bd & 0x3) + 1
i2 = i + n
copy(btmp[4-n:], bs[i:i2])
i = i2
tnsec = bigen.Uint32(btmp[:])
}
if bd&(1<<5) == 0 {
tt = time.Unix(tsec, int64(tnsec)).UTC()
return
}
// In stdlib time.Parse, when a date is parsed without a zone name, it uses "" as zone name.
// However, we need name here, so it can be shown when time is printed.
// Zone name is in form: UTC-08:00.
// Note that Go Libs do not give access to dst flag, so we ignore dst bits
i2 = i + 2
tz = bigen.Uint16(bs[i:i2])
i = i2
// sign extend sign bit into top 2 MSB (which were dst bits):
if tz&(1<<13) == 0 { // positive
tz = tz & 0x3fff //clear 2 MSBs: dst bits
} else { // negative
tz = tz | 0xc000 //set 2 MSBs: dst bits
//tzname[3] = '-' (TODO: verify. this works here)
}
tzint := int16(tz)
if tzint == 0 {
tt = time.Unix(tsec, int64(tnsec)).UTC()
} else {
// For Go Time, do not use a descriptive timezone.
// It's unnecessary, and makes it harder to do a reflect.DeepEqual.
// The Offset already tells what the offset should be, if not on UTC and unknown zone name.
// var zoneName = timeLocUTCName(tzint)
tt = time.Unix(tsec, int64(tnsec)).In(time.FixedZone("", int(tzint)*60))
}
return
}
func timeLocUTCName(tzint int16) string {
if tzint == 0 {
return "UTC"
}
var tzname = []byte("UTC+00:00")
//tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf. inline below.
//tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first
var tzhr, tzmin int16
if tzint < 0 {
tzname[3] = '-' // (TODO: verify. this works here)
tzhr, tzmin = -tzint/60, (-tzint)%60
} else {
tzhr, tzmin = tzint/60, tzint%60
}
tzname[4] = timeDigits[tzhr/10]
tzname[5] = timeDigits[tzhr%10]
tzname[7] = timeDigits[tzmin/10]
tzname[8] = timeDigits[tzmin%10]
return string(tzname)
//return time.FixedZone(string(tzname), int(tzint)*60)
}