Skip to content

Commit 62e6b63

Browse files
committed
encoding/xml: make use of reflect.TypeAssert
To simplify the code and improve performance: goos: darwin goarch: arm64 pkg: encoding/xml cpu: Apple M4 │ old │ new │ │ sec/op │ sec/op vs base │ Marshal-10 1.925µ ± 2% 1.786µ ± 2% -7.22% (p=0.000 n=10) Unmarshal-10 3.866µ ± 1% 3.766µ ± 1% -2.59% (p=0.000 n=10) geomean 2.728µ 2.593µ -4.93% │ old │ new │ │ B/op │ B/op vs base │ Marshal-10 5.570Ki ± 0% 5.570Ki ± 0% ~ (p=1.000 n=10) ¹ Unmarshal-10 7.586Ki ± 0% 7.555Ki ± 0% -0.41% (p=0.000 n=10) geomean 6.500Ki 6.487Ki -0.21% ¹ all samples are equal │ old │ new │ │ allocs/op │ allocs/op vs base │ Marshal-10 23.00 ± 0% 23.00 ± 0% ~ (p=1.000 n=10) ¹ Unmarshal-10 185.0 ± 0% 184.0 ± 0% -0.54% (p=0.000 n=10) geomean 65.23 65.05 -0.27% ¹ all samples are equal Updates #62121
1 parent 594deca commit 62e6b63

File tree

2 files changed

+83
-52
lines changed

2 files changed

+83
-52
lines changed

src/encoding/xml/marshal.go

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -451,23 +451,29 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
451451

452452
// Check for marshaler.
453453
if val.CanInterface() && typ.Implements(marshalerType) {
454-
return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
454+
marshaler, _ := reflect.TypeAssert[Marshaler](val)
455+
return p.marshalInterface(marshaler, defaultStart(typ, finfo, startTemplate))
455456
}
456457
if val.CanAddr() {
457458
pv := val.Addr()
458-
if pv.CanInterface() && pv.Type().Implements(marshalerType) {
459-
return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
459+
if pv.CanInterface() {
460+
if marshaler, ok := reflect.TypeAssert[Marshaler](pv); ok {
461+
return p.marshalInterface(marshaler, defaultStart(pv.Type(), finfo, startTemplate))
462+
}
460463
}
461464
}
462465

463466
// Check for text marshaler.
464467
if val.CanInterface() && typ.Implements(textMarshalerType) {
465-
return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
468+
textMarshaler, _ := reflect.TypeAssert[encoding.TextMarshaler](val)
469+
return p.marshalTextInterface(textMarshaler, defaultStart(typ, finfo, startTemplate))
466470
}
467471
if val.CanAddr() {
468472
pv := val.Addr()
469-
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
470-
return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
473+
if pv.CanInterface() {
474+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](pv); ok {
475+
return p.marshalTextInterface(textMarshaler, defaultStart(pv.Type(), finfo, startTemplate))
476+
}
471477
}
472478
}
473479

@@ -503,7 +509,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
503509
start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
504510
} else {
505511
fv := xmlname.value(val, dontInitNilPointers)
506-
if v, ok := fv.Interface().(Name); ok && v.Local != "" {
512+
if v, ok := reflect.TypeAssert[Name](fv); ok && v.Local != "" {
507513
start.Name = v
508514
}
509515
}
@@ -581,7 +587,8 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
581587
// marshalAttr marshals an attribute with the given name and value, adding to start.Attr.
582588
func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
583589
if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
584-
attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
590+
marshaler, _ := reflect.TypeAssert[MarshalerAttr](val)
591+
attr, err := marshaler.MarshalXMLAttr(name)
585592
if err != nil {
586593
return err
587594
}
@@ -593,20 +600,23 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
593600

594601
if val.CanAddr() {
595602
pv := val.Addr()
596-
if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
597-
attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
598-
if err != nil {
599-
return err
600-
}
601-
if attr.Name.Local != "" {
602-
start.Attr = append(start.Attr, attr)
603+
if pv.CanInterface() {
604+
if marshaler, ok := reflect.TypeAssert[MarshalerAttr](pv); ok {
605+
attr, err := marshaler.MarshalXMLAttr(name)
606+
if err != nil {
607+
return err
608+
}
609+
if attr.Name.Local != "" {
610+
start.Attr = append(start.Attr, attr)
611+
}
612+
return nil
603613
}
604-
return nil
605614
}
606615
}
607616

608617
if val.CanInterface() && val.Type().Implements(textMarshalerType) {
609-
text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
618+
textMarshaler, _ := reflect.TypeAssert[encoding.TextMarshaler](val)
619+
text, err := textMarshaler.MarshalText()
610620
if err != nil {
611621
return err
612622
}
@@ -616,13 +626,15 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
616626

617627
if val.CanAddr() {
618628
pv := val.Addr()
619-
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
620-
text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
621-
if err != nil {
622-
return err
629+
if pv.CanInterface() {
630+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](pv); ok {
631+
text, err := textMarshaler.MarshalText()
632+
if err != nil {
633+
return err
634+
}
635+
start.Attr = append(start.Attr, Attr{name, string(text)})
636+
return nil
623637
}
624-
start.Attr = append(start.Attr, Attr{name, string(text)})
625-
return nil
626638
}
627639
}
628640

@@ -647,7 +659,8 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
647659
}
648660

649661
if val.Type() == attrType {
650-
start.Attr = append(start.Attr, val.Interface().(Attr))
662+
attr, _ := reflect.TypeAssert[Attr](val)
663+
start.Attr = append(start.Attr, attr)
651664
return nil
652665
}
653666

@@ -855,7 +868,8 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
855868
return err
856869
}
857870
if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
858-
data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
871+
textMarshaler, _ := reflect.TypeAssert[encoding.TextMarshaler](vf)
872+
data, err := textMarshaler.MarshalText()
859873
if err != nil {
860874
return err
861875
}
@@ -866,15 +880,17 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
866880
}
867881
if vf.CanAddr() {
868882
pv := vf.Addr()
869-
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
870-
data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
871-
if err != nil {
872-
return err
873-
}
874-
if err := emit(p, data); err != nil {
875-
return err
883+
if pv.CanInterface() {
884+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](pv); ok {
885+
data, err := textMarshaler.MarshalText()
886+
if err != nil {
887+
return err
888+
}
889+
if err := emit(p, data); err != nil {
890+
return err
891+
}
892+
continue
876893
}
877-
continue
878894
}
879895
}
880896

@@ -902,7 +918,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
902918
return err
903919
}
904920
case reflect.Slice:
905-
if elem, ok := vf.Interface().([]byte); ok {
921+
if elem, ok := reflect.TypeAssert[[]byte](vf); ok {
906922
if err := emit(p, elem); err != nil {
907923
return err
908924
}

src/encoding/xml/read.go

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -258,25 +258,31 @@ func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
258258
if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) {
259259
// This is an unmarshaler with a non-pointer receiver,
260260
// so it's likely to be incorrect, but we do what we're told.
261-
return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
261+
unmarshaler, _ := reflect.TypeAssert[UnmarshalerAttr](val)
262+
return unmarshaler.UnmarshalXMLAttr(attr)
262263
}
263264
if val.CanAddr() {
264265
pv := val.Addr()
265-
if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType) {
266-
return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
266+
if pv.CanInterface() {
267+
if unmarshaler, ok := reflect.TypeAssert[UnmarshalerAttr](pv); ok {
268+
return unmarshaler.UnmarshalXMLAttr(attr)
269+
}
267270
}
268271
}
269272

270273
// Not an UnmarshalerAttr; try encoding.TextUnmarshaler.
271274
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
272275
// This is an unmarshaler with a non-pointer receiver,
273276
// so it's likely to be incorrect, but we do what we're told.
274-
return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
277+
textUnmarshaler, _ := reflect.TypeAssert[encoding.TextUnmarshaler](val)
278+
return textUnmarshaler.UnmarshalText([]byte(attr.Value))
275279
}
276280
if val.CanAddr() {
277281
pv := val.Addr()
278-
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
279-
return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
282+
if pv.CanInterface() {
283+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
284+
return textUnmarshaler.UnmarshalText([]byte(attr.Value))
285+
}
280286
}
281287
}
282288

@@ -355,24 +361,30 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement, depth int) e
355361
if val.CanInterface() && val.Type().Implements(unmarshalerType) {
356362
// This is an unmarshaler with a non-pointer receiver,
357363
// so it's likely to be incorrect, but we do what we're told.
358-
return d.unmarshalInterface(val.Interface().(Unmarshaler), start)
364+
unmarshaler, _ := reflect.TypeAssert[Unmarshaler](val)
365+
return d.unmarshalInterface(unmarshaler, start)
359366
}
360367

361368
if val.CanAddr() {
362369
pv := val.Addr()
363-
if pv.CanInterface() && pv.Type().Implements(unmarshalerType) {
364-
return d.unmarshalInterface(pv.Interface().(Unmarshaler), start)
370+
if pv.CanInterface() {
371+
if unmarshaler, ok := reflect.TypeAssert[Unmarshaler](pv); ok {
372+
return d.unmarshalInterface(unmarshaler, start)
373+
}
365374
}
366375
}
367376

368377
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
369-
return d.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler))
378+
textUnmarshaler, _ := reflect.TypeAssert[encoding.TextUnmarshaler](val)
379+
return d.unmarshalTextInterface(textUnmarshaler)
370380
}
371381

372382
if val.CanAddr() {
373383
pv := val.Addr()
374-
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
375-
return d.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler))
384+
if pv.CanInterface() {
385+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
386+
return d.unmarshalTextInterface(textUnmarshaler)
387+
}
376388
}
377389
}
378390

@@ -453,7 +465,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement, depth int) e
453465
return UnmarshalError(e)
454466
}
455467
fv := finfo.value(sv, initNilPointers)
456-
if _, ok := fv.Interface().(Name); ok {
468+
if _, ok := reflect.TypeAssert[Name](fv); ok {
457469
fv.Set(reflect.ValueOf(start.Name))
458470
}
459471
}
@@ -579,19 +591,22 @@ Loop:
579591
}
580592

581593
if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Implements(textUnmarshalerType) {
582-
if err := saveData.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
594+
textUnmarshaler, _ := reflect.TypeAssert[encoding.TextUnmarshaler](saveData)
595+
if err := textUnmarshaler.UnmarshalText(data); err != nil {
583596
return err
584597
}
585598
saveData = reflect.Value{}
586599
}
587600

588601
if saveData.IsValid() && saveData.CanAddr() {
589602
pv := saveData.Addr()
590-
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
591-
if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
592-
return err
603+
if pv.CanInterface() {
604+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
605+
if err := textUnmarshaler.UnmarshalText(data); err != nil {
606+
return err
607+
}
608+
saveData = reflect.Value{}
593609
}
594-
saveData = reflect.Value{}
595610
}
596611
}
597612

0 commit comments

Comments
 (0)