Skip to content

Commit

Permalink
Refactor to remove more magic numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
fxamacker committed May 28, 2024
1 parent c5c66ba commit fdf5bd8
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 41 deletions.
14 changes: 12 additions & 2 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const (
additionalInformationWith4ByteArgument = 26
additionalInformationWith8ByteArgument = 27

// additional information with major type 7
// For major type 7.
additionalInformationAsFalse = 20
additionalInformationAsTrue = 21
additionalInformationAsNull = 22
Expand All @@ -62,9 +62,15 @@ const (
additionalInformationAsFloat32 = 26
additionalInformationAsFloat64 = 27

// For major type 2, 3, 4, 5.
additionalInformationAsIndefiniteLengthFlag = 31
)

const (
maxSimpleValueInAdditionalInformation = 23
minSimpleValueIn1ByteArgument = 32
)

func (ai additionalInformation) isIndefiniteLength() bool {
return ai == additionalInformationAsIndefiniteLengthFlag
}
Expand Down Expand Up @@ -110,7 +116,11 @@ const (
)

const (
cborBreakFlag = byte(0xff)
cborBreakFlag = byte(0xff)
cborByteStringWithIndefiniteLengthHead = byte(0x5f)
cborTextStringWithIndefiniteLengthHead = byte(0x7f)
cborArrayWithIndefiniteLengthHead = byte(0x9f)
cborMapWithIndefiniteLengthHead = byte(0xbf)
)

var (
Expand Down
36 changes: 36 additions & 0 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -1358,8 +1358,10 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
v.Set(reflect.ValueOf(iv))
}
return err

case specialTypeTag:
return d.parseToTag(v)

case specialTypeTime:
if d.nextCBORNil() {
// Decoding CBOR null and undefined to time.Time is no-op.
Expand All @@ -1374,6 +1376,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
v.Set(reflect.ValueOf(tm))
}
return nil

case specialTypeUnmarshalerIface:
return d.parseToUnmarshaler(v)
}
Expand Down Expand Up @@ -1535,6 +1538,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
}()
}
}

return d.parseToValue(v, tInfo)

case cborTypeArray:
Expand Down Expand Up @@ -1628,6 +1632,7 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
return t, true, nil
}
return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()}

case cborTypeTextString:
s, err := d.parseTextString()
if err != nil {
Expand All @@ -1638,6 +1643,7 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
return time.Time{}, false, errors.New("cbor: cannot set " + string(s) + " for time.Time: " + err.Error())
}
return t, true, nil

case cborTypePositiveInt:
_, _, val := d.getHead()
if val > math.MaxInt64 {
Expand All @@ -1648,6 +1654,7 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
}
}
return time.Unix(int64(val), 0), true, nil

case cborTypeNegativeInt:
_, _, val := d.getHead()
if val > math.MaxInt64 {
Expand All @@ -1667,6 +1674,7 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
}
}
return time.Unix(int64(-1)^int64(val), 0), true, nil

case cborTypePrimitives:
_, ai, val := d.getHead()
var f float64
Expand All @@ -1690,6 +1698,7 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
}
seconds, fractional := math.Modf(f)
return time.Unix(int64(seconds), int64(fractional*1e9)), true, nil

default:
return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()}
}
Expand Down Expand Up @@ -1822,8 +1831,10 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
clone := make([]byte, len(b))
copy(clone, b)
return clone, nil

case typeString:
return string(b), nil

default:
if copied || d.dm.defaultByteStringType.Kind() == reflect.String {
// Avoid an unnecessary copy since the conversion to string must
Expand All @@ -1834,12 +1845,14 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
copy(clone, b)
return reflect.ValueOf(clone).Convert(d.dm.defaultByteStringType).Interface(), nil
}

case cborTypeTextString:
b, err := d.parseTextString()
if err != nil {
return nil, err
}
return string(b), nil

case cborTypeTag:
tagOff := d.off
_, _, tagNum := d.getHead()
Expand All @@ -1852,9 +1865,11 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
if err != nil {
return nil, err
}

switch d.dm.timeTagToAny {
case TimeTagToTime:
return tm, nil

case TimeTagToRFC3339:
if tagNum == 1 {
tm = tm.UTC()
Expand All @@ -1866,6 +1881,7 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
return nil, err
}
return string(text), nil

case TimeTagToRFC3339Nano:
if tagNum == 1 {
tm = tm.UTC()
Expand All @@ -1877,6 +1893,7 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
return nil, err
}
return string(text), nil

default:
// not reachable
}
Expand Down Expand Up @@ -1953,6 +1970,7 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
if ai < 20 || ai == 24 {
return SimpleValue(val), nil
}

switch ai {
case additionalInformationAsFalse,
additionalInformationAsTrue:
Expand All @@ -1977,6 +1995,7 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli

case cborTypeArray:
return d.parseArray()

case cborTypeMap:
if d.dm.defaultMapType != nil {
m := reflect.New(d.dm.defaultMapType)
Expand All @@ -1988,6 +2007,7 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
}
return d.parseMap()
}

return nil, nil
}

Expand Down Expand Up @@ -2035,19 +2055,23 @@ func (d *decoder) applyByteStringTextConversion(
encoded := make([]byte, base64.RawURLEncoding.EncodedLen(len(src)))
base64.RawURLEncoding.Encode(encoded, src)
return encoded, true, nil

case tagNumExpectedLaterEncodingBase64:
encoded := make([]byte, base64.StdEncoding.EncodedLen(len(src)))
base64.StdEncoding.Encode(encoded, src)
return encoded, true, nil

case tagNumExpectedLaterEncodingBase16:
encoded := make([]byte, hex.EncodedLen(len(src)))
hex.Encode(encoded, src)
return encoded, true, nil

default:
// If this happens, there is a bug: the decoder has pushed an invalid
// "expected later encoding" tag to the stack.
panic(fmt.Sprintf("unrecognized expected later encoding tag: %d", d.expectedLaterEncodingTags))
}

case reflect.Slice:
if dstType.Elem().Kind() != reflect.Uint8 || len(d.expectedLaterEncodingTags) > 0 {
// Either the destination is not a slice of bytes, or the encoder that
Expand All @@ -2064,13 +2088,15 @@ func (d *decoder) applyByteStringTextConversion(
return nil, false, fmt.Errorf("cbor: failed to decode base64url string: %v", err)
}
return decoded[:n], true, nil

case ByteSliceExpectedEncodingBase64:
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
n, err := base64.StdEncoding.Decode(decoded, src)
if err != nil {
return nil, false, fmt.Errorf("cbor: failed to decode base64 string: %v", err)
}
return decoded[:n], true, nil

case ByteSliceExpectedEncodingBase16:
decoded := make([]byte, hex.DecodedLen(len(src)))
n, err := hex.Decode(decoded, src)
Expand Down Expand Up @@ -2756,14 +2782,17 @@ func (d *decoder) skip() {
switch t {
case cborTypeByteString, cborTypeTextString:
d.off += int(val)

case cborTypeArray:
for i := 0; i < int(val); i++ {
d.skip()
}

case cborTypeMap:
for i := 0; i < int(val)*2; i++ {
d.skip()
}

case cborTypeTag:
d.skip()
}
Expand Down Expand Up @@ -2893,6 +2922,7 @@ func fillPositiveInt(t cborType, val uint64, v reflect.Value) error {
}
v.SetInt(int64(val))
return nil

case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if v.OverflowUint(val) {
return &UnmarshalTypeError{
Expand All @@ -2903,11 +2933,13 @@ func fillPositiveInt(t cborType, val uint64, v reflect.Value) error {
}
v.SetUint(val)
return nil

case reflect.Float32, reflect.Float64:
f := float64(val)
v.SetFloat(f)
return nil
}

if v.Type() == typeBigInt {
i := new(big.Int).SetUint64(val)
v.Set(reflect.ValueOf(*i))
Expand All @@ -2928,6 +2960,7 @@ func fillNegativeInt(t cborType, val int64, v reflect.Value) error {
}
v.SetInt(val)
return nil

case reflect.Float32, reflect.Float64:
f := float64(val)
v.SetFloat(f)
Expand Down Expand Up @@ -3026,6 +3059,7 @@ func isImmutableKind(k reflect.Kind) bool {
reflect.Float32, reflect.Float64,
reflect.String:
return true

default:
return false
}
Expand All @@ -3035,6 +3069,7 @@ func isHashableValue(rv reflect.Value) bool {
switch rv.Kind() {
case reflect.Slice, reflect.Map, reflect.Func:
return false

case reflect.Struct:
switch rv.Type() {
case typeTag:
Expand All @@ -3057,6 +3092,7 @@ func convertByteSliceToByteString(v interface{}) (interface{}, bool) {
switch v := v.(type) {
case []byte:
return ByteString(v), true

case Tag:
content, converted := convertByteSliceToByteString(v.Content)
if converted {
Expand Down
18 changes: 10 additions & 8 deletions diagnose.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,17 @@ func (di *diagnose) wellformed(allowExtraData bool) error {
func (di *diagnose) item() error { //nolint:gocyclo
initialByte := di.d.data[di.d.off]
switch initialByte {
case 0x5f, 0x7f: // indefinite-length byte/text string
case cborByteStringWithIndefiniteLengthHead,
cborTextStringWithIndefiniteLengthHead: // indefinite-length byte/text string
di.d.off++
if isBreakFlag(di.d.data[di.d.off]) {
di.d.off++
switch initialByte {
case 0x5f:
case cborByteStringWithIndefiniteLengthHead:
// indefinite-length bytes with no chunks.
di.w.WriteString(`''_`)
return nil
case 0x7f:
case cborTextStringWithIndefiniteLengthHead:
// indefinite-length text with no chunks.
di.w.WriteString(`""_`)
return nil
Expand All @@ -276,7 +277,7 @@ func (di *diagnose) item() error { //nolint:gocyclo
di.w.WriteByte(')')
return nil

case 0x9f: // indefinite-length array
case cborArrayWithIndefiniteLengthHead: // indefinite-length array
di.d.off++
di.w.WriteString("[_ ")

Expand All @@ -295,7 +296,7 @@ func (di *diagnose) item() error { //nolint:gocyclo
di.w.WriteByte(']')
return nil

case 0xbf: // indefinite-length map
case cborMapWithIndefiniteLengthHead: // indefinite-length map
di.d.off++
di.w.WriteString("{_ ")

Expand Down Expand Up @@ -573,7 +574,7 @@ func (di *diagnose) encodeByteString(val []byte) error {
}
}

var utf16SurrSelf = rune(0x10000)
const utf16SurrSelf = rune(0x10000)

// quote should be either `'` or `"`
func (di *diagnose) encodeTextString(val string, quote byte) error {
Expand Down Expand Up @@ -678,16 +679,17 @@ func (di *diagnose) encodeFloat(ai byte, val uint64) error {
}
// Use ES6 number to string conversion which should match most JSON generators.
// Inspired by https://github.com/golang/go/blob/4df10fba1687a6d4f51d7238a403f8f2298f6a16/src/encoding/json/encode.go#L585
const bitSize = 64
b := make([]byte, 0, 32)
if abs := math.Abs(f64); abs != 0 && (abs < 1e-6 || abs >= 1e21) {
b = strconv.AppendFloat(b, f64, 'e', -1, 64)
b = strconv.AppendFloat(b, f64, 'e', -1, bitSize)
// clean up e-09 to e-9
n := len(b)
if n >= 4 && string(b[n-4:n-1]) == "e-0" {
b = append(b[:n-2], b[n-1])
}
} else {
b = strconv.AppendFloat(b, f64, 'f', -1, 64)
b = strconv.AppendFloat(b, f64, 'f', -1, bitSize)
}

// add decimal point and trailing zero if needed
Expand Down
Loading

0 comments on commit fdf5bd8

Please sign in to comment.