Codebase list golang-github-hashicorp-go-msgpack / 10b6078
codec: Add support for decoding byte slices, even if encoded as a regular array. This requires us checking currentEncodedType in the stream first, before deciding how to decode the value when decoding into a slice. There's a slight performance hit, but correctness is more important. Also, put in flag to "conditionally" enable encoding uint as positive fixint, and update tests so they work across binc and msgpack and regardless of flag. (This means ensuring that all unsigned int values in test are > 128). (I probably will not enable this flag by default, but it's there ... for placeholding and reminder). Fixes issue #26 . Updates issue #24 . Ugorji Nwoke 10 years ago
4 changed file(s) with 68 addition(s) and 36 deletion(s). Raw diff Collapse all Expand all
1818 // Some hints:
1919 // - python msgpack encodes positive numbers as uints, so use uints below
2020 // for positive numbers.
21 // - flag mpEncodeUintAsFixnum allows uints be encoded as fixnums.
22 // To accomodate it being true or false, ensure all unsigned values below are > 128.
2123
2224 import (
2325 "bytes"
349351 },
350352 map[interface{}]interface{}{
351353 true: "true",
352 uint8(8): false,
353 "false": uint8(0),
354 uint8(138): false,
355 "false": uint8(200),
354356 },
355357 newTestStruc(0, false),
356358 }
438440 Sslice: []string{"one", "two", "three"},
439441 I64slice: []int64{1, 2, 3},
440442 I16slice: []int16{4, 5, 6},
441 Ui64slice: []uint64{7, 8, 9},
442 Ui8slice: []uint8{10, 11, 12},
443 Ui64slice: []uint64{137, 138, 139},
444 Ui8slice: []uint8{210, 211, 212},
443445 Bslice: []bool{true, false, true, false},
444446 Byslice: []byte{13, 14, 15},
445447
446 Islice: []interface{}{"true", true, "no", false, uint64(88), float64(0.4)},
448 Islice: []interface{}{"true", true, "no", false, uint64(288), float64(0.4)},
447449
448450 Ms: map[string]interface{}{
449451 "true": "true",
721723 t.FailNow()
722724 }
723725 // fmt.Printf(">>>> err: %v. tarr1: %v, tarr2: %v\n", err, tarr0, tarr2)
726 }
727
728 // test byte array, even if empty (msgpack only)
729 if h == testMsgpackH {
730 type ystruct struct {
731 Anarray []byte
732 }
733 var ya = ystruct{}
734 err = testUnmarshal(&ya, []byte{0x91, 0x90}, h)
735 if err != nil {
736 logT(t, "Error unmarshalling into ystruct: %v, Err: %v", ya, err)
737 t.FailNow()
738 }
724739 }
725740 }
726741
413413
414414 func (f *decFnInfo) kSlice(rv reflect.Value) {
415415 // A slice can be set from a map or array in stream.
416
416 currEncodedType := f.dd.currentEncodedType()
417
418 switch currEncodedType {
419 case valueTypeBytes, valueTypeString:
420 if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 {
421 if bs2, changed2 := f.dd.decodeBytes(rv.Bytes()); changed2 {
422 rv.SetBytes(bs2)
423 }
424 return
425 }
426 }
427
417428 if shortCircuitReflectToFastPath && rv.CanAddr() {
418429 switch f.ti.rtid {
419430 case intfSliceTypId:
420 f.d.decSliceIntf(rv.Addr().Interface().(*[]interface{}), f.array)
431 f.d.decSliceIntf(rv.Addr().Interface().(*[]interface{}), currEncodedType, f.array)
421432 return
422433 case uint64SliceTypId:
423 f.d.decSliceUint64(rv.Addr().Interface().(*[]uint64), f.array)
434 f.d.decSliceUint64(rv.Addr().Interface().(*[]uint64), currEncodedType, f.array)
424435 return
425436 case int64SliceTypId:
426 f.d.decSliceInt64(rv.Addr().Interface().(*[]int64), f.array)
437 f.d.decSliceInt64(rv.Addr().Interface().(*[]int64), currEncodedType, f.array)
427438 return
428439 case strSliceTypId:
429 f.d.decSliceStr(rv.Addr().Interface().(*[]string), f.array)
440 f.d.decSliceStr(rv.Addr().Interface().(*[]string), currEncodedType, f.array)
430441 return
431442 }
432443 }
433444
434 if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 {
435 if bs2, changed2 := f.dd.decodeBytes(rv.Bytes()); changed2 {
436 rv.SetBytes(bs2)
437 }
438 return
439 }
440
441 containerLen, containerLenS := decContLens(f.dd)
445 containerLen, containerLenS := decContLens(f.dd, currEncodedType)
442446
443447 // an array can never return a nil slice. so no need to check f.array here.
444448
445449 if rv.IsNil() {
446450 rv.Set(reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS))
447451 }
452
448453 if containerLen == 0 {
449454 return
450455 }
451
456
452457 if rvcap, rvlen := rv.Len(), rv.Cap(); containerLenS > rvcap {
453458 if f.array { // !rv.CanSet()
454459 decErr(msgDecCannotExpandArr, rvcap, containerLenS)
663668 *v, _ = d.d.decodeBytes(v2)
664669
665670 case *[]interface{}:
666 d.decSliceIntf(v, false)
671 d.decSliceIntf(v, valueTypeInvalid, false)
667672 case *[]uint64:
668 d.decSliceUint64(v, false)
673 d.decSliceUint64(v, valueTypeInvalid, false)
669674 case *[]int64:
670 d.decSliceInt64(v, false)
675 d.decSliceInt64(v, valueTypeInvalid, false)
671676 case *[]string:
672 d.decSliceStr(v, false)
677 d.decSliceStr(v, valueTypeInvalid, false)
673678 case *map[string]interface{}:
674679 d.decMapStrIntf(v)
675680 case *map[interface{}]interface{}:
852857
853858 // short circuit functions for common maps and slices
854859
855 func (d *Decoder) decSliceIntf(v *[]interface{}, doNotReset bool) {
856 _, containerLenS := decContLens(d.d)
860 func (d *Decoder) decSliceIntf(v *[]interface{}, currEncodedType valueType, doNotReset bool) {
861 _, containerLenS := decContLens(d.d, currEncodedType)
857862 s := *v
858863 if s == nil {
859864 s = make([]interface{}, containerLenS, containerLenS)
872877 *v = s
873878 }
874879
875 func (d *Decoder) decSliceInt64(v *[]int64, doNotReset bool) {
876 _, containerLenS := decContLens(d.d)
880 func (d *Decoder) decSliceInt64(v *[]int64, currEncodedType valueType, doNotReset bool) {
881 _, containerLenS := decContLens(d.d, currEncodedType)
877882 s := *v
878883 if s == nil {
879884 s = make([]int64, containerLenS, containerLenS)
894899 *v = s
895900 }
896901
897 func (d *Decoder) decSliceUint64(v *[]uint64, doNotReset bool) {
898 _, containerLenS := decContLens(d.d)
902 func (d *Decoder) decSliceUint64(v *[]uint64, currEncodedType valueType, doNotReset bool) {
903 _, containerLenS := decContLens(d.d, currEncodedType)
899904 s := *v
900905 if s == nil {
901906 s = make([]uint64, containerLenS, containerLenS)
916921 *v = s
917922 }
918923
919 func (d *Decoder) decSliceStr(v *[]string, doNotReset bool) {
920 _, containerLenS := decContLens(d.d)
924 func (d *Decoder) decSliceStr(v *[]string, currEncodedType valueType, doNotReset bool) {
925 _, containerLenS := decContLens(d.d, currEncodedType)
921926 s := *v
922927 if s == nil {
923928 s = make([]string, containerLenS, containerLenS)
10081013
10091014 // ----------------------------------------
10101015
1011 func decContLens(dd decDriver) (containerLen, containerLenS int) {
1012 switch currEncodedType := dd.currentEncodedType(); currEncodedType {
1016 func decContLens(dd decDriver, currEncodedType valueType) (containerLen, containerLenS int) {
1017 if currEncodedType == valueTypeInvalid {
1018 currEncodedType = dd.currentEncodedType()
1019 }
1020 switch currEncodedType {
10131021 case valueTypeArray:
10141022 containerLen = dd.readArrayLen()
10151023 containerLenS = containerLen
10261034 func decErr(format string, params ...interface{}) {
10271035 doPanic(msgTagDec, format, params...)
10281036 }
1037
1038
1039
7373 valueTypeArray
7474 valueTypeTimestamp
7575 valueTypeExt
76
77 valueTypeInvalid = 0xff
7678 )
7779
7880 var (
6060 mpNegFixNumMax = 0xff
6161 )
6262
63 // TODO: Should I enable this, which causes small uints be encoded as fixnums?
64 // uints are not fixnums. fixnums are always signed.
65 // conditionally support them (but keep flag off for compatibility).
66 const mpEncodeUintAsFixnum = false
67
6368 // MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec
6469 // that the backend RPC service takes multiple arguments, which have been arranged
6570 // in sequence in the slice.
121126 }
122127
123128 func (e *msgpackEncDriver) encodeUint(i uint64) {
124 // uints are not fixnums. fixnums are always signed.
125 // case i <= math.MaxInt8:
126 // e.w.writen1(byte(i))
127129 switch {
130 case mpEncodeUintAsFixnum && i <= math.MaxInt8:
131 e.w.writen1(byte(i))
128132 case i <= math.MaxUint8:
129133 e.w.writen2(mpUint8, byte(i))
130134 case i <= math.MaxUint16: