aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorOndrej Fabry <ofabry@cisco.com>2019-02-08 01:16:32 +0100
committerOndrej Fabry <ofabry@cisco.com>2019-02-08 01:16:32 +0100
commitfa21c9d726ebb807895a8571af9a16dab5cd8d6e (patch)
tree4597d483f90e374e89f3923324b531a56217a0f9 /cmd
parent8ba70a7b13950593aab9863246f830eda450f06b (diff)
Generator improvements and cleanup
- generator now supports include-comments flag (as opt-in) - minor code cleanup in binapi-generator - remove obsolete unit tests - flatten examples from examples/cmd folder - introduce constant for checking compatibility in future versions Change-Id: I3545f2ba4b869a3b51d6d0de7e742f3f1e1be392 Signed-off-by: Ondrej Fabry <ofabry@cisco.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/binapi-generator/definitions.go42
-rw-r--r--cmd/binapi-generator/generate.go61
-rw-r--r--cmd/binapi-generator/main.go38
-rw-r--r--cmd/binapi-generator/objects.go52
-rw-r--r--cmd/binapi-generator/parse.go218
-rw-r--r--cmd/binapi-generator/types.go129
6 files changed, 292 insertions, 248 deletions
diff --git a/cmd/binapi-generator/definitions.go b/cmd/binapi-generator/definitions.go
index 3ad782f..9bf9e53 100644
--- a/cmd/binapi-generator/definitions.go
+++ b/cmd/binapi-generator/definitions.go
@@ -15,43 +15,10 @@
package main
import (
- "strconv"
"strings"
"unicode"
)
-func getBinapiTypeSize(binapiType string) int {
- if _, ok := binapiTypes[binapiType]; ok {
- b, err := strconv.Atoi(strings.TrimLeft(binapiType, "uif"))
- if err == nil {
- return b / 8
- }
- }
- return -1
-}
-
-// binapiTypes is a set of types used VPP binary API for translation to Go types
-var binapiTypes = map[string]string{
- "u8": "uint8",
- "i8": "int8",
- "u16": "uint16",
- "i16": "int16",
- "u32": "uint32",
- "i32": "int32",
- "u64": "uint64",
- "i64": "int64",
- "f64": "float64",
-}
-
-func usesInitialism(s string) string {
- if u := strings.ToUpper(s); commonInitialisms[u] {
- return u
- } else if su, ok := specialInitialisms[u]; ok {
- return su
- }
- return ""
-}
-
// commonInitialisms is a set of common initialisms that need to stay in upper case.
var commonInitialisms = map[string]bool{
"ACL": true,
@@ -105,6 +72,15 @@ var specialInitialisms = map[string]string{
//"IPV6": "IPv6",
}
+func usesInitialism(s string) string {
+ if u := strings.ToUpper(s); commonInitialisms[u] {
+ return u
+ } else if su, ok := specialInitialisms[u]; ok {
+ return su
+ }
+ return ""
+}
+
// camelCaseName returns correct name identifier (camelCase).
func camelCaseName(name string) (should string) {
name = strings.Title(name)
diff --git a/cmd/binapi-generator/generate.go b/cmd/binapi-generator/generate.go
index 48c3a41..f2da08a 100644
--- a/cmd/binapi-generator/generate.go
+++ b/cmd/binapi-generator/generate.go
@@ -25,9 +25,11 @@ import (
)
const (
+ inputFileExt = ".api.json" // file extension of the VPP API files
+ outputFileExt = ".ba.go" // file extension of the Go generated files
+
govppApiImportPath = "git.fd.io/govpp.git/api" // import path of the govpp API package
- inputFileExt = ".api.json" // file extension of the VPP binary API files
- outputFileExt = ".ba.go" // file extension of the Go generated files
+ constAPIVersionCrc = "APIVersionCrc" // name for the API version CRC constant
)
// context is a structure storing data for code generation
@@ -37,6 +39,9 @@ type context struct {
inputData []byte // contents of the input file
+ includeAPIVersionCrc bool // include constant with API version CRC string
+ includeComments bool // include parts of original source in comments
+
moduleName string // name of the source VPP module
packageName string // name of the Go package being generated
@@ -83,10 +88,9 @@ func generatePackage(ctx *context, w *bufio.Writer) error {
generateHeader(ctx, w)
generateImports(ctx, w)
- if *includeAPIVer {
- const APIVerConstName = "VlAPIVersion"
- fmt.Fprintf(w, "// %s represents version of the binary API module.\n", APIVerConstName)
- fmt.Fprintf(w, "const %s = %v\n", APIVerConstName, ctx.packageData.APIVersion)
+ if ctx.includeAPIVersionCrc {
+ fmt.Fprintf(w, "// %s defines API version CRC of the VPP binary API module.\n", constAPIVersionCrc)
+ fmt.Fprintf(w, "const %s = %v\n", constAPIVersionCrc, ctx.packageData.APIVersion)
fmt.Fprintln(w)
}
@@ -194,9 +198,9 @@ func generateHeader(ctx *context, w io.Writer) {
// generateImports writes generated package imports into w
func generateImports(ctx *context, w io.Writer) {
- fmt.Fprintf(w, "import \"%s\"\n", govppApiImportPath)
- fmt.Fprintf(w, "import \"%s\"\n", "github.com/lunixbochs/struc")
- fmt.Fprintf(w, "import \"%s\"\n", "bytes")
+ fmt.Fprintf(w, "import api \"%s\"\n", govppApiImportPath)
+ fmt.Fprintf(w, "import struc \"%s\"\n", "github.com/lunixbochs/struc")
+ fmt.Fprintf(w, "import bytes \"%s\"\n", "bytes")
fmt.Fprintln(w)
fmt.Fprintf(w, "// Reference imports to suppress errors if they are not otherwise used.\n")
@@ -204,6 +208,13 @@ func generateImports(ctx *context, w io.Writer) {
fmt.Fprintf(w, "var _ = struc.Pack\n")
fmt.Fprintf(w, "var _ = bytes.NewBuffer\n")
fmt.Fprintln(w)
+
+ /*fmt.Fprintln(w, "// This is a compile-time assertion to ensure that this generated file")
+ fmt.Fprintln(w, "// is compatible with the GoVPP api package it is being compiled against.")
+ fmt.Fprintln(w, "// A compilation error at this line likely means your copy of the")
+ fmt.Fprintln(w, "// GoVPP api package needs to be updated.")
+ fmt.Fprintln(w, "const _ = api.GoVppAPIPackageIsVersion1 // please upgrade the GoVPP api package")
+ fmt.Fprintln(w)*/
}
// generateComment writes generated comment for the object into w
@@ -214,6 +225,10 @@ func generateComment(ctx *context, w io.Writer, goName string, vppName string, o
fmt.Fprintf(w, "// %s represents VPP binary API %s '%s':\n", goName, objKind, vppName)
}
+ if !ctx.includeComments {
+ return
+ }
+
var isNotSpace = func(r rune) bool {
return !unicode.IsSpace(r)
}
@@ -271,7 +286,7 @@ func generateServices(ctx *context, w *bufio.Writer, services []Service) {
// generate interface
fmt.Fprintf(w, "type %s interface {\n", "Services")
- for _, svc := range ctx.packageData.Services {
+ for _, svc := range services {
generateService(ctx, w, &svc)
}
fmt.Fprintln(w, "}")
@@ -284,7 +299,14 @@ func generateService(ctx *context, w io.Writer, svc *Service) {
reqTyp := camelCaseName(svc.RequestType)
// method name is same as parameter type name by default
- method := svc.MethodName()
+ method := reqTyp
+ if svc.Stream {
+ // use Dump as prefix instead of suffix for stream services
+ if m := strings.TrimSuffix(method, "Dump"); method != m {
+ method = "Dump" + m
+ }
+ }
+
params := fmt.Sprintf("*%s", reqTyp)
returns := "error"
if replyType := camelCaseName(svc.ReplyType); replyType != "" {
@@ -450,7 +472,7 @@ func generateType(ctx *context, w io.Writer, typ *Type) {
for i, field := range typ.Fields {
// skip internal fields
switch strings.ToLower(field.Name) {
- case "crc", "_vl_msg_id":
+ case crcField, msgIdField:
continue
}
@@ -488,17 +510,17 @@ func generateMessage(ctx *context, w io.Writer, msg *Message) {
n := 0
for i, field := range msg.Fields {
if i == 1 {
- if field.Name == "client_index" {
+ if field.Name == clientIndexField {
// "client_index" as the second member,
// this might be an event message or a request
msgType = eventMessage
wasClientIndex = true
- } else if field.Name == "context" {
+ } else if field.Name == contextField {
// reply needs "context" as the second member
msgType = replyMessage
}
} else if i == 2 {
- if wasClientIndex && field.Name == "context" {
+ if wasClientIndex && field.Name == contextField {
// request needs "client_index" as the second member
// and "context" as the third member
msgType = requestMessage
@@ -507,9 +529,9 @@ func generateMessage(ctx *context, w io.Writer, msg *Message) {
// skip internal fields
switch strings.ToLower(field.Name) {
- case "crc", "_vl_msg_id":
+ case crcField, msgIdField:
continue
- case "client_index", "context":
+ case clientIndexField, contextField:
if n == 0 {
continue
}
@@ -550,9 +572,10 @@ func generateField(ctx *context, w io.Writer, fields []Field, i int) {
}
dataType := convertToGoType(ctx, field.Type)
-
fieldType := dataType
- if field.IsArray() {
+
+ // check if it is array
+ if field.Length > 0 || field.SizeFrom != "" {
if dataType == "uint8" {
dataType = "byte"
}
diff --git a/cmd/binapi-generator/main.go b/cmd/binapi-generator/main.go
index b73a699..b3a131c 100644
--- a/cmd/binapi-generator/main.go
+++ b/cmd/binapi-generator/main.go
@@ -30,27 +30,15 @@ import (
)
var (
- inputFile = flag.String("input-file", "", "Input JSON file.")
- inputDir = flag.String("input-dir", ".", "Input directory with JSON files.")
+ inputFile = flag.String("input-file", "", "Input file with VPP API in JSON format.")
+ inputDir = flag.String("input-dir", ".", "Input directory with VPP API files in JSON format.")
outputDir = flag.String("output-dir", ".", "Output directory where package folders will be generated.")
- includeAPIVer = flag.Bool("include-apiver", false, "Whether to include VlAPIVersion in generated file.")
- debug = flag.Bool("debug", false, "Turn on debug mode.")
- continueOnError = flag.Bool("continue-onerror", false, "Wheter to continue with next file on error.")
+ includeAPIVer = flag.Bool("include-apiver", false, "Include APIVersion constant for each module.")
+ includeComments = flag.Bool("include-comments", false, "Include JSON API source in comments for each object.")
+ continueOnError = flag.Bool("continue-onerror", false, "Continue with next file on error.")
+ debug = flag.Bool("debug", false, "Enable debug mode.")
)
-func init() {
- flag.Parse()
- if *debug {
- logrus.SetLevel(logrus.DebugLevel)
- }
-}
-
-func logf(f string, v ...interface{}) {
- if *debug {
- logrus.Debugf(f, v...)
- }
-}
-
var log = logrus.Logger{
Level: logrus.InfoLevel,
Formatter: &logrus.TextFormatter{},
@@ -58,6 +46,11 @@ var log = logrus.Logger{
}
func main() {
+ flag.Parse()
+ if *debug {
+ logrus.SetLevel(logrus.DebugLevel)
+ }
+
if *inputFile == "" && *inputDir == "" {
fmt.Fprintln(os.Stderr, "ERROR: input-file or input-dir must be specified")
os.Exit(1)
@@ -112,6 +105,9 @@ func generateFromFile(inputFile, outputDir string) error {
return err
}
+ ctx.includeAPIVersionCrc = *includeAPIVer
+ ctx.includeComments = *includeComments
+
// read input file contents
ctx.inputData, err = readFile(inputFile)
if err != nil {
@@ -182,3 +178,9 @@ func parseJSON(inputData []byte) (*jsongo.JSONNode, error) {
return &root, nil
}
+
+func logf(f string, v ...interface{}) {
+ if *debug {
+ logrus.Debugf(f, v...)
+ }
+}
diff --git a/cmd/binapi-generator/objects.go b/cmd/binapi-generator/objects.go
index 4b424f5..75c7581 100644
--- a/cmd/binapi-generator/objects.go
+++ b/cmd/binapi-generator/objects.go
@@ -1,9 +1,5 @@
package main
-import (
- "strings"
-)
-
// Package represents collection of objects parsed from VPP binary API JSON data
type Package struct {
APIVersion string
@@ -52,6 +48,14 @@ type Type struct {
Fields []Field
}
+// Field represents VPP binary API object field
+type Field struct {
+ Name string
+ Type string
+ Length int
+ SizeFrom string
+}
+
// Union represents VPP binary API union
type Union struct {
Name string
@@ -75,43 +79,3 @@ const (
eventMessage // VPP event message
otherMessage // other VPP message
)
-
-// Field represents VPP binary API object field
-type Field struct {
- Name string
- Type string
- Length int
- SizeFrom string
-}
-
-func (f *Field) IsArray() bool {
- return f.Length > 0 || f.SizeFrom != ""
-}
-
-func (s Service) MethodName() string {
- reqTyp := camelCaseName(s.RequestType)
-
- // method name is same as parameter type name by default
- method := reqTyp
- if s.Stream {
- // use Dump as prefix instead of suffix for stream services
- if m := strings.TrimSuffix(method, "Dump"); method != m {
- method = "Dump" + m
- }
- }
-
- return method
-}
-
-func (s Service) IsDumpService() bool {
- return s.Stream
-}
-
-func (s Service) IsEventService() bool {
- return len(s.Events) > 0
-}
-
-func (s Service) IsRequestService() bool {
- // some binapi messages might have `null` reply (for example: memclnt)
- return s.ReplyType != "" && s.ReplyType != "null" // not null
-}
diff --git a/cmd/binapi-generator/parse.go b/cmd/binapi-generator/parse.go
index 07abebd..4138ac6 100644
--- a/cmd/binapi-generator/parse.go
+++ b/cmd/binapi-generator/parse.go
@@ -23,26 +23,62 @@ import (
"github.com/bennyscetbun/jsongo"
)
+// top level objects
+const (
+ objTypes = "types"
+ objMessages = "messages"
+ objUnions = "unions"
+ objEnums = "enums"
+ objServices = "services"
+ objAliases = "aliases"
+ vlAPIVersion = "vl_api_version"
+)
+
+// various object fields
+const (
+ crcField = "crc"
+ msgIdField = "_vl_msg_id"
+
+ clientIndexField = "client_index"
+ contextField = "context"
+
+ aliasLengthField = "length"
+ aliasTypeField = "type"
+
+ replyField = "reply"
+ streamField = "stream"
+ eventsField = "events"
+)
+
+// service name parts
+const (
+ serviceEventPrefix = "want_"
+ serviceDumpSuffix = "_dump"
+ serviceDetailsSuffix = "_details"
+ serviceReplySuffix = "_reply"
+ serviceNoReply = "null"
+)
+
// parsePackage parses provided JSON data into objects prepared for code generation
func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
- logf(" %s contains: %d services, %d messages, %d types, %d enums, %d unions, %d aliases (version: %s)",
+ logf(" %s (version: %s) contains: %d services, %d messages, %d types, %d enums, %d unions, %d aliases",
ctx.packageName,
- jsonRoot.Map("services").Len(),
- jsonRoot.Map("messages").Len(),
- jsonRoot.Map("types").Len(),
- jsonRoot.Map("enums").Len(),
- jsonRoot.Map("unions").Len(),
- jsonRoot.Map("aliases").Len(),
- jsonRoot.Map("vl_api_version").Get(),
+ jsonRoot.Map(vlAPIVersion).Get(),
+ jsonRoot.Map(objServices).Len(),
+ jsonRoot.Map(objMessages).Len(),
+ jsonRoot.Map(objTypes).Len(),
+ jsonRoot.Map(objEnums).Len(),
+ jsonRoot.Map(objUnions).Len(),
+ jsonRoot.Map(objAliases).Len(),
)
pkg := Package{
- APIVersion: jsonRoot.Map("vl_api_version").Get().(string),
+ APIVersion: jsonRoot.Map(vlAPIVersion).Get().(string),
RefMap: make(map[string]string),
}
// parse enums
- enums := jsonRoot.Map("enums")
+ enums := jsonRoot.Map(objEnums)
pkg.Enums = make([]Enum, enums.Len())
for i := 0; i < enums.Len(); i++ {
enumNode := enums.At(i)
@@ -60,7 +96,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse aliases
- aliases := jsonRoot.Map("aliases")
+ aliases := jsonRoot.Map(objAliases)
if aliases.GetType() == jsongo.TypeMap {
pkg.Aliases = make([]Alias, aliases.Len())
for i, key := range aliases.GetKeys() {
@@ -80,7 +116,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse types
- types := jsonRoot.Map("types")
+ types := jsonRoot.Map(objTypes)
pkg.Types = make([]Type, types.Len())
for i := 0; i < types.Len(); i++ {
typNode := types.At(i)
@@ -98,7 +134,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse unions
- unions := jsonRoot.Map("unions")
+ unions := jsonRoot.Map(objUnions)
pkg.Unions = make([]Union, unions.Len())
for i := 0; i < unions.Len(); i++ {
unionNode := unions.At(i)
@@ -116,7 +152,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse messages
- messages := jsonRoot.Map("messages")
+ messages := jsonRoot.Map(objMessages)
pkg.Messages = make([]Message, messages.Len())
for i := 0; i < messages.Len(); i++ {
msgNode := messages.At(i)
@@ -133,7 +169,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse services
- services := jsonRoot.Map("services")
+ services := jsonRoot.Map(objServices)
if services.GetType() == jsongo.TypeMap {
pkg.Services = make([]Service, services.Len())
for i, key := range services.GetKeys() {
@@ -255,7 +291,7 @@ func parseUnion(ctx *context, unionNode *jsongo.JSONNode) (*Union, error) {
if !ok {
return nil, fmt.Errorf("union name is %T, not a string", unionNode.At(0).Get())
}
- unionCRC, ok := unionNode.At(unionNode.Len() - 1).At("crc").Get().(string)
+ unionCRC, ok := unionNode.At(unionNode.Len() - 1).At(crcField).Get().(string)
if !ok {
return nil, fmt.Errorf("union crc invalid or missing")
}
@@ -292,7 +328,7 @@ func parseType(ctx *context, typeNode *jsongo.JSONNode) (*Type, error) {
if !ok {
return nil, fmt.Errorf("type name is %T, not a string", typeNode.At(0).Get())
}
- typeCRC, ok := typeNode.At(typeNode.Len() - 1).At("crc").Get().(string)
+ typeCRC, ok := typeNode.At(typeNode.Len() - 1).At(crcField).Get().(string)
if !ok {
return nil, fmt.Errorf("type crc invalid or missing")
}
@@ -319,14 +355,9 @@ func parseType(ctx *context, typeNode *jsongo.JSONNode) (*Type, error) {
return &typ, nil
}
-const (
- aliasesLength = "length"
- aliasesType = "type"
-)
-
// parseAlias parses VPP binary API alias object from JSON node
func parseAlias(ctx *context, aliasName string, aliasNode *jsongo.JSONNode) (*Alias, error) {
- if aliasNode.Len() == 0 || aliasNode.At(aliasesType).GetType() != jsongo.TypeValue {
+ if aliasNode.Len() == 0 || aliasNode.At(aliasTypeField).GetType() != jsongo.TypeValue {
return nil, errors.New("invalid JSON for alias specified")
}
@@ -334,7 +365,7 @@ func parseAlias(ctx *context, aliasName string, aliasNode *jsongo.JSONNode) (*Al
Name: aliasName,
}
- if typeNode := aliasNode.At(aliasesType); typeNode.GetType() == jsongo.TypeValue {
+ if typeNode := aliasNode.At(aliasTypeField); typeNode.GetType() == jsongo.TypeValue {
typ, ok := typeNode.Get().(string)
if !ok {
return nil, fmt.Errorf("alias type is %T, not a string", typeNode.Get())
@@ -344,7 +375,7 @@ func parseAlias(ctx *context, aliasName string, aliasNode *jsongo.JSONNode) (*Al
}
}
- if lengthNode := aliasNode.At(aliasesLength); lengthNode.GetType() == jsongo.TypeValue {
+ if lengthNode := aliasNode.At(aliasLengthField); lengthNode.GetType() == jsongo.TypeValue {
length, ok := lengthNode.Get().(float64)
if !ok {
return nil, fmt.Errorf("alias length is %T, not a float64", lengthNode.Get())
@@ -365,7 +396,7 @@ func parseMessage(ctx *context, msgNode *jsongo.JSONNode) (*Message, error) {
if !ok {
return nil, fmt.Errorf("message name is %T, not a string", msgNode.At(0).Get())
}
- msgCRC, ok := msgNode.At(msgNode.Len() - 1).At("crc").Get().(string)
+ msgCRC, ok := msgNode.At(msgNode.Len() - 1).At(crcField).Get().(string)
if !ok {
return nil, fmt.Errorf("message crc invalid or missing")
@@ -432,7 +463,7 @@ func parseField(ctx *context, field *jsongo.JSONNode) (*Field, error) {
// parseService parses VPP binary API service object from JSON node
func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Service, error) {
- if svcNode.Len() == 0 || svcNode.At("reply").GetType() != jsongo.TypeValue {
+ if svcNode.Len() == 0 || svcNode.At(replyField).GetType() != jsongo.TypeValue {
return nil, errors.New("invalid JSON for service specified")
}
@@ -441,18 +472,18 @@ func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Serv
RequestType: svcName,
}
- if replyNode := svcNode.At("reply"); replyNode.GetType() == jsongo.TypeValue {
+ if replyNode := svcNode.At(replyField); replyNode.GetType() == jsongo.TypeValue {
reply, ok := replyNode.Get().(string)
if !ok {
return nil, fmt.Errorf("service reply is %T, not a string", replyNode.Get())
}
- if reply != "null" {
+ if reply != serviceNoReply {
svc.ReplyType = reply
}
}
// stream service (dumps)
- if streamNode := svcNode.At("stream"); streamNode.GetType() == jsongo.TypeValue {
+ if streamNode := svcNode.At(streamField); streamNode.GetType() == jsongo.TypeValue {
var ok bool
svc.Stream, ok = streamNode.Get().(bool)
if !ok {
@@ -461,7 +492,7 @@ func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Serv
}
// events service (event subscription)
- if eventsNode := svcNode.At("events"); eventsNode.GetType() == jsongo.TypeArray {
+ if eventsNode := svcNode.At(eventsField); eventsNode.GetType() == jsongo.TypeArray {
for j := 0; j < eventsNode.Len(); j++ {
event := eventsNode.At(j).Get().(string)
svc.Events = append(svc.Events, event)
@@ -469,111 +500,30 @@ func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Serv
}
// validate service
- if svc.IsEventService() {
- if !strings.HasPrefix(svc.RequestType, "want_") {
- log.Debugf("Unusual EVENTS SERVICE: %+v\n"+
- "- events service %q does not have 'want_' prefix in request.",
- svc, svc.Name)
- }
- } else if svc.IsDumpService() {
- if !strings.HasSuffix(svc.RequestType, "_dump") ||
- !strings.HasSuffix(svc.ReplyType, "_details") {
- log.Debugf("Unusual STREAM SERVICE: %+v\n"+
- "- stream service %q does not have '_dump' suffix in request or reply does not have '_details' suffix.",
- svc, svc.Name)
- }
- } else if svc.IsRequestService() {
- if !strings.HasSuffix(svc.ReplyType, "_reply") {
- log.Debugf("Unusual REQUEST SERVICE: %+v\n"+
- "- service %q does not have '_reply' suffix in reply.",
- svc, svc.Name)
+ if len(svc.Events) > 0 {
+ // EVENT service
+ if !strings.HasPrefix(svc.RequestType, serviceEventPrefix) {
+ log.Debugf("unusual EVENTS service: %+v\n"+
+ "- events service %q does not have %q prefix in request.",
+ svc, svc.Name, serviceEventPrefix)
+ }
+ } else if svc.Stream {
+ // STREAM service
+ if !strings.HasSuffix(svc.RequestType, serviceDumpSuffix) ||
+ !strings.HasSuffix(svc.ReplyType, serviceDetailsSuffix) {
+ log.Debugf("unusual STREAM service: %+v\n"+
+ "- stream service %q does not have %q suffix in request or reply does not have %q suffix.",
+ svc, svc.Name, serviceDumpSuffix, serviceDetailsSuffix)
+ }
+ } else if svc.ReplyType != "" && svc.ReplyType != serviceNoReply {
+ // REQUEST service
+ // some messages might have `null` reply (for example: memclnt)
+ if !strings.HasSuffix(svc.ReplyType, serviceReplySuffix) {
+ log.Debugf("unusual REQUEST service: %+v\n"+
+ "- service %q does not have %q suffix in reply.",
+ svc, svc.Name, serviceReplySuffix)
}
}
return &svc, nil
}
-
-// toApiType returns name that is used as type reference in VPP binary API
-func toApiType(name string) string {
- return fmt.Sprintf("vl_api_%s_t", name)
-}
-
-// convertToGoType translates the VPP binary API type into Go type
-func convertToGoType(ctx *context, binapiType string) (typ string) {
- if t, ok := binapiTypes[binapiType]; ok {
- // basic types
- typ = t
- } else if r, ok := ctx.packageData.RefMap[binapiType]; ok {
- // specific types (enums/types/unions)
- typ = camelCaseName(r)
- } else {
- switch binapiType {
- case "bool", "string":
- typ = binapiType
- default:
- // fallback type
- log.Warnf("found unknown VPP binary API type %q, using byte", binapiType)
- typ = "byte"
- }
- }
- return typ
-}
-
-func getSizeOfType(typ *Type) (size int) {
- for _, field := range typ.Fields {
- size += getSizeOfBinapiTypeLength(field.Type, field.Length)
- }
- return size
-}
-
-func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
- if n := getBinapiTypeSize(typ); n > 0 {
- if length > 0 {
- return n * length
- } else {
- return n
- }
- }
- return
-}
-
-func getTypeByRef(ctx *context, ref string) *Type {
- for _, typ := range ctx.packageData.Types {
- if ref == toApiType(typ.Name) {
- return &typ
- }
- }
- return nil
-}
-
-func getAliasByRef(ctx *context, ref string) *Alias {
- for _, alias := range ctx.packageData.Aliases {
- if ref == toApiType(alias.Name) {
- return &alias
- }
- }
- return nil
-}
-
-func getUnionSize(ctx *context, union *Union) (maxSize int) {
- for _, field := range union.Fields {
- typ := getTypeByRef(ctx, field.Type)
- if typ != nil {
- if size := getSizeOfType(typ); size > maxSize {
- maxSize = size
- }
- continue
- }
- alias := getAliasByRef(ctx, field.Type)
- if alias != nil {
- if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
- maxSize = size
- }
- continue
- } else {
- logf("no type or alias found for union %s field type %q", union.Name, field.Type)
- continue
- }
- }
- return
-}
diff --git a/cmd/binapi-generator/types.go b/cmd/binapi-generator/types.go
new file mode 100644
index 0000000..3aa9819
--- /dev/null
+++ b/cmd/binapi-generator/types.go
@@ -0,0 +1,129 @@
+// Copyright (c) 2019 Cisco and/or its affiliates.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// toApiType returns name that is used as type reference in VPP binary API
+func toApiType(name string) string {
+ return fmt.Sprintf("vl_api_%s_t", name)
+}
+
+// binapiTypes is a set of types used VPP binary API for translation to Go types
+var binapiTypes = map[string]string{
+ "u8": "uint8",
+ "i8": "int8",
+ "u16": "uint16",
+ "i16": "int16",
+ "u32": "uint32",
+ "i32": "int32",
+ "u64": "uint64",
+ "i64": "int64",
+ "f64": "float64",
+}
+
+func getBinapiTypeSize(binapiType string) int {
+ if _, ok := binapiTypes[binapiType]; ok {
+ b, err := strconv.Atoi(strings.TrimLeft(binapiType, "uif"))
+ if err == nil {
+ return b / 8
+ }
+ }
+ return -1
+}
+
+// convertToGoType translates the VPP binary API type into Go type
+func convertToGoType(ctx *context, binapiType string) (typ string) {
+ if t, ok := binapiTypes[binapiType]; ok {
+ // basic types
+ typ = t
+ } else if r, ok := ctx.packageData.RefMap[binapiType]; ok {
+ // specific types (enums/types/unions)
+ typ = camelCaseName(r)
+ } else {
+ switch binapiType {
+ case "bool", "string":
+ typ = binapiType
+ default:
+ // fallback type
+ log.Warnf("found unknown VPP binary API type %q, using byte", binapiType)
+ typ = "byte"
+ }
+ }
+ return typ
+}
+
+func getSizeOfType(typ *Type) (size int) {
+ for _, field := range typ.Fields {
+ size += getSizeOfBinapiTypeLength(field.Type, field.Length)
+ }
+ return size
+}
+
+func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
+ if n := getBinapiTypeSize(typ); n > 0 {
+ if length > 0 {
+ return n * length
+ } else {
+ return n
+ }
+ }
+ return
+}
+
+func getTypeByRef(ctx *context, ref string) *Type {
+ for _, typ := range ctx.packageData.Types {
+ if ref == toApiType(typ.Name) {
+ return &typ
+ }
+ }
+ return nil
+}
+
+func getAliasByRef(ctx *context, ref string) *Alias {
+ for _, alias := range ctx.packageData.Aliases {
+ if ref == toApiType(alias.Name) {
+ return &alias
+ }
+ }
+ return nil
+}
+
+func getUnionSize(ctx *context, union *Union) (maxSize int) {
+ for _, field := range union.Fields {
+ typ := getTypeByRef(ctx, field.Type)
+ if typ != nil {
+ if size := getSizeOfType(typ); size > maxSize {
+ maxSize = size
+ }
+ continue
+ }
+ alias := getAliasByRef(ctx, field.Type)
+ if alias != nil {
+ if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
+ maxSize = size
+ }
+ continue
+ } else {
+ logf("no type or alias found for union %s field type %q", union.Name, field.Type)
+ continue
+ }
+ }
+ return
+}