"strconv"
"strings"
- "git.fd.io/govpp.git/internal/version"
+ "git.fd.io/govpp.git/version"
)
// library dependencies
fieldUnionData = "XXX_UnionData" // name for the union data field
)
+// option keys
+const (
+ msgStatus = "status"
+ msgDeprecated = "deprecated"
+ msgInProgress = "in_progress"
+)
+
+// generated option messages
+const (
+ deprecatedMsg = "the message will be removed in the future versions"
+ inProgressMsg = "the message form may change in the future versions"
+)
+
func GenerateAPI(gen *Generator, file *File) *GenFile {
logf("----------------------------")
logf(" Generate API - %s", file.Desc.Name)
g.P("// versions:")
g.P("// binapi-generator: ", version.Version())
g.P("// VPP: ", g.gen.vppVersion)
- g.P("// source: ", g.file.Desc.Path)
+ if !gen.opts.NoSourcePathInfo {
+ g.P("// source: ", g.file.Desc.Path)
+ }
}
g.P()
g.P("const _ = ", govppApiPkg.Ident("GoVppAPIPackageIsVersion"), generatedCodeVersion)
g.P()
- if !file.isTypesFile() {
- g.P("const (")
- g.P(apiName, " = ", strconv.Quote(g.file.Desc.Name))
- g.P(apiVersion, " = ", strconv.Quote(g.file.Version))
- g.P(apiCrc, " = ", g.file.Desc.CRC)
- g.P(")")
- g.P()
- }
+ g.P("const (")
+ g.P(apiName, " = ", strconv.Quote(g.file.Desc.Name))
+ g.P(apiVersion, " = ", strconv.Quote(g.file.Version))
+ g.P(apiCrc, " = ", g.file.Desc.CRC)
+ g.P(")")
+ g.P()
for _, enum := range g.file.Enums {
genEnum(g, enum)
g.P("// ", goName, " defines ", objKind, " '", vppName, "'.")
}
+func genTypeOptionComment(g *GenFile, options map[string]string) {
+ // all messages for API versions < 1.0.0 are in_progress by default
+ if msg, ok := options[msgInProgress]; ok || options[msgStatus] == msgInProgress ||
+ len(g.file.Version) > 1 && g.file.Version[0:2] == "0." {
+ if msg == "" {
+ msg = inProgressMsg
+ }
+ g.P("// InProgress: ", msg)
+ }
+ if msg, ok := options[msgDeprecated]; ok || options[msgStatus] == msgDeprecated {
+ if msg == "" {
+ msg = deprecatedMsg
+ }
+ g.P("// Deprecated: ", msg)
+ }
+}
+
func genEnum(g *GenFile, enum *Enum) {
logf("gen ENUM %s (%s) - %d entries", enum.GoName, enum.Name, len(enum.Entries))
g.P(")")
g.P()
- if isEnumFlag(enum) {
+ if enum.IsFlag || isEnumFlag(enum) {
size := BaseTypeSizes[enum.Type] * 8
g.P("func (x ", enum.GoName, ") String() string {")
g.P(" s, ok := ", enum.GoName, "_name[", gotype, "(x)]")
// generate alias-specific methods
switch alias.Name {
case "ip4_address":
- generateIPConversion(g, alias.GoName, 4)
+ genIPConversion(g, alias.GoName, 4)
case "ip6_address":
- generateIPConversion(g, alias.GoName, 16)
+ genIPConversion(g, alias.GoName, 16)
case "address_with_prefix":
- generateAddressWithPrefixConversion(g, alias.GoName)
+ genAddressWithPrefixConversion(g, alias.GoName)
case "mac_address":
- generateMacAddressConversion(g, alias.GoName)
+ genMacAddressConversion(g, alias.GoName)
+ case "timestamp":
+ genTimestampConversion(g, alias.GoName)
}
}
} else {
g.P("type ", typ.GoName, " struct {")
for i := range typ.Fields {
- generateField(g, typ.Fields, i)
+ genField(g, typ.Fields, i)
}
g.P("}")
}
// generate type-specific methods
switch typ.Name {
case "address":
- generateAddressConversion(g, typ.GoName)
+ genAddressConversion(g, typ.GoName)
case "prefix":
- generatePrefixConversion(g, typ.GoName)
+ genPrefixConversion(g, typ.GoName)
case "ip4_prefix":
- generateIPPrefixConversion(g, typ.GoName, 4)
+ genIPPrefixConversion(g, typ.GoName, 4)
case "ip6_prefix":
- generateIPPrefixConversion(g, typ.GoName, 6)
+ genIPPrefixConversion(g, typ.GoName, 6)
}
}
g.P("type ", union.GoName, " struct {")
+ // generate field comments
+ g.P("// ", union.GoName, " can be one of:")
for _, field := range union.Fields {
- g.P("// ", field.GoName, " *", getFieldType(g, field))
+ g.P("// - ", field.GoName, " *", getFieldType(g, field))
}
// generate data field
// generate methods for fields
for _, field := range union.Fields {
- genUnionFieldMethods(g, union.GoName, field)
+ genUnionField(g, union, field)
}
g.P()
}
-func genUnionFieldMethods(g *GenFile, structName string, field *Field) {
- getterStruct := fieldGoType(g, field)
+func genUnionField(g *GenFile, union *Union, field *Field) {
+ fieldType := fieldGoType(g, field)
+ constructorName := union.GoName + field.GoName
// Constructor
- g.P("func ", structName, field.GoName, "(a ", getterStruct, ") (u ", structName, ") {")
+ g.P("func ", constructorName, "(a ", fieldType, ") (u ", union.GoName, ") {")
g.P(" u.Set", field.GoName, "(a)")
g.P(" return")
g.P("}")
// Setter
- g.P("func (u *", structName, ") Set", field.GoName, "(a ", getterStruct, ") {")
- g.P(" var buf = ", govppCodecPkg.Ident("NewBuffer"), "(u.", fieldUnionData, "[:])")
+ g.P("func (u *", union.GoName, ") Set", field.GoName, "(a ", fieldType, ") {")
+ g.P(" buf := ", govppCodecPkg.Ident("NewBuffer"), "(u.", fieldUnionData, "[:])")
encodeField(g, field, "a", func(name string) string {
return "a." + name
}, 0)
g.P("}")
// Getter
- g.P("func (u *", structName, ") Get", field.GoName, "() (a ", getterStruct, ") {")
- g.P(" var buf = ", govppCodecPkg.Ident("NewBuffer"), "(u.", fieldUnionData, "[:])")
+ g.P("func (u *", union.GoName, ") Get", field.GoName, "() (a ", fieldType, ") {")
+ g.P(" buf := ", govppCodecPkg.Ident("NewBuffer"), "(u.", fieldUnionData, "[:])")
decodeField(g, field, "a", func(name string) string {
return "a." + name
}, 0)
g.P(" return")
g.P("}")
+
g.P()
}
-func generateField(g *GenFile, fields []*Field, i int) {
+func withSuffix(s string, suffix string) string {
+ if strings.HasSuffix(s, suffix) {
+ return s
+ }
+ return s + suffix
+}
+
+func genField(g *GenFile, fields []*Field, i int) {
field := fields[i]
logf(" gen FIELD[%d] %s (%s) - type: %q (array: %v/%v)", i, field.GoName, field.Name, field.Type, field.Array, field.Length)
gotype := getFieldType(g, field)
tags := structTags{
- "binapi": fieldTagJSON(field),
- "json": fieldTagBinapi(field),
+ "binapi": fieldTagBinapi(field),
+ "json": fieldTagJson(field),
}
g.P(field.GoName, " ", gotype, tags)
}
-func fieldTagBinapi(field *Field) string {
+func fieldTagJson(field *Field) string {
if field.FieldSizeOf != nil {
return "-"
}
return fmt.Sprintf("%s,omitempty", field.Name)
}
-func fieldTagJSON(field *Field) string {
+func fieldTagBinapi(field *Field) string {
typ := fromApiType(field.Type)
if field.Array {
if field.Length > 0 {
tag = append(tag, fmt.Sprintf("limit=%s", limit))
}
if def, ok := field.Meta["default"]; ok && def != nil {
- actual := fieldActualType(field)
- if t, ok := BaseTypesGo[actual]; ok {
- switch t {
- case I8, I16, I32, I64:
- def = int(def.(float64))
- case U8, U16, U32, U64:
- def = uint(def.(float64))
- case F64:
- def = def.(float64)
- }
+ switch fieldActualType(field) {
+ case I8, I16, I32, I64:
+ def = int(def.(float64))
+ case U8, U16, U32, U64:
+ def = uint(def.(float64))
+ case F64:
+ def = def.(float64)
}
- tag = append(tag, fmt.Sprintf("default=%s", def))
+ tag = append(tag, fmt.Sprintf("default=%v", def))
}
return strings.Join(tag, ",")
}
logf("gen MESSAGE %s (%s) - %d fields", msg.GoName, msg.Name, len(msg.Fields))
genTypeComment(g, msg.GoIdent.GoName, msg.Name, "message")
+ genTypeOptionComment(g, msg.Options)
// generate message definition
if len(msg.Fields) == 0 {
} else {
g.P("type ", msg.GoIdent, " struct {")
for i := range msg.Fields {
- generateField(g, msg.Fields, i)
+ genField(g, msg.Fields, i)
}
g.P("}")
}
g.P()
- generateMessageMethods(g, msg)
+ genMessageMethods(g, msg)
// encoding methods
- generateMessageSize(g, msg.GoIdent.GoName, msg.Fields)
- generateMessageMarshal(g, msg.GoIdent.GoName, msg.Fields)
- generateMessageUnmarshal(g, msg.GoIdent.GoName, msg.Fields)
+ genMessageSize(g, msg.GoIdent.GoName, msg.Fields)
+ genMessageMarshal(g, msg.GoIdent.GoName, msg.Fields)
+ genMessageUnmarshal(g, msg.GoIdent.GoName, msg.Fields)
g.P()
}
-func generateMessageMethods(g *GenFile, msg *Message) {
+func genMessageMethods(g *GenFile, msg *Message) {
// Reset method
g.P("func (m *", msg.GoIdent.GoName, ") Reset() { *m = ", msg.GoIdent.GoName, "{} }")
g.P()
}
+
+func apiMsgType(t msgType) GoIdent {
+ switch t {
+ case msgTypeRequest:
+ return govppApiPkg.Ident("RequestMessage")
+ case msgTypeReply:
+ return govppApiPkg.Ident("ReplyMessage")
+ case msgTypeEvent:
+ return govppApiPkg.Ident("EventMessage")
+ default:
+ return govppApiPkg.Ident("OtherMessage")
+ }
+}