Support UnmarshalText for decoding

This commit is contained in:
Masaaki Goshima 2020-05-08 20:25:49 +09:00
parent c23e5f43a7
commit bb169a5cf6
3 changed files with 55 additions and 2 deletions

View File

@ -152,7 +152,7 @@ func (d *Decoder) compileHead(typ *rtype) (decoder, error) {
if typ.Implements(unmarshalJSONType) { if typ.Implements(unmarshalJSONType) {
return newUnmarshalJSONDecoder(typ), nil return newUnmarshalJSONDecoder(typ), nil
} else if typ.Implements(unmarshalTextType) { } else if typ.Implements(unmarshalTextType) {
return newUnmarshalTextDecoder(typ), nil
} }
return d.compile(typ.Elem()) return d.compile(typ.Elem())
} }
@ -161,7 +161,7 @@ func (d *Decoder) compile(typ *rtype) (decoder, error) {
if typ.Implements(unmarshalJSONType) { if typ.Implements(unmarshalJSONType) {
return newUnmarshalJSONDecoder(typ), nil return newUnmarshalJSONDecoder(typ), nil
} else if typ.Implements(unmarshalTextType) { } else if typ.Implements(unmarshalTextType) {
return newUnmarshalTextDecoder(typ), nil
} }
switch typ.Kind() { switch typ.Kind() {
case reflect.Ptr: case reflect.Ptr:

View File

@ -197,3 +197,24 @@ func Test_UnmarshalJSON(t *testing.T) {
assertEq(t, "unmarshal", v.v, 10) assertEq(t, "unmarshal", v.v, 10)
}) })
} }
type unmarshalText struct {
v int
}
func (u *unmarshalText) UnmarshalText(b []byte) error {
var v int
if err := json.Unmarshal(b, &v); err != nil {
return err
}
u.v = v
return nil
}
func Test_UnmarshalText(t *testing.T) {
t.Run("*struct", func(t *testing.T) {
var v unmarshalText
assertErr(t, json.Unmarshal([]byte(`11`), &v))
assertEq(t, "unmarshal", v.v, 11)
})
}

32
decode_unmarshal_text.go Normal file
View File

@ -0,0 +1,32 @@
package json
import (
"encoding"
"unsafe"
)
type unmarshalTextDecoder struct {
typ *rtype
}
func newUnmarshalTextDecoder(typ *rtype) *unmarshalTextDecoder {
return &unmarshalTextDecoder{typ: typ}
}
func (d *unmarshalTextDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) {
cursor = skipWhiteSpace(buf, cursor)
start := cursor
end, err := skipValue(buf, cursor)
if err != nil {
return 0, err
}
src := buf[start:end]
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: d.typ,
ptr: unsafe.Pointer(p),
}))
if err := v.(encoding.TextUnmarshaler).UnmarshalText(src); err != nil {
return 0, err
}
return end, nil
}