Commit e73d66ce authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #37557 from sttts/sttts-update-ugorji

Automatic merge from submit-queue Update ugorji/go/codec godep In order to pick-up https://github.com/ugorji/go/issues/119 and to get rid of the workaround at https://github.com/kubernetes/kubernetes/pull/36909/files#diff-a09eb061a0fb0ef3c9ef9d696f1ad0b4R426.
parents 3371766d 9859bb37
...@@ -2209,11 +2209,11 @@ ...@@ -2209,11 +2209,11 @@
}, },
{ {
"ImportPath": "github.com/ugorji/go/codec", "ImportPath": "github.com/ugorji/go/codec",
"Rev": "f1f1a805ed361a0e078bb537e4ea78cd37dcf065" "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74"
}, },
{ {
"ImportPath": "github.com/ugorji/go/codec/codecgen", "ImportPath": "github.com/ugorji/go/codec/codecgen",
"Rev": "f1f1a805ed361a0e078bb537e4ea78cd37dcf065" "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74"
}, },
{ {
"ImportPath": "github.com/vishvananda/netlink", "ImportPath": "github.com/vishvananda/netlink",
......
...@@ -45,7 +45,7 @@ find_files() { ...@@ -45,7 +45,7 @@ find_files() {
IFS=$'\n' IFS=$'\n'
conflicts=($(find_files | sed 's|/.readonly||' | while read dir; do conflicts=($(find_files | sed 's|/.readonly||' | while read dir; do
dir=${dir#./} dir=${dir#./}
if kube::util::has_changes_against_upstream_branch "${branch}" "^${dir}/[^/]*\$" "/.readonly\$|/BUILD$|/zz_generated" &>/dev/null; then if kube::util::has_changes_against_upstream_branch "${branch}" "^${dir}/[^/]*\$" '/\.readonly$|/BUILD$|/zz_generated|/\.generated\.|\.proto$|\.pb\.go$' >/dev/null; then
echo "${dir}" echo "${dir}"
fi fi
done)) done))
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -161,13 +161,13 @@ func (x *TestResource) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -161,13 +161,13 @@ func (x *TestResource) CodecEncodeSelf(e *codec1978.Encoder) {
z.EncSendContainerState(codecSelfer_containerMapKey1234) z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("metadata")) r.EncodeString(codecSelferC_UTF81234, string("metadata"))
z.EncSendContainerState(codecSelfer_containerMapValue1234) z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy11 := &x.ObjectMeta yy12 := &x.ObjectMeta
yy11.CodecEncodeSelf(e) yy12.CodecEncodeSelf(e)
} }
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234) z.EncSendContainerState(codecSelfer_containerArrayElem1234)
yym13 := z.EncBinary() yym15 := z.EncBinary()
_ = yym13 _ = yym15
if false { if false {
} else { } else {
r.EncodeInt(int64(x.Value)) r.EncodeInt(int64(x.Value))
...@@ -176,8 +176,8 @@ func (x *TestResource) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -176,8 +176,8 @@ func (x *TestResource) CodecEncodeSelf(e *codec1978.Encoder) {
z.EncSendContainerState(codecSelfer_containerMapKey1234) z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("value")) r.EncodeString(codecSelferC_UTF81234, string("value"))
z.EncSendContainerState(codecSelfer_containerMapValue1234) z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym14 := z.EncBinary() yym16 := z.EncBinary()
_ = yym14 _ = yym16
if false { if false {
} else { } else {
r.EncodeInt(int64(x.Value)) r.EncodeInt(int64(x.Value))
...@@ -196,25 +196,25 @@ func (x *TestResource) CodecDecodeSelf(d *codec1978.Decoder) { ...@@ -196,25 +196,25 @@ func (x *TestResource) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
yym15 := z.DecBinary() yym1 := z.DecBinary()
_ = yym15 _ = yym1
if false { if false {
} else if z.HasExtensions() && z.DecExt(x) { } else if z.HasExtensions() && z.DecExt(x) {
} else { } else {
yyct16 := r.ContainerType() yyct2 := r.ContainerType()
if yyct16 == codecSelferValueTypeMap1234 { if yyct2 == codecSelferValueTypeMap1234 {
yyl16 := r.ReadMapStart() yyl2 := r.ReadMapStart()
if yyl16 == 0 { if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerMapEnd1234) z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} else { } else {
x.codecDecodeSelfFromMap(yyl16, d) x.codecDecodeSelfFromMap(yyl2, d)
} }
} else if yyct16 == codecSelferValueTypeArray1234 { } else if yyct2 == codecSelferValueTypeArray1234 {
yyl16 := r.ReadArrayStart() yyl2 := r.ReadArrayStart()
if yyl16 == 0 { if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
x.codecDecodeSelfFromArray(yyl16, d) x.codecDecodeSelfFromArray(yyl2, d)
} }
} else { } else {
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
...@@ -226,12 +226,12 @@ func (x *TestResource) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { ...@@ -226,12 +226,12 @@ func (x *TestResource) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yys17Slc = z.DecScratchBuffer() // default slice to decode into var yys3Slc = z.DecScratchBuffer() // default slice to decode into
_ = yys17Slc _ = yys3Slc
var yyhl17 bool = l >= 0 var yyhl3 bool = l >= 0
for yyj17 := 0; ; yyj17++ { for yyj3 := 0; ; yyj3++ {
if yyhl17 { if yyhl3 {
if yyj17 >= l { if yyj3 >= l {
break break
} }
} else { } else {
...@@ -240,39 +240,57 @@ func (x *TestResource) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { ...@@ -240,39 +240,57 @@ func (x *TestResource) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
} }
} }
z.DecSendContainerState(codecSelfer_containerMapKey1234) z.DecSendContainerState(codecSelfer_containerMapKey1234)
yys17Slc = r.DecodeBytes(yys17Slc, true, true) yys3Slc = r.DecodeBytes(yys3Slc, true, true)
yys17 := string(yys17Slc) yys3 := string(yys3Slc)
z.DecSendContainerState(codecSelfer_containerMapValue1234) z.DecSendContainerState(codecSelfer_containerMapValue1234)
switch yys17 { switch yys3 {
case "kind": case "kind":
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Kind = "" x.Kind = ""
} else { } else {
x.Kind = string(r.DecodeString()) yyv4 := &x.Kind
yym5 := z.DecBinary()
_ = yym5
if false {
} else {
*((*string)(yyv4)) = r.DecodeString()
}
} }
case "apiVersion": case "apiVersion":
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.APIVersion = "" x.APIVersion = ""
} else { } else {
x.APIVersion = string(r.DecodeString()) yyv6 := &x.APIVersion
yym7 := z.DecBinary()
_ = yym7
if false {
} else {
*((*string)(yyv6)) = r.DecodeString()
}
} }
case "metadata": case "metadata":
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ObjectMeta = pkg2_v1.ObjectMeta{} x.ObjectMeta = pkg2_v1.ObjectMeta{}
} else { } else {
yyv20 := &x.ObjectMeta yyv8 := &x.ObjectMeta
yyv20.CodecDecodeSelf(d) yyv8.CodecDecodeSelf(d)
} }
case "value": case "value":
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Value = 0 x.Value = 0
} else { } else {
x.Value = int(r.DecodeInt(codecSelferBitsize1234)) yyv9 := &x.Value
yym10 := z.DecBinary()
_ = yym10
if false {
} else {
*((*int)(yyv9)) = int(r.DecodeInt(codecSelferBitsize1234))
}
} }
default: default:
z.DecStructFieldNotFound(-1, yys17) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys17 } // end switch yys3
} // end for yyj17 } // end for yyj3
z.DecSendContainerState(codecSelfer_containerMapEnd1234) z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} }
...@@ -280,16 +298,16 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -280,16 +298,16 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj22 int var yyj11 int
var yyb22 bool var yyb11 bool
var yyhl22 bool = l >= 0 var yyhl11 bool = l >= 0
yyj22++ yyj11++
if yyhl22 { if yyhl11 {
yyb22 = yyj22 > l yyb11 = yyj11 > l
} else { } else {
yyb22 = r.CheckBreak() yyb11 = r.CheckBreak()
} }
if yyb22 { if yyb11 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -297,15 +315,21 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -297,15 +315,21 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Kind = "" x.Kind = ""
} else { } else {
x.Kind = string(r.DecodeString()) yyv12 := &x.Kind
yym13 := z.DecBinary()
_ = yym13
if false {
} else {
*((*string)(yyv12)) = r.DecodeString()
}
} }
yyj22++ yyj11++
if yyhl22 { if yyhl11 {
yyb22 = yyj22 > l yyb11 = yyj11 > l
} else { } else {
yyb22 = r.CheckBreak() yyb11 = r.CheckBreak()
} }
if yyb22 { if yyb11 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -313,15 +337,21 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -313,15 +337,21 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.APIVersion = "" x.APIVersion = ""
} else { } else {
x.APIVersion = string(r.DecodeString()) yyv14 := &x.APIVersion
yym15 := z.DecBinary()
_ = yym15
if false {
} else {
*((*string)(yyv14)) = r.DecodeString()
}
} }
yyj22++ yyj11++
if yyhl22 { if yyhl11 {
yyb22 = yyj22 > l yyb11 = yyj11 > l
} else { } else {
yyb22 = r.CheckBreak() yyb11 = r.CheckBreak()
} }
if yyb22 { if yyb11 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -329,16 +359,16 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -329,16 +359,16 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ObjectMeta = pkg2_v1.ObjectMeta{} x.ObjectMeta = pkg2_v1.ObjectMeta{}
} else { } else {
yyv25 := &x.ObjectMeta yyv16 := &x.ObjectMeta
yyv25.CodecDecodeSelf(d) yyv16.CodecDecodeSelf(d)
} }
yyj22++ yyj11++
if yyhl22 { if yyhl11 {
yyb22 = yyj22 > l yyb11 = yyj11 > l
} else { } else {
yyb22 = r.CheckBreak() yyb11 = r.CheckBreak()
} }
if yyb22 { if yyb11 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -346,20 +376,26 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -346,20 +376,26 @@ func (x *TestResource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Value = 0 x.Value = 0
} else { } else {
x.Value = int(r.DecodeInt(codecSelferBitsize1234)) yyv17 := &x.Value
yym18 := z.DecBinary()
_ = yym18
if false {
} else {
*((*int)(yyv17)) = int(r.DecodeInt(codecSelferBitsize1234))
}
} }
for { for {
yyj22++ yyj11++
if yyhl22 { if yyhl11 {
yyb22 = yyj22 > l yyb11 = yyj11 > l
} else { } else {
yyb22 = r.CheckBreak() yyb11 = r.CheckBreak()
} }
if yyb22 { if yyb11 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj22-1, "") z.DecStructFieldNotFound(yyj11-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }
...@@ -29,8 +29,6 @@ import ( ...@@ -29,8 +29,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/ugorji/go/codec"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
) )
...@@ -445,27 +443,6 @@ func (vs Verbs) String() string { ...@@ -445,27 +443,6 @@ func (vs Verbs) String() string {
return fmt.Sprintf("%v", []string(vs)) return fmt.Sprintf("%v", []string(vs))
} }
// CodecEncodeSelf is part of the codec.Selfer interface.
func (vs *Verbs) CodecEncodeSelf(encoder *codec.Encoder) {
encoder.Encode(vs)
}
// CodecDecodeSelf is part of the codec.Selfer interface. It is overwritten here to make sure
// that an empty verbs list is not decoded as nil. On the other hand, an undefined verbs list
// will lead to nil because this decoding for Verbs is not invoked.
//
// TODO(sttts): this is due to a ugorji regression: https://github.com/ugorji/go/issues/119. Remove the
// workaround when the regression is fixed.
func (vs *Verbs) CodecDecodeSelf(decoder *codec.Decoder) {
m := []string{}
decoder.Decode(&m)
if len(m) == 0 {
*vs = []string{}
} else {
*vs = m
}
}
// APIResourceList is a list of APIResource, it is used to expose the name of the // APIResourceList is a list of APIResource, it is used to expose the name of the
// resources supported in a specific group and version, and if the resource // resources supported in a specific group and version, and if the resource
// is namespaced. // is namespaced.
......
...@@ -24,7 +24,7 @@ import ( ...@@ -24,7 +24,7 @@ import (
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
) )
func TestVerbsMarshalJSON(t *testing.T) { func TestVerbsUgorjiMarshalJSON(t *testing.T) {
cases := []struct { cases := []struct {
input APIResource input APIResource
result string result string
...@@ -40,12 +40,12 @@ func TestVerbsMarshalJSON(t *testing.T) { ...@@ -40,12 +40,12 @@ func TestVerbsMarshalJSON(t *testing.T) {
t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err) t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err)
} }
if string(result) != c.result { if string(result) != c.result {
t.Errorf("[%d] Failed to marshal input: '%v': expected %+v, got %q", i, c.input, c.result, string(result)) t.Errorf("[%d] Failed to marshal input: '%v': expected '%v', got '%v'", i, c.input, c.result, string(result))
} }
} }
} }
func TestVerbsUnmarshalJSON(t *testing.T) { func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
cases := []struct { cases := []struct {
input string input string
result APIResource result APIResource
...@@ -67,7 +67,29 @@ func TestVerbsUnmarshalJSON(t *testing.T) { ...@@ -67,7 +67,29 @@ func TestVerbsUnmarshalJSON(t *testing.T) {
} }
} }
func TestVerbsUgorjiUnmarshalJSON(t *testing.T) { // TestUgorjiMarshalJSONWithOmit tests that we don't have regressions regarding nil and empty slices with "omit"
func TestUgorjiMarshalJSONWithOmit(t *testing.T) {
cases := []struct {
input LabelSelector
result string
}{
{LabelSelector{}, `{}`},
{LabelSelector{MatchExpressions: []LabelSelectorRequirement{}}, `{}`},
{LabelSelector{MatchExpressions: []LabelSelectorRequirement{{}}}, `{"matchExpressions":[{"key":"","operator":""}]}`},
}
for i, c := range cases {
result, err := json.Marshal(&c.input)
if err != nil {
t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err)
}
if string(result) != c.result {
t.Errorf("[%d] Failed to marshal input: '%v': expected '%v', got '%v'", i, c.input, c.result, string(result))
}
}
}
func TestVerbsUnmarshalJSON(t *testing.T) {
cases := []struct { cases := []struct {
input string input string
result APIResource result APIResource
......
...@@ -6290,11 +6290,14 @@ go_library( ...@@ -6290,11 +6290,14 @@ go_library(
"github.com/ugorji/go/codec/binc.go", "github.com/ugorji/go/codec/binc.go",
"github.com/ugorji/go/codec/cbor.go", "github.com/ugorji/go/codec/cbor.go",
"github.com/ugorji/go/codec/decode.go", "github.com/ugorji/go/codec/decode.go",
"github.com/ugorji/go/codec/decode_go.go",
"github.com/ugorji/go/codec/encode.go", "github.com/ugorji/go/codec/encode.go",
"github.com/ugorji/go/codec/fast-path.generated.go", "github.com/ugorji/go/codec/fast-path.generated.go",
"github.com/ugorji/go/codec/gen.generated.go", "github.com/ugorji/go/codec/gen.generated.go",
"github.com/ugorji/go/codec/gen.go", "github.com/ugorji/go/codec/gen.go",
"github.com/ugorji/go/codec/gen-helper.generated.go", "github.com/ugorji/go/codec/gen-helper.generated.go",
"github.com/ugorji/go/codec/gen_16.go",
"github.com/ugorji/go/codec/gen_17.go",
"github.com/ugorji/go/codec/helper.go", "github.com/ugorji/go/codec/helper.go",
"github.com/ugorji/go/codec/helper_internal.go", "github.com/ugorji/go/codec/helper_internal.go",
"github.com/ugorji/go/codec/helper_not_unsafe.go", "github.com/ugorji/go/codec/helper_not_unsafe.go",
...@@ -12378,7 +12381,6 @@ go_library( ...@@ -12378,7 +12381,6 @@ go_library(
"//vendor:github.com/gogo/protobuf/proto", "//vendor:github.com/gogo/protobuf/proto",
"//vendor:github.com/gogo/protobuf/sortkeys", "//vendor:github.com/gogo/protobuf/sortkeys",
"//vendor:github.com/google/gofuzz", "//vendor:github.com/google/gofuzz",
"//vendor:github.com/ugorji/go/codec",
"//vendor:k8s.io/apimachinery/pkg/conversion", "//vendor:k8s.io/apimachinery/pkg/conversion",
"//vendor:k8s.io/apimachinery/pkg/genericapiserver/openapi/common", "//vendor:k8s.io/apimachinery/pkg/genericapiserver/openapi/common",
"//vendor:k8s.io/apimachinery/pkg/labels", "//vendor:k8s.io/apimachinery/pkg/labels",
......
...@@ -64,10 +64,11 @@ Rich Feature Set includes: ...@@ -64,10 +64,11 @@ Rich Feature Set includes:
- Never silently skip data when decoding. - Never silently skip data when decoding.
User decides whether to return an error or silently skip data when keys or indexes User decides whether to return an error or silently skip data when keys or indexes
in the data stream do not map to fields in the struct. in the data stream do not map to fields in the struct.
- Detect and error when encoding a cyclic reference (instead of stack overflow shutdown)
- 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:
...@@ -171,6 +172,8 @@ package codec ...@@ -171,6 +172,8 @@ package codec
// TODO: // TODO:
// //
// - optimization for codecgen:
// if len of entity is <= 3 words, then support a value receiver for encode.
// - (En|De)coder should store an error when it occurs. // - (En|De)coder should store an error when it occurs.
// Until reset, subsequent calls return that error that was stored. // Until reset, subsequent calls return that error that was stored.
// This means that free panics must go away. // This means that free panics must go away.
...@@ -178,16 +181,19 @@ package codec ...@@ -178,16 +181,19 @@ package codec
// - Decoding using a chan is good, but incurs concurrency costs. // - Decoding using a chan is good, but incurs concurrency costs.
// This is because there's no fast way to use a channel without it // This is because there's no fast way to use a channel without it
// having to switch goroutines constantly. // having to switch goroutines constantly.
// Callback pattern is still the best. Maybe cnsider supporting something like: // Callback pattern is still the best. Maybe consider supporting something like:
// type X struct { // type X struct {
// Name string // Name string
// Ys []Y // Ys []Y
// Ys chan <- Y // Ys chan <- Y
// Ys func(interface{}) -> call this interface for each entry in there. // Ys func(Y) -> call this function for each entry
// } // }
// - Consider adding a isZeroer interface { isZero() bool } // - Consider adding a isZeroer interface { isZero() bool }
// It is used within isEmpty, for omitEmpty support. // It is used within isEmpty, for omitEmpty support.
// - Consider making Handle used AS-IS within the encoding/decoding session. // - Consider making Handle used AS-IS within the encoding/decoding session.
// This means that we don't cache Handle information within the (En|De)coder, // This means that we don't cache Handle information within the (En|De)coder,
// except we really need it at Reset(...) // except we really need it at Reset(...)
// - Handle recursive types during encoding/decoding? // - Consider adding math/big support
// - Consider reducing the size of the generated functions:
// Maybe use one loop, and put the conditionals in the loop.
// for ... { if cLen > 0 { if j == cLen { break } } else if dd.CheckBreak() { break } }
...@@ -68,7 +68,7 @@ Rich Feature Set includes: ...@@ -68,7 +68,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:
......
...@@ -348,6 +348,13 @@ func (d *bincDecDriver) readNextBd() { ...@@ -348,6 +348,13 @@ 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.vd == bincVdSpecial && d.vs == bincSpNil { if d.vd == bincVdSpecial && d.vs == bincSpNil {
return valueTypeNil return valueTypeNil
...@@ -705,7 +712,7 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool) ...@@ -705,7 +712,7 @@ 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)
...@@ -908,10 +915,14 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver { ...@@ -908,10 +915,14 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
func (e *bincEncDriver) reset() { func (e *bincEncDriver) reset() {
e.w = e.e.w e.w = e.e.w
e.s = 0
e.m = nil
} }
func (d *bincDecDriver) reset() { func (d *bincDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.s = nil
d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0
} }
var _ decDriver = (*bincDecDriver)(nil) var _ decDriver = (*bincDecDriver)(nil)
......
...@@ -188,6 +188,13 @@ func (d *cborDecDriver) readNextBd() { ...@@ -188,6 +188,13 @@ 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.bd == cborBdNil { if d.bd == cborBdNil {
return valueTypeNil return valueTypeNil
...@@ -508,7 +515,7 @@ func (d *cborDecDriver) DecodeNaked() { ...@@ -508,7 +515,7 @@ func (d *cborDecDriver) DecodeNaked() {
n.v = valueTypeExt n.v = valueTypeExt
n.u = d.decUint() n.u = d.decUint()
n.l = nil n.l = nil
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
default: default:
...@@ -578,6 +585,7 @@ func (e *cborEncDriver) reset() { ...@@ -578,6 +585,7 @@ func (e *cborEncDriver) reset() {
func (d *cborDecDriver) reset() { func (d *cborDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.bd, d.bdRead = 0, false
} }
var _ decDriver = (*cborDecDriver)(nil) var _ decDriver = (*cborDecDriver)(nil)
......
...@@ -23,6 +23,7 @@ Usage of codecgen: ...@@ -23,6 +23,7 @@ Usage of codecgen:
-c="github.com/ugorji/go/codec": codec path -c="github.com/ugorji/go/codec": codec path
-o="": out file -o="": out file
-r=".*": regex for type name to match -r=".*": regex for type name to match
-nr="": regex for type name to exclude
-rt="": tags for go run -rt="": tags for go run
-t="": build tag to put in file -t="": build tag to put in file
-u=false: Use unsafe, e.g. to avoid unnecessary allocation on []byte->string -u=false: Use unsafe, e.g. to avoid unnecessary allocation on []byte->string
......
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv" "strconv"
"strings"
"text/template" "text/template"
"time" "time"
) )
...@@ -82,7 +83,7 @@ func CodecGenTempWrite{{ .RandString }}() { ...@@ -82,7 +83,7 @@ func CodecGenTempWrite{{ .RandString }}() {
// fout contains Codec(En|De)codeSelf implementations for every type T. // fout contains Codec(En|De)codeSelf implementations for every type T.
// //
func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, goRunTag string, func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, goRunTag string,
st string, regexName *regexp.Regexp, deleteTempFile bool, infiles ...string) (err error) { st string, regexName *regexp.Regexp, notRegexName *regexp.Regexp, deleteTempFile bool, infiles ...string) (err error) {
// For each file, grab AST, find each type, and write a call to it. // For each file, grab AST, find each type, and write a call to it.
if len(infiles) == 0 { if len(infiles) == 0 {
return return
...@@ -135,6 +136,16 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, ...@@ -135,6 +136,16 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool,
if tv.ImportPath == tv.CodecImportPath { if tv.ImportPath == tv.CodecImportPath {
tv.CodecPkgFiles = true tv.CodecPkgFiles = true
tv.CodecPkgName = "codec" tv.CodecPkgName = "codec"
} else {
// HACK: always handle vendoring. It should be typically on in go 1.6, 1.7
s := tv.ImportPath
const vendorStart = "vendor/"
const vendorInline = "/vendor/"
if i := strings.LastIndex(s, vendorInline); i >= 0 {
tv.ImportPath = s[i+len(vendorInline):]
} else if strings.HasPrefix(s, vendorStart) {
tv.ImportPath = s[len(vendorStart):]
}
} }
astfiles := make([]*ast.File, len(infiles)) astfiles := make([]*ast.File, len(infiles))
for i, infile := range infiles { for i, infile := range infiles {
...@@ -160,6 +171,31 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, ...@@ -160,6 +171,31 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool,
} }
} }
// keep track of types with selfer methods
// selferMethods := []string{"CodecEncodeSelf", "CodecDecodeSelf"}
selferEncTyps := make(map[string]bool)
selferDecTyps := make(map[string]bool)
for _, f := range astfiles {
for _, d := range f.Decls {
// if fd, ok := d.(*ast.FuncDecl); ok && fd.Recv != nil && fd.Recv.NumFields() == 1 {
if fd, ok := d.(*ast.FuncDecl); ok && fd.Recv != nil && len(fd.Recv.List) == 1 {
recvType := fd.Recv.List[0].Type
if ptr, ok := recvType.(*ast.StarExpr); ok {
recvType = ptr.X
}
if id, ok := recvType.(*ast.Ident); ok {
switch fd.Name.Name {
case "CodecEncodeSelf":
selferEncTyps[id.Name] = true
case "CodecDecodeSelf":
selferDecTyps[id.Name] = true
}
}
}
}
}
// now find types
for _, f := range astfiles { for _, f := range astfiles {
for _, d := range f.Decls { for _, d := range f.Decls {
if gd, ok := d.(*ast.GenDecl); ok { if gd, ok := d.(*ast.GenDecl); ok {
...@@ -180,7 +216,14 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, ...@@ -180,7 +216,14 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool,
// FuncType, InterfaceType, StarExpr (ptr), etc // FuncType, InterfaceType, StarExpr (ptr), etc
switch td.Type.(type) { switch td.Type.(type) {
case *ast.StructType, *ast.Ident, *ast.MapType, *ast.ArrayType, *ast.ChanType: case *ast.StructType, *ast.Ident, *ast.MapType, *ast.ArrayType, *ast.ChanType:
if regexName.FindStringIndex(td.Name.Name) != nil { // only add to tv.Types iff
// - it matches per the -r parameter
// - it doesn't match per the -nr parameter
// - it doesn't have any of the Selfer methods in the file
if regexName.FindStringIndex(td.Name.Name) != nil &&
notRegexName.FindStringIndex(td.Name.Name) == nil &&
!selferEncTyps[td.Name.Name] &&
!selferDecTyps[td.Name.Name] {
tv.Types = append(tv.Types, td.Name.Name) tv.Types = append(tv.Types, td.Name.Name)
} }
} }
...@@ -259,6 +302,7 @@ func main() { ...@@ -259,6 +302,7 @@ func main() {
c := flag.String("c", genCodecPath, "codec path") c := flag.String("c", genCodecPath, "codec path")
t := flag.String("t", "", "build tag to put in file") t := flag.String("t", "", "build tag to put in file")
r := flag.String("r", ".*", "regex for type name to match") r := flag.String("r", ".*", "regex for type name to match")
nr := flag.String("nr", "^$", "regex for type name to exclude")
rt := flag.String("rt", "", "tags for go run") rt := flag.String("rt", "", "tags for go run")
st := flag.String("st", "codec,json", "struct tag keys to introspect") st := flag.String("st", "codec,json", "struct tag keys to introspect")
x := flag.Bool("x", false, "keep temp file") x := flag.Bool("x", false, "keep temp file")
...@@ -266,7 +310,7 @@ func main() { ...@@ -266,7 +310,7 @@ func main() {
d := flag.Int64("d", 0, "random identifier for use in generated code") d := flag.Int64("d", 0, "random identifier for use in generated code")
flag.Parse() flag.Parse()
if err := Generate(*o, *t, *c, *d, *u, *rt, *st, if err := Generate(*o, *t, *c, *d, *u, *rt, *st,
regexp.MustCompile(*r), !*x, flag.Args()...); err != nil { regexp.MustCompile(*r), regexp.MustCompile(*nr), !*x, flag.Args()...); err != nil {
fmt.Fprintf(os.Stderr, "codecgen error: %v\n", err) fmt.Fprintf(os.Stderr, "codecgen error: %v\n", err)
os.Exit(1) os.Exit(1)
} }
......
...@@ -91,10 +91,12 @@ type decDriver interface { ...@@ -91,10 +91,12 @@ type decDriver interface {
uncacheRead() uncacheRead()
} }
type decNoSeparator struct{} type decNoSeparator struct {
}
func (_ decNoSeparator) ReadEnd() {}
func (_ decNoSeparator) ReadEnd() {} // func (_ decNoSeparator) uncacheRead() {}
func (_ decNoSeparator) uncacheRead() {}
type DecodeOptions struct { type DecodeOptions struct {
// MapType specifies type to use during schema-less decoding of a map in the stream. // MapType specifies type to use during schema-less decoding of a map in the stream.
...@@ -161,6 +163,15 @@ type DecodeOptions struct { ...@@ -161,6 +163,15 @@ type DecodeOptions struct {
// Note: Handles will be smart when using the intern functionality. // Note: Handles will be smart when using the intern functionality.
// So everything will not be interned. // So everything will not be interned.
InternString bool InternString bool
// PreferArrayOverSlice controls whether to decode to an array or a slice.
//
// This only impacts decoding into a nil interface{}.
// Consequently, it has no effect on codecgen.
//
// *Note*: This only applies if using go1.5 and above,
// as it requires reflect.ArrayOf support which was absent before go1.5.
PreferArrayOverSlice bool
} }
// ------------------------------------ // ------------------------------------
...@@ -433,6 +444,10 @@ func (f *decFnInfo) rawExt(rv reflect.Value) { ...@@ -433,6 +444,10 @@ func (f *decFnInfo) rawExt(rv reflect.Value) {
f.d.d.DecodeExt(rv.Addr().Interface(), 0, nil) f.d.d.DecodeExt(rv.Addr().Interface(), 0, nil)
} }
func (f *decFnInfo) raw(rv reflect.Value) {
rv.SetBytes(f.d.raw())
}
func (f *decFnInfo) ext(rv reflect.Value) { func (f *decFnInfo) ext(rv reflect.Value) {
f.d.d.DecodeExt(rv.Addr().Interface(), f.xfTag, f.xfFn) f.d.d.DecodeExt(rv.Addr().Interface(), f.xfTag, f.xfFn)
} }
...@@ -583,14 +598,16 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) { ...@@ -583,14 +598,16 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) {
if d.mtid == 0 || d.mtid == mapIntfIntfTypId { if d.mtid == 0 || d.mtid == mapIntfIntfTypId {
l := len(n.ms) l := len(n.ms)
n.ms = append(n.ms, nil) n.ms = append(n.ms, nil)
d.decode(&n.ms[l]) var v2 interface{} = &n.ms[l]
rvn = reflect.ValueOf(&n.ms[l]).Elem() d.decode(v2)
rvn = reflect.ValueOf(v2).Elem()
n.ms = n.ms[:l] n.ms = n.ms[:l]
} else if d.mtid == mapStrIntfTypId { // for json performance } else if d.mtid == mapStrIntfTypId { // for json performance
l := len(n.ns) l := len(n.ns)
n.ns = append(n.ns, nil) n.ns = append(n.ns, nil)
d.decode(&n.ns[l]) var v2 interface{} = &n.ns[l]
rvn = reflect.ValueOf(&n.ns[l]).Elem() d.decode(v2)
rvn = reflect.ValueOf(v2).Elem()
n.ns = n.ns[:l] n.ns = n.ns[:l]
} else { } else {
rvn = reflect.New(d.h.MapType).Elem() rvn = reflect.New(d.h.MapType).Elem()
...@@ -601,9 +618,13 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) { ...@@ -601,9 +618,13 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) {
if d.stid == 0 || d.stid == intfSliceTypId { if d.stid == 0 || d.stid == intfSliceTypId {
l := len(n.ss) l := len(n.ss)
n.ss = append(n.ss, nil) n.ss = append(n.ss, nil)
d.decode(&n.ss[l]) var v2 interface{} = &n.ss[l]
rvn = reflect.ValueOf(&n.ss[l]).Elem() d.decode(v2)
n.ss = n.ss[:l] n.ss = n.ss[:l]
rvn = reflect.ValueOf(v2).Elem()
if reflectArrayOfSupported && d.stid == 0 && d.h.PreferArrayOverSlice {
rvn = reflectArrayOf(rvn)
}
} else { } else {
rvn = reflect.New(d.h.SliceType).Elem() rvn = reflect.New(d.h.SliceType).Elem()
d.decodeValue(rvn, nil) d.decodeValue(rvn, nil)
...@@ -615,9 +636,9 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) { ...@@ -615,9 +636,9 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) {
l := len(n.is) l := len(n.is)
n.is = append(n.is, nil) n.is = append(n.is, nil)
v2 := &n.is[l] v2 := &n.is[l]
n.is = n.is[:l]
d.decode(v2) d.decode(v2)
v = *v2 v = *v2
n.is = n.is[:l]
} }
bfn := d.h.getExtForTag(tag) bfn := d.h.getExtForTag(tag)
if bfn == nil { if bfn == nil {
...@@ -1166,7 +1187,7 @@ type decRtidFn struct { ...@@ -1166,7 +1187,7 @@ type decRtidFn struct {
// primitives are being decoded. // primitives are being decoded.
// //
// maps and arrays are not handled by this mechanism. // maps and arrays are not handled by this mechanism.
// However, RawExt is, and we accomodate for extensions that decode // However, RawExt is, and we accommodate for extensions that decode
// RawExt from DecodeNaked, but need to decode the value subsequently. // RawExt from DecodeNaked, but need to decode the value subsequently.
// kInterfaceNaked and swallow, which call DecodeNaked, handle this caveat. // kInterfaceNaked and swallow, which call DecodeNaked, handle this caveat.
// //
...@@ -1453,8 +1474,8 @@ func (d *Decoder) swallow() { ...@@ -1453,8 +1474,8 @@ func (d *Decoder) swallow() {
l := len(n.is) l := len(n.is)
n.is = append(n.is, nil) n.is = append(n.is, nil)
v2 := &n.is[l] v2 := &n.is[l]
n.is = n.is[:l]
d.decode(v2) d.decode(v2)
n.is = n.is[:l]
} }
} }
} }
...@@ -1504,6 +1525,8 @@ func (d *Decoder) decode(iv interface{}) { ...@@ -1504,6 +1525,8 @@ func (d *Decoder) decode(iv interface{}) {
*v = 0 *v = 0
case *[]uint8: case *[]uint8:
*v = nil *v = nil
case *Raw:
*v = nil
case reflect.Value: case reflect.Value:
if v.Kind() != reflect.Ptr || v.IsNil() { if v.Kind() != reflect.Ptr || v.IsNil() {
d.errNotValidPtrValue(v) d.errNotValidPtrValue(v)
...@@ -1543,7 +1566,6 @@ func (d *Decoder) decode(iv interface{}) { ...@@ -1543,7 +1566,6 @@ func (d *Decoder) decode(iv interface{}) {
d.decodeValueNotNil(v.Elem(), nil) d.decodeValueNotNil(v.Elem(), nil)
case *string: case *string:
*v = d.d.DecodeString() *v = d.d.DecodeString()
case *bool: case *bool:
*v = d.d.DecodeBool() *v = d.d.DecodeBool()
...@@ -1574,6 +1596,9 @@ func (d *Decoder) decode(iv interface{}) { ...@@ -1574,6 +1596,9 @@ func (d *Decoder) decode(iv interface{}) {
case *[]uint8: case *[]uint8:
*v = d.d.DecodeBytes(*v, false, false) *v = d.d.DecodeBytes(*v, false, false)
case *Raw:
*v = d.raw()
case *interface{}: case *interface{}:
d.decodeValueNotNil(reflect.ValueOf(iv).Elem(), nil) d.decodeValueNotNil(reflect.ValueOf(iv).Elem(), nil)
...@@ -1695,6 +1720,8 @@ func (d *Decoder) getDecFn(rt reflect.Type, checkFastpath, checkCodecSelfer bool ...@@ -1695,6 +1720,8 @@ func (d *Decoder) getDecFn(rt reflect.Type, checkFastpath, checkCodecSelfer bool
fn.f = (*decFnInfo).selferUnmarshal fn.f = (*decFnInfo).selferUnmarshal
} else if rtid == rawExtTypId { } else if rtid == rawExtTypId {
fn.f = (*decFnInfo).rawExt fn.f = (*decFnInfo).rawExt
} else if rtid == rawTypId {
fn.f = (*decFnInfo).raw
} else if d.d.IsBuiltinType(rtid) { } else if d.d.IsBuiltinType(rtid) {
fn.f = (*decFnInfo).builtin fn.f = (*decFnInfo).builtin
} else if xfFn := d.h.getExt(rtid); xfFn != nil { } else if xfFn := d.h.getExt(rtid); xfFn != nil {
...@@ -1793,12 +1820,13 @@ func (d *Decoder) getDecFn(rt reflect.Type, checkFastpath, checkCodecSelfer bool ...@@ -1793,12 +1820,13 @@ func (d *Decoder) getDecFn(rt reflect.Type, checkFastpath, checkCodecSelfer bool
} }
func (d *Decoder) structFieldNotFound(index int, rvkencname string) { func (d *Decoder) structFieldNotFound(index int, rvkencname string) {
// NOTE: rvkencname may be a stringView, so don't pass it to another function.
if d.h.ErrorIfNoField { if d.h.ErrorIfNoField {
if index >= 0 { if index >= 0 {
d.errorf("no matching struct field found when decoding stream array at index %v", index) d.errorf("no matching struct field found when decoding stream array at index %v", index)
return return
} else if rvkencname != "" { } else if rvkencname != "" {
d.errorf("no matching struct field found when decoding stream map with key %s", rvkencname) d.errorf("no matching struct field found when decoding stream map with key " + rvkencname)
return return
} }
} }
...@@ -1862,6 +1890,7 @@ func (d *Decoder) intern(s string) { ...@@ -1862,6 +1890,7 @@ func (d *Decoder) intern(s string) {
} }
} }
// nextValueBytes returns the next value in the stream as a set of bytes.
func (d *Decoder) nextValueBytes() []byte { func (d *Decoder) nextValueBytes() []byte {
d.d.uncacheRead() d.d.uncacheRead()
d.r.track() d.r.track()
...@@ -1869,6 +1898,15 @@ func (d *Decoder) nextValueBytes() []byte { ...@@ -1869,6 +1898,15 @@ func (d *Decoder) nextValueBytes() []byte {
return d.r.stopTrack() return d.r.stopTrack()
} }
func (d *Decoder) raw() []byte {
// ensure that this is not a view into the bytes
// i.e. make new copy always.
bs := d.nextValueBytes()
bs2 := make([]byte, len(bs))
copy(bs2, bs)
return bs2
}
// -------------------------------------------------- // --------------------------------------------------
// decSliceHelper assists when decoding into a slice, from a map or an array in the stream. // decSliceHelper assists when decoding into a slice, from a map or an array in the stream.
......
// 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.
// +build go1.5
package codec
import "reflect"
const reflectArrayOfSupported = true
func reflectArrayOf(rvn reflect.Value) (rvn2 reflect.Value) {
rvn2 = reflect.New(reflect.ArrayOf(rvn.Len(), intfTyp)).Elem()
reflect.Copy(rvn2, rvn)
return
}
// 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.
// +build !go1.5
package codec
import "reflect"
const reflectArrayOfSupported = false
func reflectArrayOf(rvn reflect.Value) (rvn2 reflect.Value) {
panic("reflect.ArrayOf unsupported")
}
...@@ -23,7 +23,7 @@ package codec ...@@ -23,7 +23,7 @@ package codec
// 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.
...@@ -38,6 +38,8 @@ import ( ...@@ -38,6 +38,8 @@ import (
"sort" "sort"
) )
const fastpathEnabled = true
const fastpathCheckNilFalse = false // for reflect const fastpathCheckNilFalse = false // for reflect
const fastpathCheckNilTrue = true // for type switch const fastpathCheckNilTrue = true // for type switch
...@@ -81,9 +83,6 @@ var fastpathAV fastpathA ...@@ -81,9 +83,6 @@ 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(*encFnInfo, reflect.Value), fd func(*decFnInfo, reflect.Value)) (f fastpathE) {
xrt := reflect.TypeOf(v) xrt := reflect.TypeOf(v)
...@@ -106,9 +105,6 @@ func init() { ...@@ -106,9 +105,6 @@ 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 }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:{{else}} case []{{ .Elem }}:{{else}}
...@@ -126,9 +122,6 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { ...@@ -126,9 +122,6 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
} }
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 }}:
...@@ -144,9 +137,6 @@ func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { ...@@ -144,9 +137,6 @@ func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
} }
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 }}:
...@@ -165,7 +155,11 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { ...@@ -165,7 +155,11 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) { func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e) if f.ti.mbs {
fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
} else {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
}
} }
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) { func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
ee := e.e ee := e.e
...@@ -182,6 +176,31 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil b ...@@ -182,6 +176,31 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil b
if cr != nil { cr.sendContainerState(containerArrayEnd) }{{/* ee.EncodeEnd() */}} if cr != nil { cr.sendContainerState(containerArrayEnd) }{{/* ee.EncodeEnd() */}}
} }
func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
ee := e.e
cr := e.cr
if checkNil && v == nil {
ee.EncodeNil()
return
}
if len(v)%2 == 1 {
e.errorf("mapBySlice requires even slice length, but got %v", len(v))
return
}
ee.EncodeMapStart(len(v) / 2)
for j, v2 := range v {
if cr != nil {
if j%2 == 0 {
cr.sendContainerState(containerMapKey)
} else {
cr.sendContainerState(containerMapValue)
}
}
{{ encmd .Elem "v2"}}
}
if cr != nil { cr.sendContainerState(containerMapEnd) }
}
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
...@@ -257,9 +276,6 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele ...@@ -257,9 +276,6 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
// -- -- fast path type switch // -- -- fast path type switch
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) 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 }}:{{else}} case []{{ .Elem }}:{{else}}
...@@ -328,7 +344,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b ...@@ -328,7 +344,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
...@@ -391,7 +407,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b ...@@ -391,7 +407,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]{{ .Elem }}, 1, 4) v = make([]{{ .Elem }}, 1, 4)
......
...@@ -4,6 +4,8 @@ package codec ...@@ -4,6 +4,8 @@ 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.
......
{{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }} {{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }}
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}} {{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}}
var {{var "c"}} bool {{/* // changed */}} var {{var "c"}} bool {{/* // changed */}}
_ = {{var "c"}}{{end}}
if {{var "l"}} == 0 { if {{var "l"}} == 0 {
{{if isSlice }}if {{var "v"}} == nil { {{if isSlice }}if {{var "v"}} == nil {
{{var "v"}} = []{{ .Typ }}{} {{var "v"}} = []{{ .Typ }}{}
...@@ -26,6 +27,8 @@ if {{var "l"}} == 0 { ...@@ -26,6 +27,8 @@ if {{var "l"}} == 0 {
} }
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}} {{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}} 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"}}) {{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
{{ else }}{{if not .Immutable }} {{ else }}{{if not .Immutable }}
......
// //+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.
...@@ -17,7 +17,7 @@ import ( ...@@ -17,7 +17,7 @@ import (
// 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).
...@@ -84,6 +84,11 @@ func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) { ...@@ -84,6 +84,11 @@ func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
} }
// 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) EncRaw(iv Raw) {
f.e.raw(iv)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) TimeRtidIfBinc() uintptr { func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
if _, ok := f.e.hh.(*BincHandle); ok { if _, ok := f.e.hh.(*BincHandle); ok {
return timeTypId return timeTypId
...@@ -192,6 +197,11 @@ func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { ...@@ -192,6 +197,11 @@ func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
} }
// 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) DecRaw() []byte {
return f.d.raw()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) TimeRtidIfBinc() uintptr { func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
if _, ok := f.d.hh.(*BincHandle); ok { if _, ok := f.d.hh.(*BincHandle); ok {
return timeTypId return timeTypId
......
// //+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.
...@@ -17,7 +17,7 @@ import ( ...@@ -17,7 +17,7 @@ import (
// 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).
...@@ -79,6 +79,10 @@ func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) { ...@@ -79,6 +79,10 @@ func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
f.e.marshal(bs, fnerr, false, c_RAW) f.e.marshal(bs, fnerr, false, c_RAW)
} }
// 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) EncRaw(iv Raw) {
f.e.raw(iv)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) TimeRtidIfBinc() uintptr { func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
if _, ok := f.e.hh.(*BincHandle); ok { if _, ok := f.e.hh.(*BincHandle); ok {
return timeTypId return timeTypId
...@@ -172,6 +176,10 @@ func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { ...@@ -172,6 +176,10 @@ func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
} }
} }
// 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) DecRaw() []byte {
return f.d.raw()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) TimeRtidIfBinc() uintptr { func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
if _, ok := f.d.hh.(*BincHandle); ok { if _, ok := f.d.hh.(*BincHandle); ok {
return timeTypId return timeTypId
......
...@@ -68,8 +68,9 @@ z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) ...@@ -68,8 +68,9 @@ z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }})
const genDecListTmpl = ` const genDecListTmpl = `
{{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }} {{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }}
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}} {{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}}
var {{var "c"}} bool {{/* // changed */}} var {{var "c"}} bool {{/* // changed */}}
_ = {{var "c"}}{{end}}
if {{var "l"}} == 0 { if {{var "l"}} == 0 {
{{if isSlice }}if {{var "v"}} == nil { {{if isSlice }}if {{var "v"}} == nil {
{{var "v"}} = []{{ .Typ }}{} {{var "v"}} = []{{ .Typ }}{}
...@@ -95,6 +96,8 @@ if {{var "l"}} == 0 { ...@@ -95,6 +96,8 @@ if {{var "l"}} == 0 {
} }
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}} {{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}} 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"}}) {{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
{{ else }}{{if not .Immutable }} {{ else }}{{if not .Immutable }}
......
// 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.
// +build go1.5,!go1.6
package codec
import "os"
func init() {
genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") == "1"
}
// 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.
// +build go1.6
package codec
import "os"
func init() {
genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") != "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.
// +build go1.7
package codec
func init() {
genCheckVendor = true
}
...@@ -70,8 +70,8 @@ func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool { ...@@ -70,8 +70,8 @@ func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool {
return false return false
} }
func isEmptyValue(v reflect.Value) bool { func isEmptyValue(v reflect.Value, deref, checkStruct bool) bool {
return hIsEmptyValue(v, derefForIsEmptyValue, checkStructForEmptyValue) return hIsEmptyValue(v, deref, checkStruct)
} }
func pruneSignExt(v []byte, pos bool) (n int) { func pruneSignExt(v []byte, pos bool) (n int) {
......
//+build !unsafe // +build !unsafe
// 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.
......
//+build unsafe // +build unsafe
// 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.
...@@ -16,7 +16,7 @@ type unsafeString struct { ...@@ -16,7 +16,7 @@ type unsafeString struct {
Len int Len int
} }
type unsafeBytes struct { type unsafeSlice struct {
Data uintptr Data uintptr
Len int Len int
Cap int Cap int
...@@ -29,8 +29,10 @@ func stringView(v []byte) string { ...@@ -29,8 +29,10 @@ func stringView(v []byte) string {
if len(v) == 0 { if len(v) == 0 {
return "" return ""
} }
x := unsafeString{uintptr(unsafe.Pointer(&v[0])), len(v)}
return *(*string)(unsafe.Pointer(&x)) bx := (*unsafeSlice)(unsafe.Pointer(&v))
sx := unsafeString{bx.Data, bx.Len}
return *(*string)(unsafe.Pointer(&sx))
} }
// bytesView returns a view of the string as a []byte. // bytesView returns a view of the string as a []byte.
...@@ -40,6 +42,8 @@ func bytesView(v string) []byte { ...@@ -40,6 +42,8 @@ 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)}
return *(*[]byte)(unsafe.Pointer(&x)) sx := (*unsafeString)(unsafe.Pointer(&v))
bx := unsafeSlice{sx.Data, sx.Len, sx.Len}
return *(*[]byte)(unsafe.Pointer(&bx))
} }
...@@ -43,18 +43,23 @@ import ( ...@@ -43,18 +43,23 @@ import (
//-------------------------------- //--------------------------------
var jsonLiterals = [...]byte{'t', 'r', 'u', 'e', 'f', 'a', 'l', 's', 'e', 'n', 'u', 'l', 'l'} var (
jsonLiterals = [...]byte{'t', 'r', 'u', 'e', 'f', 'a', 'l', 's', 'e', 'n', 'u', 'l', 'l'}
var jsonFloat64Pow10 = [...]float64{ jsonFloat64Pow10 = [...]float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22, 1e20, 1e21, 1e22,
} }
var jsonUint64Pow10 = [...]uint64{ jsonUint64Pow10 = [...]uint64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
} }
// jsonTabs and jsonSpaces are used as caches for indents
jsonTabs, jsonSpaces string
)
const ( const (
// jsonUnreadAfterDecNum controls whether we unread after decoding a number. // jsonUnreadAfterDecNum controls whether we unread after decoding a number.
...@@ -85,8 +90,23 @@ const ( ...@@ -85,8 +90,23 @@ const (
jsonNumUintMaxVal = 1<<uint64(64) - 1 jsonNumUintMaxVal = 1<<uint64(64) - 1
// jsonNumDigitsUint64Largest = 19 // jsonNumDigitsUint64Largest = 19
jsonSpacesOrTabsLen = 128
) )
func init() {
var bs [jsonSpacesOrTabsLen]byte
for i := 0; i < jsonSpacesOrTabsLen; i++ {
bs[i] = ' '
}
jsonSpaces = string(bs[:])
for i := 0; i < jsonSpacesOrTabsLen; i++ {
bs[i] = '\t'
}
jsonTabs = string(bs[:])
}
type jsonEncDriver struct { type jsonEncDriver struct {
e *Encoder e *Encoder
w encWriter w encWriter
...@@ -94,30 +114,76 @@ type jsonEncDriver struct { ...@@ -94,30 +114,76 @@ type jsonEncDriver struct {
b [64]byte // scratch b [64]byte // scratch
bs []byte // scratch bs []byte // scratch
se setExtWrapper se setExtWrapper
ds string // indent string
dl uint16 // indent level
dt bool // indent using tabs
d bool // indent
c containerState c containerState
noBuiltInTypes noBuiltInTypes
} }
// indent is done as below:
// - newline and indent are added before each mapKey or arrayElem
// - newline and indent are added before each ending,
// except there was no entry (so we can have {} or [])
func (e *jsonEncDriver) sendContainerState(c containerState) { func (e *jsonEncDriver) sendContainerState(c containerState) {
// determine whether to output separators // determine whether to output separators
if c == containerMapKey { if c == containerMapKey {
if e.c != containerMapStart { if e.c != containerMapStart {
e.w.writen1(',') e.w.writen1(',')
} }
if e.d {
e.writeIndent()
}
} else if c == containerMapValue { } else if c == containerMapValue {
e.w.writen1(':') if e.d {
e.w.writen2(':', ' ')
} else {
e.w.writen1(':')
}
} else if c == containerMapEnd { } else if c == containerMapEnd {
if e.d {
e.dl--
if e.c != containerMapStart {
e.writeIndent()
}
}
e.w.writen1('}') e.w.writen1('}')
} else if c == containerArrayElem { } else if c == containerArrayElem {
if e.c != containerArrayStart { if e.c != containerArrayStart {
e.w.writen1(',') e.w.writen1(',')
} }
if e.d {
e.writeIndent()
}
} else if c == containerArrayEnd { } else if c == containerArrayEnd {
if e.d {
e.dl--
if e.c != containerArrayStart {
e.writeIndent()
}
}
e.w.writen1(']') e.w.writen1(']')
} }
e.c = c e.c = c
} }
func (e *jsonEncDriver) writeIndent() {
e.w.writen1('\n')
if x := len(e.ds) * int(e.dl); x <= jsonSpacesOrTabsLen {
if e.dt {
e.w.writestr(jsonTabs[:x])
} else {
e.w.writestr(jsonSpaces[:x])
}
} else {
for i := uint16(0); i < e.dl; i++ {
e.w.writestr(e.ds)
}
}
}
func (e *jsonEncDriver) EncodeNil() { func (e *jsonEncDriver) EncodeNil() {
e.w.writeb(jsonLiterals[9:13]) // null e.w.writeb(jsonLiterals[9:13]) // null
} }
...@@ -131,19 +197,39 @@ func (e *jsonEncDriver) EncodeBool(b bool) { ...@@ -131,19 +197,39 @@ func (e *jsonEncDriver) EncodeBool(b bool) {
} }
func (e *jsonEncDriver) EncodeFloat32(f float32) { func (e *jsonEncDriver) EncodeFloat32(f float32) {
e.w.writeb(strconv.AppendFloat(e.b[:0], float64(f), 'E', -1, 32)) e.encodeFloat(float64(f), 32)
} }
func (e *jsonEncDriver) EncodeFloat64(f float64) { func (e *jsonEncDriver) EncodeFloat64(f float64) {
// e.w.writestr(strconv.FormatFloat(f, 'E', -1, 64)) // e.w.writestr(strconv.FormatFloat(f, 'E', -1, 64))
e.w.writeb(strconv.AppendFloat(e.b[:0], f, 'E', -1, 64)) e.encodeFloat(f, 64)
}
func (e *jsonEncDriver) encodeFloat(f float64, numbits int) {
x := strconv.AppendFloat(e.b[:0], f, 'G', -1, numbits)
e.w.writeb(x)
if bytes.IndexByte(x, 'E') == -1 && bytes.IndexByte(x, '.') == -1 {
e.w.writen2('.', '0')
}
} }
func (e *jsonEncDriver) EncodeInt(v int64) { func (e *jsonEncDriver) EncodeInt(v int64) {
if x := e.h.IntegerAsString; x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) {
e.w.writen1('"')
e.w.writeb(strconv.AppendInt(e.b[:0], v, 10))
e.w.writen1('"')
return
}
e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) e.w.writeb(strconv.AppendInt(e.b[:0], v, 10))
} }
func (e *jsonEncDriver) EncodeUint(v uint64) { func (e *jsonEncDriver) EncodeUint(v uint64) {
if x := e.h.IntegerAsString; x == 'A' || x == 'L' && v > 1<<53 {
e.w.writen1('"')
e.w.writeb(strconv.AppendUint(e.b[:0], v, 10))
e.w.writen1('"')
return
}
e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) e.w.writeb(strconv.AppendUint(e.b[:0], v, 10))
} }
...@@ -165,11 +251,17 @@ func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) { ...@@ -165,11 +251,17 @@ func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
} }
func (e *jsonEncDriver) EncodeArrayStart(length int) { func (e *jsonEncDriver) EncodeArrayStart(length int) {
if e.d {
e.dl++
}
e.w.writen1('[') e.w.writen1('[')
e.c = containerArrayStart e.c = containerArrayStart
} }
func (e *jsonEncDriver) EncodeMapStart(length int) { func (e *jsonEncDriver) EncodeMapStart(length int) {
if e.d {
e.dl++
}
e.w.writen1('{') e.w.writen1('{')
e.c = containerMapStart e.c = containerMapStart
} }
...@@ -564,6 +656,11 @@ func (d *jsonDecDriver) decNum(storeBytes bool) { ...@@ -564,6 +656,11 @@ func (d *jsonDecDriver) decNum(storeBytes bool) {
d.tok = b d.tok = b
} }
b := d.tok b := d.tok
var str bool
if b == '"' {
str = true
b = d.r.readn1()
}
if !(b == '+' || b == '-' || b == '.' || (b >= '0' && b <= '9')) { if !(b == '+' || b == '-' || b == '.' || (b >= '0' && b <= '9')) {
d.d.errorf("json: decNum: got first char '%c'", b) d.d.errorf("json: decNum: got first char '%c'", b)
return return
...@@ -578,6 +675,10 @@ func (d *jsonDecDriver) decNum(storeBytes bool) { ...@@ -578,6 +675,10 @@ func (d *jsonDecDriver) decNum(storeBytes bool) {
n.reset() n.reset()
d.bs = d.bs[:0] d.bs = d.bs[:0]
if str && storeBytes {
d.bs = append(d.bs, '"')
}
// The format of a number is as below: // The format of a number is as below:
// parsing: sign? digit* dot? digit* e? sign? digit* // parsing: sign? digit* dot? digit* e? sign? digit*
// states: 0 1* 2 3* 4 5* 6 7 // states: 0 1* 2 3* 4 5* 6 7
...@@ -668,6 +769,14 @@ LOOP: ...@@ -668,6 +769,14 @@ LOOP:
default: default:
break LOOP break LOOP
} }
case '"':
if str {
if storeBytes {
d.bs = append(d.bs, '"')
}
b, eof = r.readn1eof()
}
break LOOP
default: default:
break LOOP break LOOP
} }
...@@ -822,6 +931,11 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [ ...@@ -822,6 +931,11 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
if isstring { if isstring {
return d.bs return d.bs
} }
// if appendStringAsBytes returned a zero-len slice, then treat as nil.
// This should only happen for null, and "".
if len(d.bs) == 0 {
return nil
}
bs0 := d.bs bs0 := d.bs
slen := base64.StdEncoding.DecodedLen(len(bs0)) slen := base64.StdEncoding.DecodedLen(len(bs0))
if slen <= cap(bs) { if slen <= cap(bs) {
...@@ -859,6 +973,14 @@ func (d *jsonDecDriver) appendStringAsBytes() { ...@@ -859,6 +973,14 @@ func (d *jsonDecDriver) appendStringAsBytes() {
} }
d.tok = b d.tok = b
} }
// handle null as a string
if d.tok == 'n' {
d.readStrIdx(10, 13) // ull
d.bs = d.bs[:0]
return
}
if d.tok != '"' { if d.tok != '"' {
d.d.errorf("json: expect char '%c' but got char '%c'", '"', d.tok) d.d.errorf("json: expect char '%c' but got char '%c'", '"', d.tok)
} }
...@@ -1033,6 +1155,24 @@ type JsonHandle struct { ...@@ -1033,6 +1155,24 @@ type JsonHandle struct {
// RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way. // RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way.
// If not configured, raw bytes are encoded to/from base64 text. // If not configured, raw bytes are encoded to/from base64 text.
RawBytesExt InterfaceExt RawBytesExt InterfaceExt
// Indent indicates how a value is encoded.
// - If positive, indent by that number of spaces.
// - If negative, indent by that number of tabs.
Indent int8
// IntegerAsString controls how integers (signed and unsigned) are encoded.
//
// Per the JSON Spec, JSON numbers are 64-bit floating point numbers.
// Consequently, integers > 2^53 cannot be represented as a JSON number without losing precision.
// This can be mitigated by configuring how to encode integers.
//
// IntegerAsString interpretes the following values:
// - if 'L', then encode integers > 2^53 as a json string.
// - if 'A', then encode all integers as a json string
// containing the exact integer representation as a decimal.
// - else encode all integers as a json number (default)
IntegerAsString uint8
} }
func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
...@@ -1040,26 +1180,48 @@ func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceE ...@@ -1040,26 +1180,48 @@ func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceE
} }
func (h *JsonHandle) newEncDriver(e *Encoder) encDriver { func (h *JsonHandle) newEncDriver(e *Encoder) encDriver {
hd := jsonEncDriver{e: e, w: e.w, h: h} hd := jsonEncDriver{e: e, h: h}
hd.bs = hd.b[:0] hd.bs = hd.b[:0]
hd.se.i = h.RawBytesExt
hd.reset()
return &hd return &hd
} }
func (h *JsonHandle) newDecDriver(d *Decoder) decDriver { func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
// d := jsonDecDriver{r: r.(*bytesDecReader), h: h} // d := jsonDecDriver{r: r.(*bytesDecReader), h: h}
hd := jsonDecDriver{d: d, r: d.r, h: h} hd := jsonDecDriver{d: d, h: h}
hd.bs = hd.b[:0] hd.bs = hd.b[:0]
hd.se.i = h.RawBytesExt hd.reset()
return &hd return &hd
} }
func (e *jsonEncDriver) reset() { func (e *jsonEncDriver) reset() {
e.w = e.e.w e.w = e.e.w
e.se.i = e.h.RawBytesExt
if e.bs != nil {
e.bs = e.bs[:0]
}
e.d, e.dt, e.dl, e.ds = false, false, 0, ""
e.c = 0
if e.h.Indent > 0 {
e.d = true
e.ds = jsonSpaces[:e.h.Indent]
} else if e.h.Indent < 0 {
e.d = true
e.dt = true
e.ds = jsonTabs[:-(e.h.Indent)]
}
} }
func (d *jsonDecDriver) reset() { func (d *jsonDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.se.i = d.h.RawBytesExt
if d.bs != nil {
d.bs = d.bs[:0]
}
d.c, d.tok = 0, 0
d.n.reset()
} }
var jsonEncodeTerminate = []byte{' '} var jsonEncodeTerminate = []byte{' '}
......
...@@ -374,7 +374,7 @@ func (d *msgpackDecDriver) DecodeNaked() { ...@@ -374,7 +374,7 @@ func (d *msgpackDecDriver) DecodeNaked() {
} }
if n.v == valueTypeUint && d.h.SignedInteger { if n.v == valueTypeUint && d.h.SignedInteger {
n.v = valueTypeInt n.v = valueTypeInt
n.i = int64(n.v) n.i = int64(n.u)
} }
return return
} }
...@@ -561,6 +561,13 @@ func (d *msgpackDecDriver) readNextBd() { ...@@ -561,6 +561,13 @@ 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) {
bd := d.bd bd := d.bd
if bd == mpNil { if bd == mpNil {
...@@ -729,6 +736,7 @@ func (e *msgpackEncDriver) reset() { ...@@ -729,6 +736,7 @@ func (e *msgpackEncDriver) reset() {
func (d *msgpackDecDriver) reset() { func (d *msgpackDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.bd, d.bdRead = 0, false
} }
//-------------------------------------------------- //--------------------------------------------------
......
...@@ -171,7 +171,7 @@ do ...@@ -171,7 +171,7 @@ do
'xf') zforce=1;; 'xf') zforce=1;;
'xb') zbak=1;; 'xb') zbak=1;;
'xx') zexternal=1;; 'xx') zexternal=1;;
*) echo "prebuild.sh accepts [-fb] only"; return 1;; *) echo "prebuild.sh accepts [-fbx] only"; return 1;;
esac esac
done done
shift $((OPTIND-1)) shift $((OPTIND-1))
......
...@@ -25,7 +25,7 @@ type Rpc interface { ...@@ -25,7 +25,7 @@ type Rpc interface {
} }
// RpcCodecBuffered allows access to the underlying bufio.Reader/Writer // RpcCodecBuffered allows access to the underlying bufio.Reader/Writer
// used by the rpc connection. It accomodates use-cases where the connection // used by the rpc connection. It accommodates use-cases where the connection
// should be used by rpc and non-rpc functions, e.g. streaming a file after // should be used by rpc and non-rpc functions, e.g. streaming a file after
// sending an rpc response. // sending an rpc response.
type RpcCodecBuffered interface { type RpcCodecBuffered interface {
......
...@@ -166,6 +166,13 @@ func (d *simpleDecDriver) readNextBd() { ...@@ -166,6 +166,13 @@ func (d *simpleDecDriver) readNextBd() {
d.bdRead = true d.bdRead = true
} }
func (d *simpleDecDriver) uncacheRead() {
if d.bdRead {
d.r.unreadn1()
d.bdRead = false
}
}
func (d *simpleDecDriver) ContainerType() (vt valueType) { func (d *simpleDecDriver) ContainerType() (vt valueType) {
if d.bd == simpleVdNil { if d.bd == simpleVdNil {
return valueTypeNil return valueTypeNil
...@@ -340,7 +347,7 @@ func (d *simpleDecDriver) decLen() int { ...@@ -340,7 +347,7 @@ func (d *simpleDecDriver) decLen() int {
} }
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("decLen: Cannot read length: bd%%8 must be in range 0..4. Got: %d", d.bd%8)
return -1 return -1
} }
...@@ -474,7 +481,7 @@ func (d *simpleDecDriver) DecodeNaked() { ...@@ -474,7 +481,7 @@ 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.
...@@ -512,6 +519,7 @@ func (e *simpleEncDriver) reset() { ...@@ -512,6 +519,7 @@ func (e *simpleEncDriver) reset() {
func (d *simpleDecDriver) reset() { func (d *simpleDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.bd, d.bdRead = 0, false
} }
var _ decDriver = (*simpleDecDriver)(nil) var _ decDriver = (*simpleDecDriver)(nil)
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
# sudo apt-get install python-pip # sudo apt-get install python-pip
# pip install --user msgpack-python msgpack-rpc-python cbor # pip install --user msgpack-python msgpack-rpc-python cbor
# Ensure all "string" keys are utf strings (else encoded as bytes)
import cbor, msgpack, msgpackrpc, sys, os, threading import cbor, msgpack, msgpackrpc, sys, os, threading
def get_test_data_list(): def get_test_data_list():
...@@ -26,35 +28,39 @@ def get_test_data_list(): ...@@ -26,35 +28,39 @@ def get_test_data_list():
-3232.0, -3232.0,
-6464646464.0, -6464646464.0,
3232.0, 3232.0,
6464.0,
6464646464.0, 6464646464.0,
False, False,
True, True,
u"null",
None, None,
u"someday", u"someday",
u"",
u"bytestring",
1328176922000002000, 1328176922000002000,
u"",
-2206187877999998000, -2206187877999998000,
u"bytestring",
270, 270,
u"none",
-2013855847999995777, -2013855847999995777,
#-6795364578871345152, #-6795364578871345152,
] ]
l1 = [ l1 = [
{ "true": True, { "true": True,
"false": False }, "false": False },
{ "true": "True", { "true": u"True",
"false": False, "false": False,
"uint16(1616)": 1616 }, "uint16(1616)": 1616 },
{ "list": [1616, 32323232, True, -3232.0, {"TRUE":True, "FALSE":False}, [True, False] ], { "list": [1616, 32323232, True, -3232.0, {"TRUE":True, "FALSE":False}, [True, False] ],
"int32":32323232, "bool": True, "int32":32323232, "bool": True,
"LONG STRING": "123456789012345678901234567890123456789012345678901234567890", "LONG STRING": u"123456789012345678901234567890123456789012345678901234567890",
"SHORT STRING": "1234567890" }, "SHORT STRING": u"1234567890" },
{ True: "true", 8: False, "false": 0 } { True: "true", 138: False, "false": 200 }
] ]
l = [] l = []
l.extend(l0) l.extend(l0)
l.append(l0) l.append(l0)
l.append(1)
l.extend(l1) l.extend(l1)
return l return l
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
_run() { _run() {
# 1. VARIATIONS: regular (t), canonical (c), IO R/W (i), # 1. VARIATIONS: regular (t), canonical (c), IO R/W (i),
# binc-nosymbols (n), struct2array (s), intern string (e), # 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) # 2. MODE: reflection (r), external (x), codecgen (g), unsafe (u), notfastpath (f)
# 3. OPTIONS: verbose (v), reset (z), must (m), # 3. OPTIONS: verbose (v), reset (z), must (m),
# #
...@@ -16,7 +17,7 @@ _run() { ...@@ -16,7 +17,7 @@ _run() {
zargs="" zargs=""
local OPTIND local OPTIND
OPTIND=1 OPTIND=1
while getopts "xurtcinsvgzmef" flag while getopts "_xurtcinsvgzmefdl" flag
do do
case "x$flag" in case "x$flag" in
'xr') ;; 'xr') ;;
...@@ -27,6 +28,7 @@ _run() { ...@@ -27,6 +28,7 @@ _run() {
'xv') zargs="$zargs -tv" ;; 'xv') zargs="$zargs -tv" ;;
'xz') zargs="$zargs -tr" ;; 'xz') zargs="$zargs -tr" ;;
'xm') zargs="$zargs -tm" ;; 'xm') zargs="$zargs -tm" ;;
'xl') zargs="$zargs -tl" ;;
*) ;; *) ;;
esac esac
done done
...@@ -35,15 +37,19 @@ _run() { ...@@ -35,15 +37,19 @@ _run() {
# echo ">>>>>>> TAGS: $ztags" # echo ">>>>>>> TAGS: $ztags"
OPTIND=1 OPTIND=1
while getopts "xurtcinsvgzmef" flag while getopts "_xurtcinsvgzmefdl" flag
do do
case "x$flag" in case "x$flag" in
'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;; 'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;;
'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" $zargs -tc; 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 ;; 'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" $zargs -ti; sleep 2 ;;
'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" $zargs -tn; 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 ;; 'xs') printf ">>>>>>> TO_ARRAY : "; go test "-tags=$ztags" $zargs -ts; sleep 2 ;;
'xe') printf ">>>>>>> INTERN : "; go test "-tags=$ztags" $zargs -te; 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 esac
done done
...@@ -53,22 +59,44 @@ _run() { ...@@ -53,22 +59,44 @@ _run() {
} }
# echo ">>>>>>> RUNNING VARIATIONS OF TESTS" # echo ">>>>>>> RUNNING VARIATIONS OF TESTS"
if [[ "x$@" = "x" ]]; then if [[ "x$@" = "x" || "x$@" = "x-A" ]]; then
# All: r, x, g, gu # All: r, x, g, gu
_run "-rtcinsm" # regular _run "-_tcinsed_ml" # regular
_run "-rtcinsmz" # regular with reset _run "-_tcinsed_ml_z" # regular with reset
_run "-rtcinsmf" # regular with no fastpath (notfastpath) _run "-_tcinsed_ml_f" # regular with no fastpath (notfastpath)
_run "-xtcinsm" # external _run "-x_tcinsed_ml" # external
_run "-gxtcinsm" # codecgen: requires external _run "-gx_tcinsed_ml" # codecgen: requires external
_run "-gxutcinsm" # codecgen + unsafe _run "-gxu_tcinsed_ml" # codecgen + unsafe
elif [[ "x$@" = "x-Z" ]]; then elif [[ "x$@" = "x-Z" ]]; then
# Regular # Regular
_run "-rtcinsm" # regular _run "-_tcinsed_ml" # regular
_run "-rtcinsmz" # regular with reset _run "-_tcinsed_ml_z" # regular with reset
elif [[ "x$@" = "x-F" ]]; then elif [[ "x$@" = "x-F" ]]; then
# regular with notfastpath # regular with notfastpath
_run "-rtcinsmf" # regular _run "-_tcinsed_ml_f" # regular
_run "-rtcinsmzf" # regular with reset _run "-_tcinsed_ml_zf" # regular with reset
elif [[ "x$@" = "x-C" ]]; then
# codecgen
_run "-gx_tcinsed_ml" # codecgen: requires external
_run "-gxu_tcinsed_ml" # codecgen + unsafe
elif [[ "x$@" = "x-X" ]]; then
# external
_run "-x_tcinsed_ml" # external
elif [[ "x$@" = "x-h" || "x$@" = "x-?" ]]; then
cat <<EOF
Usage: tests.sh [options...]
-A run through all tests (regular, external, codecgen)
-Z regular tests only
-F regular tests only (without fastpath, so they run quickly)
-C codecgen only
-X external only
-h show help (usage)
-? same as -h
(no options)
same as -A
(unrecognized options)
just pass on the options from the command line
EOF
else else
_run "$@" _run "$@"
fi fi
...@@ -5,11 +5,22 @@ package codec ...@@ -5,11 +5,22 @@ package codec
import ( import (
"fmt" "fmt"
"reflect"
"time" "time"
) )
var ( var (
timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} 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{} type timeExt struct{}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment