-
Notifications
You must be signed in to change notification settings - Fork 199
Preprocessor Directives
You can make tweaks to how the code generator generates methods using directives in your source code comments. All directives take the form
//msgp:directive [arg1] [arg2] [arg3]...much like the gc compiler directives.
There are two flavors of directives: global and pass-specific.
//msgp:ignore Type1 Type2 Type3Ignore tells the code generator not to generate methods for the list of types supplied.
//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.
//msgp:shim Enum as:string using:(Enum).String/parseString
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.)
Example shimming an external types to JSON:
//msgp:shim host.InfoStat as:[]byte using:asJSON/parseJSONInto[host.InfoStat]
//msgp:shim host.TemperatureStat as:[]byte using:asJSON/parseJSONInto[host.TemperatureStat]
func asJSON(v any) []byte {
b, _ := json.Marshal(v)
return b
}
func parseJSONInto[T any](b []byte) T {
var t T
json.Unmarshal(b, &t)
return t
}
Note there is no error checking on shimmed types.
the replace directive makes it easier to serialize foreign types.
Example usage with github.com/google/uuid
package main
import "github.com/google/uuid"
//go:generate msgp
//msgp:replace uuid.UUID with:UUID
type UUID [16]byte
// Or like that
//msgp:replace uuid.UUID with:[16]byte
type User struct {
ID uuid.UUID
}This can also be used to replace serialization of external types with internal types.
For example //msgp:replace cpu.TimesStat with:cpuTimesStat will replace an external type cpu.TimesStat with a
local cpuTimesStat, which should be a copy of the external struct, that has generated functions.
A pass-specific directive operates on one particular code generation pass. They take the form
//msgp:passname directives [arg1] [arg2] ...The valid pass names are as follows:
encodedecodemarshalunmarshalsizetest
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.