Skip to content

Commit 8badb25

Browse files
committed
codecgen: support time.Time natively, and handle omitEmpty for structs
Fixes #224 Fixes #225
1 parent 6e9891a commit 8badb25

File tree

1 file changed

+48
-17
lines changed

1 file changed

+48
-17
lines changed

codec/gen.go

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ var (
135135
genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`)
136136
)
137137

138+
type genBuf struct {
139+
buf []byte
140+
}
141+
142+
func (x *genBuf) s(s string) *genBuf { x.buf = append(x.buf, s...); return x }
143+
func (x *genBuf) b(s []byte) *genBuf { x.buf = append(x.buf, s...); return x }
144+
func (x *genBuf) v() string { return string(x.buf) }
145+
138146
// genRunner holds some state used during a Gen run.
139147
type genRunner struct {
140148
w io.Writer // output
@@ -697,13 +705,17 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
697705
}
698706

699707
// check if
700-
// - type is RawExt, Raw
708+
// - type is time.Time, RawExt, Raw
701709
// - the type implements (Text|JSON|Binary)(Unm|M)arshal
702710
x.linef("%sm%s := z.EncBinary()", genTempVarPfx, mi)
703711
x.linef("_ = %sm%s", genTempVarPfx, mi)
704712
x.line("if false {") //start if block
705713
defer func() { x.line("}") }() //end if block
706714

715+
if t == timeTyp {
716+
x.linef("} else { r.EncodeTime(*%s)", varname)
717+
return
718+
}
707719
if t == rawTyp {
708720
x.linef("} else { z.EncRaw(%s)", varname)
709721
return
@@ -848,6 +860,29 @@ func (x *genRunner) encZero(t reflect.Type) {
848860
}
849861
}
850862

863+
func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) {
864+
// smartly check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc.
865+
// also, for maps/slices/arrays, check if len ! 0 (not if == zero value)
866+
switch t2.Type.Kind() {
867+
case reflect.Struct:
868+
// fmt.Printf(">>>> structfield: omitempty: type: %s, field: %s\n", t2.Type.Name(), t2.Name)
869+
buf.s("true ")
870+
varname2 := varname + "." + t2.Name
871+
for i, n := 0, t2.Type.NumField(); i < n; i++ {
872+
f := t2.Type.Field(i)
873+
if f.PkgPath != "" { // unexported
874+
continue
875+
}
876+
buf.s(" && ")
877+
x.encOmitEmptyLine(f, varname2, buf)
878+
}
879+
case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan:
880+
buf.s("len(").s(varname).s(".").s(t2.Name).s(") != 0")
881+
default:
882+
buf.s(varname).s(".").s(t2.Name).s(" != ").s(x.genZeroValueR(t2.Type))
883+
}
884+
}
885+
851886
func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
852887
// Use knowledge from structfieldinfo (mbs, encodable fields. Ignore omitempty. )
853888
// replicate code in kStruct i.e. for each field, deref type to non-pointer, and call x.enc on it
@@ -881,7 +916,7 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
881916
continue
882917
}
883918
var t2 reflect.StructField
884-
var omitline string
919+
var omitline genBuf
885920
{
886921
t2typ := t
887922
varname3 := varname
@@ -900,21 +935,13 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
900935
// do not include actual field in the omit line.
901936
// that is done subsequently (right after - below).
902937
if uint8(ij+1) < si.nis && t2typ.Kind() == reflect.Ptr {
903-
omitline += varname3 + " != nil && "
938+
omitline.s(varname3).s(" != nil && ")
939+
// omitline += varname3 + " != nil && "
904940
}
905941
}
906942
}
907-
// never check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc.
908-
// also, for maps/slices/arrays, check if len ! 0 (not if == zero value)
909-
switch t2.Type.Kind() {
910-
case reflect.Struct:
911-
omitline += " true"
912-
case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan:
913-
omitline += "len(" + varname + "." + t2.Name + ") != 0"
914-
default:
915-
omitline += varname + "." + t2.Name + " != " + x.genZeroValueR(t2.Type)
916-
}
917-
x.linef("%s[%v] = %s", numfieldsvar, j, omitline)
943+
x.encOmitEmptyLine(t2, varname, &omitline)
944+
x.linef("%s[%v] = %s", numfieldsvar, j, omitline.v())
918945
}
919946
}
920947
// x.linef("var %snn%s int", genTempVarPfx, i)
@@ -1163,14 +1190,18 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
11631190
}
11641191

11651192
// check if
1166-
// - type is Raw, RawExt
1193+
// - type is time.Time, Raw, RawExt
11671194
// - the type implements (Text|JSON|Binary)(Unm|M)arshal
11681195
mi := x.varsfx()
11691196
x.linef("%sm%s := z.DecBinary()", genTempVarPfx, mi)
11701197
x.linef("_ = %sm%s", genTempVarPfx, mi)
11711198
x.line("if false {") //start if block
11721199
defer func() { x.line("}") }() //end if block
11731200

1201+
if t == timeTyp {
1202+
x.linef("} else { *%v = r.DecodeTime()", varname)
1203+
return
1204+
}
11741205
if t == rawTyp {
11751206
x.linef("} else { *%v = z.DecRaw()", varname)
11761207
return
@@ -1677,7 +1708,7 @@ func genImportPath(t reflect.Type) (s string) {
16771708
s = t.PkgPath()
16781709
if genCheckVendor {
16791710
// HACK: always handle vendoring. It should be typically on in go 1.6, 1.7
1680-
s = stripVendor(s)
1711+
s = genStripVendor(s)
16811712
}
16821713
return
16831714
}
@@ -1926,7 +1957,7 @@ func genInternalSortType(s string, elem bool) string {
19261957
panic("sorttype: unexpected type: " + s)
19271958
}
19281959

1929-
func stripVendor(s string) string {
1960+
func genStripVendor(s string) string {
19301961
// HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
19311962
// if s contains /vendor/ OR startsWith vendor/, then return everything after it.
19321963
const vendorStart = "vendor/"

0 commit comments

Comments
 (0)