-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
struct fields can be tagged with msgp:",omitempty" Such fields will not be serialized if they contain their zero values. There is no cost to this feature if tags are not used. For structs with many optional fields, the space and time savings can be substantial. Fixes #103
- Loading branch information
Showing
11 changed files
with
401 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package cfg | ||
|
||
import ( | ||
"flag" | ||
) | ||
|
||
type MsgpConfig struct { | ||
Out string | ||
GoFile string | ||
Encode bool | ||
Marshal bool | ||
Tests bool | ||
Unexported bool | ||
} | ||
|
||
// call DefineFlags before myflags.Parse() | ||
func (c *MsgpConfig) DefineFlags(fs *flag.FlagSet) { | ||
fs.StringVar(&c.Out, "o", "", "output file") | ||
fs.StringVar(&c.GoFile, "file", "", "input file") | ||
fs.BoolVar(&c.Encode, "io", true, "create Encode and Decode methods") | ||
fs.BoolVar(&c.Marshal, "marshal", true, "create Marshal and Unmarshal methods") | ||
fs.BoolVar(&c.Tests, "tests", true, "create tests and benchmarks") | ||
fs.BoolVar(&c.Unexported, "unexported", false, "also process unexported types") | ||
} | ||
|
||
// call c.ValidateConfig() after myflags.Parse() | ||
func (c *MsgpConfig) ValidateConfig() error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package gen | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
) | ||
|
||
func fieldsempty(w io.Writer) *fieldsEmpty { | ||
return &fieldsEmpty{ | ||
p: printer{w: w}, | ||
} | ||
} | ||
|
||
type fieldsEmpty struct { | ||
passes | ||
p printer | ||
recvr string | ||
} | ||
|
||
func (e *fieldsEmpty) Method() Method { return FieldsEmpty } | ||
|
||
func (e *fieldsEmpty) Execute(p Elem) error { | ||
if !e.p.ok() { | ||
return e.p.err | ||
} | ||
p = e.applyall(p) | ||
if p == nil { | ||
return nil | ||
} | ||
if !IsPrintable(p) { | ||
return nil | ||
} | ||
|
||
e.recvr = fmt.Sprintf("%s %s", p.Varname(), imutMethodReceiver(p)) | ||
|
||
next(e, p) | ||
return e.p.err | ||
} | ||
|
||
func (e *fieldsEmpty) gStruct(s *Struct) { | ||
e.p.printf("// fieldsNotEmpty supports omitempty tags\n") | ||
e.p.printf("func (%s) fieldsNotEmpty(isempty []bool) uint32 {", e.recvr) | ||
|
||
nfields := len(s.Fields) | ||
numOE := 0 | ||
for i := range s.Fields { | ||
if s.Fields[i].OmitEmpty { | ||
numOE++ | ||
} | ||
} | ||
if numOE == 0 { | ||
// no fields tagged with omitempty, just return the full field count. | ||
e.p.printf("\nreturn %d }\n", nfields) | ||
return | ||
} | ||
|
||
// remember this to avoid recomputing it in other passes. | ||
s.hasOmitEmptyTags = true | ||
|
||
om := emptyOmitter(&e.p, s.vname) | ||
|
||
e.p.printf("if len(isempty) == 0 { return %d }\n", nfields) | ||
e.p.printf("var fieldsInUse uint32 = %d\n", nfields) | ||
for i := range s.Fields { | ||
if s.Fields[i].OmitEmpty { | ||
e.p.printf("isempty[%d] = ", i) | ||
next(om, s.Fields[i].FieldElem) | ||
e.p.printf("if isempty[%d] { fieldsInUse-- }\n", i) | ||
} | ||
} | ||
e.p.printf("\n return fieldsInUse \n}\n") | ||
} | ||
|
||
func (s *fieldsEmpty) gPtr(p *Ptr) {} | ||
|
||
func (s *fieldsEmpty) gSlice(sl *Slice) {} | ||
|
||
func (s *fieldsEmpty) gArray(a *Array) {} | ||
|
||
func (s *fieldsEmpty) gMap(m *Map) {} | ||
|
||
func (s *fieldsEmpty) gBase(b *BaseElem) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package gen | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
func emptyOmitter(p *printer, varname string) *omitEmpty { | ||
return &omitEmpty{ | ||
p: p, | ||
varname: varname, | ||
} | ||
} | ||
|
||
type omitEmpty struct { | ||
p *printer | ||
varname string | ||
} | ||
|
||
func (s *omitEmpty) gStruct(st *Struct) { | ||
s.p.printf("false // struct values are never empty\n") | ||
} | ||
|
||
func (s *omitEmpty) gPtr(p *Ptr) { | ||
s.p.printf("(%s == nil) // pointer, omitempty\n", p.vname) | ||
} | ||
|
||
func (s *omitEmpty) gSlice(sl *Slice) { | ||
s.p.printf("%s", IsLenZero(sl.vname)) | ||
} | ||
|
||
func (s *omitEmpty) gArray(a *Array) { | ||
s.p.printf("%s", IsLenZero(a.vname)) | ||
} | ||
|
||
func (s *omitEmpty) gMap(m *Map) { | ||
s.p.printf("%s", IsLenZero(m.vname)) | ||
} | ||
|
||
func (s *omitEmpty) gBase(b *BaseElem) { | ||
switch b.Value { | ||
case Bytes: | ||
s.p.printf("%s", IsLenZero(b.Varname())) | ||
case String: | ||
s.p.printf("%s", IsLenZero(b.Varname())) | ||
case Float32, Float64, Complex64, Complex128, Uint, Uint8, Uint16, Uint32, Uint64, Byte, Int, Int8, Int16, Int32, Int64: | ||
s.p.printf("%s", IsEmptyNumber(b.Varname())) | ||
case Bool: | ||
s.p.printf("%s", IsEmptyBool(b.Varname())) | ||
case Time: // time.Time | ||
s.p.printf("%s", IsEmptyTime(b.Varname())) | ||
case Intf: // interface{} | ||
// assume, for now, never empty. rarely makes sense to serialize these. | ||
fallthrough | ||
default: | ||
s.p.print("false\n") | ||
} | ||
} | ||
|
||
func IsEmptyNumber(f string) string { | ||
return fmt.Sprintf("(%s == 0) // number, omitempty\n", | ||
f) | ||
} | ||
|
||
func IsLenZero(f string) string { | ||
return fmt.Sprintf("(len(%s) == 0) // string, omitempty\n", | ||
f) | ||
} | ||
|
||
func IsEmptyBool(f string) string { | ||
return fmt.Sprintf("(!%s) // bool, omitempty\n", | ||
f) | ||
} | ||
|
||
func IsEmptyTime(f string) string { | ||
return fmt.Sprintf("(%s.IsZero()) // time.Time, omitempty\n", | ||
f) | ||
} |
Oops, something went wrong.