@@ -113,54 +113,43 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
113
113
return fncs
114
114
}
115
115
116
- // Handle custom marshaler.
117
- switch which := implementsWhich (t , jsonMarshalerV2Type , jsonMarshalerV1Type , textAppenderType , textMarshalerType ); which {
118
- case jsonMarshalerV2Type :
116
+ if implements (t , textMarshalerType ) {
119
117
fncs .nonDefault = true
120
118
fncs .marshal = func (enc * jsontext.Encoder , va addressableValue , mo * jsonopts.Struct ) error {
121
- xe := export .Encoder (enc )
122
- prevDepth , prevLength := xe .Tokens .DepthLength ()
123
- xe .Flags .Set (jsonflags .WithinArshalCall | 1 )
124
- err := va .Addr ().Interface ().(MarshalerV2 ).MarshalJSONV2 (enc , mo )
125
- xe .Flags .Set (jsonflags .WithinArshalCall | 0 )
126
- currDepth , currLength := xe .Tokens .DepthLength ()
127
- if (prevDepth != currDepth || prevLength + 1 != currLength ) && err == nil {
128
- err = errNonSingularValue
129
- }
130
- if err != nil {
119
+ marshaler := va .Addr ().Interface ().(encoding.TextMarshaler )
120
+ if err := export .Encoder (enc ).AppendRaw ('"' , false , func (b []byte ) ([]byte , error ) {
121
+ b2 , err := marshaler .MarshalText ()
122
+ return append (b , b2 ... ), err
123
+ }); err != nil {
131
124
err = wrapSkipFunc (err , "marshal method" )
132
- if xe .Flags .Get (jsonflags .ReportLegacyErrorValues ) {
133
- return internal .NewMarshalerError (va .Addr ().Interface (), err , "MarshalJSONV2 " ) // unlike unmarshal, always wrapped
125
+ if export . Encoder ( enc ) .Flags .Get (jsonflags .ReportLegacyErrorValues ) {
126
+ return internal .NewMarshalerError (va .Addr ().Interface (), err , "MarshalText " ) // unlike unmarshal, always wrapped
134
127
}
135
- if ! export .IsIOError (err ) {
136
- err = newSemanticErrorWithPosition (enc , t , prevDepth , prevLength , err )
128
+ if ! isSemanticError ( err ) && ! export .IsIOError (err ) {
129
+ err = newMarshalErrorBefore (enc , t , err )
137
130
}
138
131
return err
139
132
}
140
133
return nil
141
134
}
142
- case jsonMarshalerV1Type :
143
- fncs .nonDefault = true
144
- fncs .marshal = func (enc * jsontext.Encoder , va addressableValue , mo * jsonopts.Struct ) error {
145
- marshaler := va .Addr ().Interface ().(MarshalerV1 )
146
- val , err := marshaler .MarshalJSON ()
147
- if err != nil {
148
- err = wrapSkipFunc (err , "marshal method" )
149
- if export .Encoder (enc ).Flags .Get (jsonflags .ReportLegacyErrorValues ) {
150
- return internal .NewMarshalerError (va .Addr ().Interface (), err , "MarshalJSON" ) // unlike unmarshal, always wrapped
151
- }
152
- err = newMarshalErrorBefore (enc , t , err )
153
- return collapseSemanticErrors (err )
154
- }
155
- if err := enc .WriteValue (val ); err != nil {
156
- if isSyntacticError (err ) {
157
- err = newMarshalErrorBefore (enc , t , err )
135
+ // TODO(https://go.dev/issue/62384): Rely on encoding.TextAppender instead.
136
+ if implements (t , appenderToType ) && t .PkgPath () == "net/netip" {
137
+ fncs .marshal = func (enc * jsontext.Encoder , va addressableValue , mo * jsonopts.Struct ) error {
138
+ appender := va .Addr ().Interface ().(interface { AppendTo ([]byte ) []byte })
139
+ if err := export .Encoder (enc ).AppendRaw ('"' , false , func (b []byte ) ([]byte , error ) {
140
+ return appender .AppendTo (b ), nil
141
+ }); err != nil {
142
+ if ! isSemanticError (err ) && ! export .IsIOError (err ) {
143
+ err = newMarshalErrorBefore (enc , t , err )
144
+ }
145
+ return err
158
146
}
159
- return err
147
+ return nil
160
148
}
161
- return nil
162
149
}
163
- case textAppenderType :
150
+ }
151
+
152
+ if implements (t , textAppenderType ) {
164
153
fncs .nonDefault = true
165
154
fncs .marshal = func (enc * jsontext.Encoder , va addressableValue , mo * jsonopts.Struct ) (err error ) {
166
155
appender := va .Addr ().Interface ().(encodingTextAppender )
@@ -176,69 +165,92 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
176
165
}
177
166
return nil
178
167
}
179
- case textMarshalerType :
168
+ }
169
+
170
+ if implements (t , jsonMarshalerV1Type ) {
180
171
fncs .nonDefault = true
181
172
fncs .marshal = func (enc * jsontext.Encoder , va addressableValue , mo * jsonopts.Struct ) error {
182
- marshaler := va .Addr ().Interface ().(encoding.TextMarshaler )
183
- if err := export .Encoder (enc ).AppendRaw ('"' , false , func (b []byte ) ([]byte , error ) {
184
- b2 , err := marshaler .MarshalText ()
185
- return append (b , b2 ... ), err
186
- }); err != nil {
173
+ marshaler := va .Addr ().Interface ().(MarshalerV1 )
174
+ val , err := marshaler .MarshalJSON ()
175
+ if err != nil {
187
176
err = wrapSkipFunc (err , "marshal method" )
188
177
if export .Encoder (enc ).Flags .Get (jsonflags .ReportLegacyErrorValues ) {
189
- return internal .NewMarshalerError (va .Addr ().Interface (), err , "MarshalText " ) // unlike unmarshal, always wrapped
178
+ return internal .NewMarshalerError (va .Addr ().Interface (), err , "MarshalJSON " ) // unlike unmarshal, always wrapped
190
179
}
191
- if ! isSemanticError (err ) && ! export .IsIOError (err ) {
180
+ err = newMarshalErrorBefore (enc , t , err )
181
+ return collapseSemanticErrors (err )
182
+ }
183
+ if err := enc .WriteValue (val ); err != nil {
184
+ if isSyntacticError (err ) {
192
185
err = newMarshalErrorBefore (enc , t , err )
193
186
}
194
187
return err
195
188
}
196
189
return nil
197
190
}
198
- // TODO(https://go.dev/issue/62384): Rely on encoding.TextAppender instead.
199
- if implementsWhich (t , appenderToType ) != nil && t .PkgPath () == "net/netip" {
200
- fncs .marshal = func (enc * jsontext.Encoder , va addressableValue , mo * jsonopts.Struct ) error {
201
- appender := va .Addr ().Interface ().(interface { AppendTo ([]byte ) []byte })
202
- if err := export .Encoder (enc ).AppendRaw ('"' , false , func (b []byte ) ([]byte , error ) {
203
- return appender .AppendTo (b ), nil
204
- }); err != nil {
205
- if ! isSemanticError (err ) && ! export .IsIOError (err ) {
206
- err = newMarshalErrorBefore (enc , t , err )
207
- }
208
- return err
191
+ }
192
+
193
+ if implements (t , jsonMarshalerV2Type ) {
194
+ fncs .nonDefault = true
195
+ fncs .marshal = func (enc * jsontext.Encoder , va addressableValue , mo * jsonopts.Struct ) error {
196
+ xe := export .Encoder (enc )
197
+ prevDepth , prevLength := xe .Tokens .DepthLength ()
198
+ xe .Flags .Set (jsonflags .WithinArshalCall | 1 )
199
+ err := va .Addr ().Interface ().(MarshalerV2 ).MarshalJSONV2 (enc , mo )
200
+ xe .Flags .Set (jsonflags .WithinArshalCall | 0 )
201
+ currDepth , currLength := xe .Tokens .DepthLength ()
202
+ if (prevDepth != currDepth || prevLength + 1 != currLength ) && err == nil {
203
+ err = errNonSingularValue
204
+ }
205
+ if err != nil {
206
+ err = wrapSkipFunc (err , "marshal method" )
207
+ if xe .Flags .Get (jsonflags .ReportLegacyErrorValues ) {
208
+ return internal .NewMarshalerError (va .Addr ().Interface (), err , "MarshalJSONV2" ) // unlike unmarshal, always wrapped
209
209
}
210
- return nil
210
+ if ! export .IsIOError (err ) {
211
+ err = newSemanticErrorWithPosition (enc , t , prevDepth , prevLength , err )
212
+ }
213
+ return err
211
214
}
215
+ return nil
212
216
}
213
217
}
214
218
215
- // Handle custom unmarshaler.
216
- switch which := implementsWhich (t , jsonUnmarshalerV2Type , jsonUnmarshalerV1Type , textUnmarshalerType ); which {
217
- case jsonUnmarshalerV2Type :
219
+ if implements (t , textUnmarshalerType ) {
218
220
fncs .nonDefault = true
219
221
fncs .unmarshal = func (dec * jsontext.Decoder , va addressableValue , uo * jsonopts.Struct ) error {
220
222
xd := export .Decoder (dec )
221
- prevDepth , prevLength := xd .Tokens .DepthLength ()
222
- xd .Flags .Set (jsonflags .WithinArshalCall | 1 )
223
- err := va .Addr ().Interface ().(UnmarshalerV2 ).UnmarshalJSONV2 (dec , uo )
224
- xd .Flags .Set (jsonflags .WithinArshalCall | 0 )
225
- currDepth , currLength := xd .Tokens .DepthLength ()
226
- if (prevDepth != currDepth || prevLength + 1 != currLength ) && err == nil {
227
- err = errNonSingularValue
228
- }
223
+ var flags jsonwire.ValueFlags
224
+ val , err := xd .ReadValue (& flags )
229
225
if err != nil {
226
+ return err // must be a syntactic or I/O error
227
+ }
228
+ if val .Kind () == 'n' {
229
+ if ! uo .Flags .Get (jsonflags .MergeWithLegacySemantics ) {
230
+ va .SetZero ()
231
+ }
232
+ return nil
233
+ }
234
+ if val .Kind () != '"' {
235
+ return newUnmarshalErrorAfter (dec , t , errNonStringValue )
236
+ }
237
+ s := jsonwire .UnquoteMayCopy (val , flags .IsVerbatim ())
238
+ unmarshaler := va .Addr ().Interface ().(encoding.TextUnmarshaler )
239
+ if err := unmarshaler .UnmarshalText (s ); err != nil {
230
240
err = wrapSkipFunc (err , "unmarshal method" )
231
- if xd .Flags .Get (jsonflags .ReportLegacyErrorValues ) {
241
+ if export . Decoder ( dec ) .Flags .Get (jsonflags .ReportLegacyErrorValues ) {
232
242
return err // unlike marshal, never wrapped
233
243
}
234
- if ! isSyntacticError (err ) && ! export .IsIOError (err ) {
235
- err = newSemanticErrorWithPosition (dec , t , prevDepth , prevLength , err )
244
+ if ! isSemanticError ( err ) && ! isSyntacticError (err ) && ! export .IsIOError (err ) {
245
+ err = newUnmarshalErrorAfter (dec , t , err )
236
246
}
237
247
return err
238
248
}
239
249
return nil
240
250
}
241
- case jsonUnmarshalerV1Type :
251
+ }
252
+
253
+ if implements (t , jsonUnmarshalerV1Type ) {
242
254
fncs .nonDefault = true
243
255
fncs .unmarshal = func (dec * jsontext.Decoder , va addressableValue , uo * jsonopts.Struct ) error {
244
256
val , err := dec .ReadValue ()
@@ -256,33 +268,27 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
256
268
}
257
269
return nil
258
270
}
259
- case textUnmarshalerType :
271
+ }
272
+
273
+ if implements (t , jsonUnmarshalerV2Type ) {
260
274
fncs .nonDefault = true
261
275
fncs .unmarshal = func (dec * jsontext.Decoder , va addressableValue , uo * jsonopts.Struct ) error {
262
276
xd := export .Decoder (dec )
263
- var flags jsonwire.ValueFlags
264
- val , err := xd .ReadValue (& flags )
265
- if err != nil {
266
- return err // must be a syntactic or I/O error
267
- }
268
- if val .Kind () == 'n' {
269
- if ! uo .Flags .Get (jsonflags .MergeWithLegacySemantics ) {
270
- va .SetZero ()
271
- }
272
- return nil
273
- }
274
- if val .Kind () != '"' {
275
- return newUnmarshalErrorAfter (dec , t , errNonStringValue )
277
+ prevDepth , prevLength := xd .Tokens .DepthLength ()
278
+ xd .Flags .Set (jsonflags .WithinArshalCall | 1 )
279
+ err := va .Addr ().Interface ().(UnmarshalerV2 ).UnmarshalJSONV2 (dec , uo )
280
+ xd .Flags .Set (jsonflags .WithinArshalCall | 0 )
281
+ currDepth , currLength := xd .Tokens .DepthLength ()
282
+ if (prevDepth != currDepth || prevLength + 1 != currLength ) && err == nil {
283
+ err = errNonSingularValue
276
284
}
277
- s := jsonwire .UnquoteMayCopy (val , flags .IsVerbatim ())
278
- unmarshaler := va .Addr ().Interface ().(encoding.TextUnmarshaler )
279
- if err := unmarshaler .UnmarshalText (s ); err != nil {
285
+ if err != nil {
280
286
err = wrapSkipFunc (err , "unmarshal method" )
281
- if export . Decoder ( dec ) .Flags .Get (jsonflags .ReportLegacyErrorValues ) {
287
+ if xd .Flags .Get (jsonflags .ReportLegacyErrorValues ) {
282
288
return err // unlike marshal, never wrapped
283
289
}
284
- if ! isSemanticError ( err ) && ! isSyntacticError (err ) && ! export .IsIOError (err ) {
285
- err = newUnmarshalErrorAfter (dec , t , err )
290
+ if ! isSyntacticError (err ) && ! export .IsIOError (err ) {
291
+ err = newSemanticErrorWithPosition (dec , t , prevDepth , prevLength , err )
286
292
}
287
293
return err
288
294
}
@@ -293,13 +299,19 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
293
299
return fncs
294
300
}
295
301
296
- // implementsWhich is like t.Implements(ifaceType) for a list of interfaces,
302
+ // implementsAny is like t.Implements(ifaceType) for a list of interfaces,
297
303
// but checks whether either t or reflect.PointerTo(t) implements the interface.
298
- func implementsWhich (t reflect.Type , ifaceTypes ... reflect.Type ) ( which reflect. Type ) {
304
+ func implementsAny (t reflect.Type , ifaceTypes ... reflect.Type ) bool {
299
305
for _ , ifaceType := range ifaceTypes {
300
- if t . Implements ( ifaceType ) || reflect . PointerTo ( t ). Implements ( ifaceType ) {
301
- return ifaceType
306
+ if implements ( t , ifaceType ) {
307
+ return true
302
308
}
303
309
}
304
- return nil
310
+ return false
311
+ }
312
+
313
+ // implements is like t.Implements(ifaceType) but checks whether
314
+ // either t or reflect.PointerTo(t) implements the interface.
315
+ func implements (t , ifaceType reflect.Type ) bool {
316
+ return t .Implements (ifaceType ) || reflect .PointerTo (t ).Implements (ifaceType )
305
317
}
0 commit comments