From bb169a5cf6b654f216f33ef50f953546425d604f Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Fri, 8 May 2020 20:25:49 +0900 Subject: [PATCH] Support UnmarshalText for decoding --- decode.go | 4 ++-- decode_test.go | 21 +++++++++++++++++++++ decode_unmarshal_text.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 decode_unmarshal_text.go diff --git a/decode.go b/decode.go index 143294a..923cdce 100644 --- a/decode.go +++ b/decode.go @@ -152,7 +152,7 @@ func (d *Decoder) compileHead(typ *rtype) (decoder, error) { if typ.Implements(unmarshalJSONType) { return newUnmarshalJSONDecoder(typ), nil } else if typ.Implements(unmarshalTextType) { - + return newUnmarshalTextDecoder(typ), nil } return d.compile(typ.Elem()) } @@ -161,7 +161,7 @@ func (d *Decoder) compile(typ *rtype) (decoder, error) { if typ.Implements(unmarshalJSONType) { return newUnmarshalJSONDecoder(typ), nil } else if typ.Implements(unmarshalTextType) { - + return newUnmarshalTextDecoder(typ), nil } switch typ.Kind() { case reflect.Ptr: diff --git a/decode_test.go b/decode_test.go index cd9011d..ca975bb 100644 --- a/decode_test.go +++ b/decode_test.go @@ -197,3 +197,24 @@ func Test_UnmarshalJSON(t *testing.T) { 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) + }) +} diff --git a/decode_unmarshal_text.go b/decode_unmarshal_text.go new file mode 100644 index 0000000..b74dda8 --- /dev/null +++ b/decode_unmarshal_text.go @@ -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 +}