@@ -17,93 +17,139 @@ limitations under the License.
17
17
package modes
18
18
19
19
import (
20
+ "io"
21
+
20
22
"github.com/fxamacker/cbor/v2"
21
23
)
22
24
23
- var Encode cbor.EncMode = func () cbor.EncMode {
24
- encode , err := cbor.EncOptions {
25
- // Map keys need to be sorted to have deterministic output, and this is the order
26
- // defined in RFC 8949 4.2.1 "Core Deterministic Encoding Requirements".
27
- Sort : cbor .SortBytewiseLexical ,
28
-
29
- // CBOR supports distinct types for IEEE-754 float16, float32, and float64. Store
30
- // floats in the smallest width that preserves value so that equivalent float32 and
31
- // float64 values encode to identical bytes, as they do in a JSON
32
- // encoding. Satisfies one of the "Core Deterministic Encoding Requirements".
33
- ShortestFloat : cbor .ShortestFloat16 ,
34
-
35
- // Error on attempt to encode NaN and infinite values. This is what the JSON
36
- // serializer does.
37
- NaNConvert : cbor .NaNConvertReject ,
38
- InfConvert : cbor .InfConvertReject ,
39
-
40
- // Error on attempt to encode math/big.Int values, which can't be faithfully
41
- // roundtripped through Unstructured in general (the dynamic numeric types allowed
42
- // in Unstructured are limited to float64 and int64).
43
- BigIntConvert : cbor .BigIntConvertReject ,
44
-
45
- // MarshalJSON for time.Time writes RFC3339 with nanos.
46
- Time : cbor .TimeRFC3339Nano ,
47
-
48
- // The decoder must be able to accept RFC3339 strings with or without tag 0 (e.g. by
49
- // the end of time.Time -> JSON -> Unstructured -> CBOR, the CBOR encoder has no
50
- // reliable way of knowing that a particular string originated from serializing a
51
- // time.Time), so producing tag 0 has little use.
52
- TimeTag : cbor .EncTagNone ,
53
-
54
- // Indefinite-length items have multiple encodings and aren't being used anyway, so
55
- // disable to avoid an opportunity for nondeterminism.
56
- IndefLength : cbor .IndefLengthForbidden ,
57
-
58
- // Preserve distinction between nil and empty for slices and maps.
59
- NilContainers : cbor .NilContainerAsNull ,
60
-
61
- // OK to produce tags.
62
- TagsMd : cbor .TagsAllowed ,
63
-
64
- // Use the same definition of "empty" as encoding/json.
65
- OmitEmpty : cbor .OmitEmptyGoValue ,
66
-
67
- // The CBOR types text string and byte string are structurally equivalent, with the
68
- // semantic difference that a text string whose content is an invalid UTF-8 sequence
69
- // is itself invalid. We reject all invalid text strings at decode time and do not
70
- // validate or sanitize all Go strings at encode time. Encoding Go strings to the
71
- // byte string type is comparable to the existing Protobuf behavior and cheaply
72
- // ensures that the output is valid CBOR.
73
- String : cbor .StringToByteString ,
74
-
75
- // Encode struct field names to the byte string type rather than the text string
76
- // type.
77
- FieldName : cbor .FieldNameToByteString ,
78
-
79
- // Marshal Go byte arrays to CBOR arrays of integers (as in JSON) instead of byte
80
- // strings.
81
- ByteArray : cbor .ByteArrayToArray ,
82
-
83
- // Marshal []byte to CBOR byte string enclosed in tag 22 (expected later base64
84
- // encoding, https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.5.2), to
85
- // interoperate with the existing JSON behavior. This indicates to the decoder that,
86
- // when decoding into a string (or unstructured), the resulting value should be the
87
- // base64 encoding of the original bytes. No base64 encoding or decoding needs to be
88
- // performed for []byte-to-CBOR-to-[]byte roundtrips.
89
- ByteSliceLaterFormat : cbor .ByteSliceLaterFormatBase64 ,
90
-
91
- // Disable default recognition of types implementing encoding.BinaryMarshaler, which
92
- // is not recognized for JSON encoding.
93
- BinaryMarshaler : cbor .BinaryMarshalerNone ,
94
- }.EncMode ()
95
- if err != nil {
96
- panic (err )
25
+ var Encode = EncMode {
26
+ delegate : func () cbor.UserBufferEncMode {
27
+ encode , err := cbor.EncOptions {
28
+ // Map keys need to be sorted to have deterministic output, and this is the order
29
+ // defined in RFC 8949 4.2.1 "Core Deterministic Encoding Requirements".
30
+ Sort : cbor .SortBytewiseLexical ,
31
+
32
+ // CBOR supports distinct types for IEEE-754 float16, float32, and float64. Store
33
+ // floats in the smallest width that preserves value so that equivalent float32 and
34
+ // float64 values encode to identical bytes, as they do in a JSON
35
+ // encoding. Satisfies one of the "Core Deterministic Encoding Requirements".
36
+ ShortestFloat : cbor .ShortestFloat16 ,
37
+
38
+ // Error on attempt to encode NaN and infinite values. This is what the JSON
39
+ // serializer does.
40
+ NaNConvert : cbor .NaNConvertReject ,
41
+ InfConvert : cbor .InfConvertReject ,
42
+
43
+ // Error on attempt to encode math/big.Int values, which can't be faithfully
44
+ // roundtripped through Unstructured in general (the dynamic numeric types allowed
45
+ // in Unstructured are limited to float64 and int64).
46
+ BigIntConvert : cbor .BigIntConvertReject ,
47
+
48
+ // MarshalJSON for time.Time writes RFC3339 with nanos.
49
+ Time : cbor .TimeRFC3339Nano ,
50
+
51
+ // The decoder must be able to accept RFC3339 strings with or without tag 0 (e.g. by
52
+ // the end of time.Time -> JSON -> Unstructured -> CBOR, the CBOR encoder has no
53
+ // reliable way of knowing that a particular string originated from serializing a
54
+ // time.Time), so producing tag 0 has little use.
55
+ TimeTag : cbor .EncTagNone ,
56
+
57
+ // Indefinite-length items have multiple encodings and aren't being used anyway, so
58
+ // disable to avoid an opportunity for nondeterminism.
59
+ IndefLength : cbor .IndefLengthForbidden ,
60
+
61
+ // Preserve distinction between nil and empty for slices and maps.
62
+ NilContainers : cbor .NilContainerAsNull ,
63
+
64
+ // OK to produce tags.
65
+ TagsMd : cbor .TagsAllowed ,
66
+
67
+ // Use the same definition of "empty" as encoding/json.
68
+ OmitEmpty : cbor .OmitEmptyGoValue ,
69
+
70
+ // The CBOR types text string and byte string are structurally equivalent, with the
71
+ // semantic difference that a text string whose content is an invalid UTF-8 sequence
72
+ // is itself invalid. We reject all invalid text strings at decode time and do not
73
+ // validate or sanitize all Go strings at encode time. Encoding Go strings to the
74
+ // byte string type is comparable to the existing Protobuf behavior and cheaply
75
+ // ensures that the output is valid CBOR.
76
+ String : cbor .StringToByteString ,
77
+
78
+ // Encode struct field names to the byte string type rather than the text string
79
+ // type.
80
+ FieldName : cbor .FieldNameToByteString ,
81
+
82
+ // Marshal Go byte arrays to CBOR arrays of integers (as in JSON) instead of byte
83
+ // strings.
84
+ ByteArray : cbor .ByteArrayToArray ,
85
+
86
+ // Marshal []byte to CBOR byte string enclosed in tag 22 (expected later base64
87
+ // encoding, https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.5.2), to
88
+ // interoperate with the existing JSON behavior. This indicates to the decoder that,
89
+ // when decoding into a string (or unstructured), the resulting value should be the
90
+ // base64 encoding of the original bytes. No base64 encoding or decoding needs to be
91
+ // performed for []byte-to-CBOR-to-[]byte roundtrips.
92
+ ByteSliceLaterFormat : cbor .ByteSliceLaterFormatBase64 ,
93
+
94
+ // Disable default recognition of types implementing encoding.BinaryMarshaler, which
95
+ // is not recognized for JSON encoding.
96
+ BinaryMarshaler : cbor .BinaryMarshalerNone ,
97
+ }.UserBufferEncMode ()
98
+ if err != nil {
99
+ panic (err )
100
+ }
101
+ return encode
102
+ }(),
103
+ }
104
+
105
+ var EncodeNondeterministic = EncMode {
106
+ delegate : func () cbor.UserBufferEncMode {
107
+ opts := Encode .options ()
108
+ opts .Sort = cbor .SortNone // TODO: Use cbor.SortFastShuffle after bump to v2.7.0.
109
+ em , err := opts .UserBufferEncMode ()
110
+ if err != nil {
111
+ panic (err )
112
+ }
113
+ return em
114
+ }(),
115
+ }
116
+
117
+ type EncMode struct {
118
+ delegate cbor.UserBufferEncMode
119
+ }
120
+
121
+ func (em EncMode ) options () cbor.EncOptions {
122
+ return em .delegate .EncOptions ()
123
+ }
124
+
125
+ func (em EncMode ) MarshalTo (v interface {}, w io.Writer ) error {
126
+ if buf , ok := w .(* buffer ); ok {
127
+ return em .delegate .MarshalToBuffer (v , & buf .Buffer )
128
+ }
129
+
130
+ buf := buffers .Get ()
131
+ defer buffers .Put (buf )
132
+ if err := em .delegate .MarshalToBuffer (v , & buf .Buffer ); err != nil {
133
+ return err
134
+ }
135
+
136
+ if _ , err := io .Copy (w , buf ); err != nil {
137
+ return err
97
138
}
98
- return encode
99
- }()
100
-
101
- var EncodeNondeterministic cbor.EncMode = func () cbor.EncMode {
102
- opts := Encode .EncOptions ()
103
- opts .Sort = cbor .SortNone
104
- em , err := opts .EncMode ()
105
- if err != nil {
106
- panic (err )
139
+
140
+ return nil
141
+ }
142
+
143
+ func (em EncMode ) Marshal (v interface {}) ([]byte , error ) {
144
+ buf := buffers .Get ()
145
+ defer buffers .Put (buf )
146
+
147
+ if err := em .MarshalTo (v , & buf .Buffer ); err != nil {
148
+ return nil , err
107
149
}
108
- return em
109
- }()
150
+
151
+ clone := make ([]byte , buf .Len ())
152
+ copy (clone , buf .Bytes ())
153
+
154
+ return clone , nil
155
+ }
0 commit comments