Repository: fxamacker/cbor
Pull request #544 (2024-05-29 01:53:51)

Use "cbor:" prefixed error msg when decoding with non-default TimeTagToAnyMode setting
Changes:
- Use "cbor:" prefixed error msg when decoding with non-default `TimeTagToAnyMode`
- Refactor to remove more magic numbers


Patch:
diff --git a/decode.go b/decode.go
index 5449d53..06ee294 100644
--- a/decode.go
+++ b/decode.go
@@ -1874,11 +1874,12 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
 				if tagNum == 1 {
 					tm = tm.UTC()
 				}
-				// Formats to RFC3339 and errors on time.Time values that cannot be
-				// represented by RFC3339.
+				// Call time.MarshalText() to format decoded time to RFC3339 format,
+				// and return error on time value that cannot be represented in
+				// RFC3339 format. E.g. year cannot exceed 9999, etc.
 				text, err := tm.Truncate(time.Second).MarshalText()
 				if err != nil {
-					return nil, err
+					return nil, fmt.Errorf("cbor: decoded time cannot be represented in RFC3339 format: %v", err)
 				}
 				return string(text), nil
 
@@ -1886,11 +1887,12 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli
 				if tagNum == 1 {
 					tm = tm.UTC()
 				}
-				// Formats to RFC3339 with subsecond precision and errors on
-				// time.Time values that cannot be represented by RFC3339.
+				// Call time.MarshalText() to format decoded time to RFC3339 format,
+				// and return error on time value that cannot be represented in
+				// RFC3339 format with sub-second precision.
 				text, err := tm.MarshalText()
 				if err != nil {
-					return nil, err
+					return nil, fmt.Errorf("cbor: decoded time cannot be represented in RFC3339 format with sub-second precision: %v", err)
 				}
 				return string(text), nil
 
diff --git a/encode.go b/encode.go
index 90a1a59..b45147f 100644
--- a/encode.go
+++ b/encode.go
@@ -981,7 +981,9 @@ func encodeFloat(e *bytes.Buffer, em *encMode, v reflect.Value) error {
 	if v.Kind() == reflect.Float64 && (fopt == ShortestFloatNone || cannotFitFloat32(f64)) {
 		// Encode float64
 		// Don't use encodeFloat64() because it cannot be inlined.
-		var scratch [9]byte
+		const argumentSize = 8
+		const headSize = 1 + argumentSize
+		var scratch [headSize]byte
 		scratch[0] = byte(cborTypePrimitives) | byte(additionalInformationAsFloat64)
 		binary.BigEndian.PutUint64(scratch[1:], math.Float64bits(f64))
 		e.Write(scratch[:])
@@ -1005,20 +1007,24 @@ func encodeFloat(e *bytes.Buffer, em *encMode, v reflect.Value) error {
 		if p == float16.PrecisionExact {
 			// Encode float16
 			// Don't use encodeFloat16() because it cannot be inlined.
-			var scratch [3]byte
+			const argumentSize = 2
+			const headSize = 1 + argumentSize
+			var scratch [headSize]byte
 			scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat16
 			binary.BigEndian.PutUint16(scratch[1:], uint16(f16))
-			e.Write(scratch[:3])
+			e.Write(scratch[:])
 			return nil
 		}
 	}
 
 	// Encode float32
 	// Don't use encodeFloat32() because it cannot be inlined.
-	var scratch [5]byte
+	const argumentSize = 4
+	const headSize = 1 + argumentSize
+	var scratch [headSize]byte
 	scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat32
 	binary.BigEndian.PutUint32(scratch[1:], math.Float32bits(f32))
-	e.Write(scratch[:5])
+	e.Write(scratch[:])
 	return nil
 }
 
@@ -1104,26 +1110,32 @@ func encodeNaN(e *bytes.Buffer, em *encMode, v reflect.Value) error {
 }
 
 func encodeFloat16(e *bytes.Buffer, f16 float16.Float16) error {
-	var scratch [3]byte
+	const argumentSize = 2
+	const headSize = 1 + argumentSize
+	var scratch [headSize]byte
 	scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat16
 	binary.BigEndian.PutUint16(scratch[1:], uint16(f16))
-	e.Write(scratch[:3])
+	e.Write(scratch[:])
 	return nil
 }
 
 func encodeFloat32(e *bytes.Buffer, f32 float32) error {
-	var scratch [5]byte
+	const argumentSize = 4
+	const headSize = 1 + argumentSize
+	var scratch [headSize]byte
 	scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat32
 	binary.BigEndian.PutUint32(scratch[1:], math.Float32bits(f32))
-	e.Write(scratch[:5])
+	e.Write(scratch[:])
 	return nil
 }
 
 func encodeFloat64(e *bytes.Buffer, f64 float64) error {
-	var scratch [9]byte
+	const argumentSize = 8
+	const headSize = 1 + argumentSize
+	var scratch [headSize]byte
 	scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat64
 	binary.BigEndian.PutUint64(scratch[1:], math.Float64bits(f64))
-	e.Write(scratch[:9])
+	e.Write(scratch[:])
 	return nil
 }
 


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 6eebb94..b5060fc 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -8915,13 +8915,13 @@ func TestDecModeTimeTagToAny(t *testing.T) {
 			name:           "error under TimeTagToRFC3339 when tag 1 represents a time that can't be represented by valid RFC3339",
 			opts:           DecOptions{TimeTagToAny: TimeTagToRFC3339},
 			in:             hexDecode("c11b0000003afff44181"), // 1(253402300801)
-			wantErrMessage: "Time.MarshalText: year outside of range [0,9999]",
+			wantErrMessage: "cbor: decoded time cannot be represented in RFC3339 format: Time.MarshalText: year outside of range [0,9999]",
 		},
 		{
 			name:           "error under TimeTagToRFC3339Nano when tag 1 represents a time that can't be represented by valid RFC3339",
 			opts:           DecOptions{TimeTagToAny: TimeTagToRFC3339Nano},
 			in:             hexDecode("c11b0000003afff44181"), // 1(253402300801)
-			wantErrMessage: "Time.MarshalText: year outside of range [0,9999]",
+			wantErrMessage: "cbor: decoded time cannot be represented in RFC3339 format with sub-second precision: Time.MarshalText: year outside of range [0,9999]",
 		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {