Skip to content

Commit

Permalink
support encoding.TextUnmarshaler and add example test
Browse files Browse the repository at this point in the history
  • Loading branch information
Songmu committed Jul 12, 2016
1 parent 6737863 commit 0c4ba88
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 17 deletions.
43 changes: 36 additions & 7 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,16 @@ func Unmarshal(data []byte, v interface{}) error {
continue
}
fv.SetFloat(n)
case reflect.Interface:
if tu, ok := fv.Interface().(encoding.TextUnmarshaler); ok {
err := tu.UnmarshalText([]byte(s))
default:
u := indirect(fv)
if u == nil {
errs[ft.Name] = &UnmarshalTypeError{s, fv.Type()}
} else {
err := u.UnmarshalText([]byte(s))
if err != nil {
errs[ft.Name] = err
}
continue
}
fallthrough
default:
errs[ft.Name] = &UnmarshalTypeError{s, fv.Type()}
}
}

Expand All @@ -160,3 +159,33 @@ func Unmarshal(data []byte, v interface{}) error {
}
return errs
}

func indirect(v reflect.Value) encoding.TextUnmarshaler {
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
v = v.Addr()
}
for {
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && e.Elem().Kind() == reflect.Ptr {
v = e
continue
}
}
if v.Kind() != reflect.Ptr {
break
}
if v.Elem().Kind() != reflect.Ptr && v.CanSet() {
break
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
if v.Type().NumMethod() > 0 {
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
return u
}
}
}
return nil
}
23 changes: 13 additions & 10 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,21 @@ func Marshal(v interface{}) ([]byte, error) {
arr = append(arr, key+":"+strconv.FormatUint(fv.Uint(), 10))
case reflect.Float32, reflect.Float64:
arr = append(arr, key+":"+strconv.FormatFloat(fv.Float(), 'f', -1, fv.Type().Bits()))
case reflect.Interface:
if u, ok := fv.Interface().(encoding.TextMarshaler); ok {
buf, err := u.MarshalText()
if err != nil {
errs[ft.Name] = err
} else {
arr = append(arr, key+":"+string(buf))
default:
if fv.Type().NumMethod() > 0 {
if u, ok := fv.Interface().(encoding.TextMarshaler); ok {
if u == nil {
continue
}
buf, err := u.MarshalText()
if err != nil {
errs[ft.Name] = err
} else {
arr = append(arr, key+":"+string(buf))
}
continue
}
continue
}
fallthrough
default:
errs[ft.Name] = &MarshalTypeError{fv.String(), fv.Type()}
}
}
Expand Down
89 changes: 89 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package ltsv_test

import (
"net"
"time"

"github.com/Songmu/go-ltsv"
"github.com/kr/pretty"
)

type log struct {
Time LogTime
Host net.IP
Req string
Status int
Size int
UA string
ReqTime float64
AppTime *float64
VHost string
}

const timeFormat = "2006-01-02T15:04:05Z07:00"

type LogTime struct {
time.Time
}

func (lt *LogTime) UnmarshalText(t []byte) error {
ti, err := time.Parse(timeFormat, string(t))
if err != nil {
return err
}
lt.Time = ti
return nil
}

func ExampleUnmarshal() {
ltsvLog := "time:2016-07-13T00:00:04+09:00\t" +
"host:192.0.2.1\t" +
"req:POST /api/v0/tsdb HTTP/1.1\t" +
"status:200\t" +
"size:36\t" +
"ua:ua:mackerel-agent/0.31.2 (Revision 775fad2)\t" +
"reqtime:0.087\t" +
"vhost:mackerel.io"
l := log{}
ltsv.Unmarshal([]byte(ltsvLog), &l)
pretty.Println(l)
// Output:
// ltsv_test.log{
// Time: ltsv_test.LogTime{
// Time: time.Time{
// sec: 63603932404,
// nsec: 0,
// loc: &time.Location{
// name: "Local",
// zone: {
// {name:"JCST", offset:32400, isDST:false},
// {name:"JDT", offset:36000, isDST:true},
// {name:"JST", offset:32400, isDST:false},
// },
// tx: {
// {when:-1017824400, index:0x2, isstd:false, isutc:false},
// {when:-683794800, index:0x1, isstd:false, isutc:false},
// {when:-672393600, index:0x2, isstd:false, isutc:false},
// {when:-654764400, index:0x1, isstd:false, isutc:false},
// {when:-640944000, index:0x2, isstd:false, isutc:false},
// {when:-620290800, index:0x1, isstd:false, isutc:false},
// {when:-609494400, index:0x2, isstd:false, isutc:false},
// {when:-588841200, index:0x1, isstd:false, isutc:false},
// {when:-578044800, index:0x2, isstd:false, isutc:false},
// },
// cacheStart: -578044800,
// cacheEnd: 9223372036854775807,
// cacheZone: &time.zone{(CYCLIC REFERENCE)},
// },
// },
// },
// Host: {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xc0, 0x0, 0x2, 0x1},
// Req: "POST /api/v0/tsdb HTTP/1.1",
// Status: 200,
// Size: 36,
// UA: "ua:mackerel-agent/0.31.2 (Revision 775fad2)",
// ReqTime: 0.087,
// AppTime: (*float64)(nil),
// VHost: "mackerel.io",
// }
}

0 comments on commit 0c4ba88

Please sign in to comment.