proper encoding.TextMarshaler interfaces handling

Currently easyjson doesn't handle [encoding.TextMarshaler][1] interfaces.
This leads to a situation where types like [net.IP][2] are handled
as Base64Bytes.

[1]: https://godoc.org/encoding#TextMarshaler
[2]: https://godoc.org/net#IP
This commit is contained in:
Vladimir Varankin
2017-03-06 21:23:53 +03:00
parent 44f6bc771e
commit 1a411a8244
5 changed files with 82 additions and 4 deletions
+9
View File
@@ -1,6 +1,7 @@
package gen
import (
"encoding"
"encoding/json"
"fmt"
"reflect"
@@ -65,6 +66,14 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, i
return nil
}
unmarshalerIface = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
if reflect.PtrTo(t).Implements(unmarshalerIface) {
fmt.Fprintln(g.out, ws+"if data := in.UnsafeString(); in.Ok() {")
fmt.Fprintln(g.out, ws+" in.AddError( ("+out+").UnmarshalText([]byte(data)) )")
fmt.Fprintln(g.out, ws+"}")
return nil
}
err := g.genTypeDecoderNoCheck(t, out, tags, indent)
return err
}
+7
View File
@@ -1,6 +1,7 @@
package gen
import (
"encoding"
"encoding/json"
"fmt"
"reflect"
@@ -95,6 +96,12 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, in
return nil
}
marshalerIface = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
if reflect.PtrTo(t).Implements(marshalerIface) {
fmt.Fprintln(g.out, ws+"out.RawText( ("+in+").MarshalText() )")
return nil
}
err := g.genTypeEncoderNoCheck(t, in, tags, indent)
return err
}
+18 -1
View File
@@ -68,7 +68,7 @@ func (w *Writer) RawString(s string) {
w.Buffer.AppendString(s)
}
// RawByte appends raw binary data to the buffer or sets the error if it is given. Useful for
// Raw appends raw binary data to the buffer or sets the error if it is given. Useful for
// calling with results of MarshalJSON-like functions.
func (w *Writer) Raw(data []byte, err error) {
switch {
@@ -83,6 +83,23 @@ func (w *Writer) Raw(data []byte, err error) {
}
}
// RawText encloses raw binary data in quotes and appends in to the buffer.
// Useful for calling with results of MarshalText-like functions.
func (w *Writer) RawText(data []byte, err error) {
switch {
case w.Error != nil:
return
case err != nil:
w.Error = err
case len(data) > 0:
w.Buffer.AppendByte('"')
w.Buffer.AppendBytes(data)
w.Buffer.AppendByte('"')
default:
w.RawString("null")
}
}
// Base64Bytes appends data to the buffer after base64 encoding it
func (w *Writer) Base64Bytes(data []byte) {
if data == nil {
+1
View File
@@ -28,6 +28,7 @@ var testCases = []struct {
{&optsValue, optsString},
{&rawValue, rawString},
{&stdMarshalerValue, stdMarshalerString},
{&userMarshalerValue, userMarshalerString},
{&unexportedStructValue, unexportedStructString},
{&excludedFieldValue, excludedFieldString},
{&sliceValue, sliceString},
+47 -3
View File
@@ -3,6 +3,7 @@ package tests
import (
"fmt"
"math"
"net"
"time"
"github.com/mailru/easyjson"
@@ -392,11 +393,54 @@ var rawString = `{` +
`}`
type StdMarshaler struct {
T time.Time
T time.Time
IP net.IP
}
var stdMarshalerValue = StdMarshaler{T: time.Date(2016, 01, 02, 14, 15, 10, 0, time.UTC)}
var stdMarshalerString = `{"T":"2016-01-02T14:15:10Z"}`
var stdMarshalerValue = StdMarshaler{
T: time.Date(2016, 01, 02, 14, 15, 10, 0, time.UTC),
IP: net.IPv4(192, 168, 0, 1),
}
var stdMarshalerString = `{` +
`"T":"2016-01-02T14:15:10Z",` +
`"IP":"192.168.0.1"` +
`}`
type UserMarshaler struct {
V vMarshaler
T tMarshaler
}
type vMarshaler net.IP
func (v vMarshaler) MarshalJSON() ([]byte, error) {
return []byte(`"0::0"`), nil
}
func (v *vMarshaler) UnmarshalJSON([]byte) error {
*v = vMarshaler(net.IPv6zero)
return nil
}
type tMarshaler net.IP
func (v tMarshaler) MarshalText() ([]byte, error) {
return []byte(`[0::0]`), nil
}
func (v *tMarshaler) UnmarshalText([]byte) error {
*v = tMarshaler(net.IPv6zero)
return nil
}
var userMarshalerValue = UserMarshaler{
V: vMarshaler(net.IPv6zero),
T: tMarshaler(net.IPv6zero),
}
var userMarshalerString = `{` +
`"V":"0::0",` +
`"T":"[0::0]"` +
`}`
type unexportedStruct struct {
Value string