-
Notifications
You must be signed in to change notification settings - Fork 2
Using the Code Generator
The msgp
code generator takes Go code as input and creates files with more Go code as output. The msgp
command takes the type definitions in a particular Go source file and outputs a number of methods for that type in order to serialize it to or from MessagePack.
By default, the generator generates implementations for all of the following interfaces:
msgp.Marshaler
msgp.Unmarshaler
msgp.Sizer
msgp.Decoder
msgp.Encoder
Additionally, the generator will generate tests and benchmarks for the implemented methods. You can turn the generation of particular method sets and tests on and off with flags passed to the generator.
If you want to run the generator with the default options, all you need to include in your source file is one commented line:
//go:generate msgp
The following flags are supported:
-
-o
- output file name (default is{input}_gen.go
) -
-src
- input file name or directory (default is$GOFILE
set by thego generate
command) -
-io
- satisfy themsgp.Decoder
andmsgp.Encoder
interfaces (default istrue
) -
-marshal
- satisfy themsgp.Marshaler
andmsgp.Unmarshaler
interfaces (default istrue
) -
-tests
- generate tests and benchmarks (default istrue
)
Provided that you have msgp
and the go generate
tool installed, all you should have to do is run go generate
in the same directory as your source file to invoke the generator.
For example, if you want the output file to be called stuff.go
and you don't want to satisfy the msgp.Decoder
and msgp.Encoder
interfaces or generate tests, you would instead use:
//go:generate msgp -o=stuff.go -io=false -tests=false
If you want to run the generator without using go generate
, you must use the -src
flag. If you wanted to run the generator on the file my_types.go
, then from the source directory you would run (assuming msgp
is installed and in your $PATH):
msgp -src=my_types.go
which would generate my_types_gen.go
and my_types_gen_test.go
.
You can adjust how the code generator generates methods using directives as source code comments. All directives have the form:
//msgp:directive [arg1] [arg2] [arg3]...
There are two kinds of directives: global and pass-specific.
//msgp:ignore Type1 Type2 Type3
The ignore
directive tells the code generator to ignore the types listed.
//msgp:tuple TypeA
type TypeA struct {
Left float64
Right float64
}
The msgp:tuple
directive tells the generator to generate code for the struct so that it is serialized as an array instead of a map. In other words, TypeA{1.0, 2.0}
above would be encoded as
[1.0,2.0]
instead of
{"Left":1.0,"Right":2.0}
For smaller objects, tuple encoding can yield serious performance improvements.
//go:generate msgp
//msgp:shim Enum as:string using:(Enum).String/parseString mode:convert
type Enum byte
const(
A Enum = iota
B
C
D
invalid
)
func (e Enum) String() string {
switch e {
case A:
return "A"
case B:
return "B"
case C:
return "C"
case D:
return "D"
default:
return "<invalid>"
}
}
func parseString(s string) Enum {
switch s {
case "A":
return A
case "B":
return B
case "C":
return C
case "D":
return D
default:
return invalid
}
}
The shim
directive lets you inline a type-conversion function for a user-defined type in order to have it encode and decode differently than the default for its concrete type. In the example above, we're using the shim
directive to translate a const-iota
block into strings for encoding and decoding. Note that the as:
argument must take a "base" type (a built-in, []byte
, interface{}
, msgp.Extension
or a type already processed by the code generator.) The mode can be either "convert" or "cast" and defaults to "cast" if not set.
A pass-specific directive operates on one particular code generation pass. They have the form:
//msgp:passname directives [arg1] [arg2] ...
The valid pass names are:
encode
decode
marshal
unmarshal
size
test
The ignore
directive can be applied to a particular combination of pass and type when invoked like:
//msgp:encode ignore Type1 Type2...
Methods that are ignored also do not produce test cases. (The code generator is aware of the dependency.)
Ignore can be particularly useful when you don't want the code generator to clobber an existing manually-written implementation of one of the methods.
In any directive, along with the concrete names of types you can list regular expressions to match types. Simply prefix reg=
before the regular expression to match, or prefix reg!=
before the regular expression that the type names should not match. For example, this set of directives:
//go:generate msgp
//msgp:encode ignore reg=User
//msgp:unmarshal ignore reg!=^Contents
indicate that types that include User
in the name will not get an EncodeMsg
method, and only types that begin with the string Contents
will get an UnmarshalMsg
method.
You can use concrete type names along with regexp matching:
//msgp:encode ignore reg=Req AnotherType
Using a flag like -io
or -marshal
may not be enough for you if, for example, in general you don't want methods of a particular kind but do want it for only certain types.
The regular expression syntax is described here: https://godoc.org/regexp