1 // Copyright (c) 2020 Cisco and/or its affiliates.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
21 "github.com/sirupsen/logrus"
24 func genMessageSize(g *GenFile, name string, fields []*Field) {
25 g.P("func (m *", name, ") Size() (size int) {")
26 g.P("if m == nil { return 0 }")
28 sizeBaseType := func(typ, name string, length int, sizefrom string) {
32 g.P("size += ", length, " // ", name)
34 g.P("size += 4 + len(", name, ")", " // ", name)
37 var size = BaseTypeSizes[typ]
39 g.P("size += ", size, " * len(", name, ")", " // ", name)
42 g.P("size += ", size, " * ", length, " // ", name)
44 g.P("size += ", size, " // ", name)
51 var sizeFields func(fields []*Field, parentName string)
52 sizeFields = func(fields []*Field, parentName string) {
54 defer func() { lvl-- }()
56 getFieldName := func(name string) string {
57 return fmt.Sprintf("%s.%s", parentName, name)
60 for _, field := range fields {
61 name := getFieldName(field.GoName)
63 var sizeFromName string
64 if field.FieldSizeFrom != nil {
65 sizeFromName = getFieldName(field.FieldSizeFrom.GoName)
68 if _, ok := BaseTypesGo[field.Type]; ok {
69 sizeBaseType(field.Type, name, field.Length, sizeFromName)
74 index := fmt.Sprintf("j%d", lvl)
76 g.P("for ", index, " := 0; ", index, " < ", field.Length, "; ", index, "++ {")
77 } else if field.FieldSizeFrom != nil {
78 g.P("for ", index, " := 0; ", index, " < len(", name, "); ", index, "++ {")
80 if field.Length == 0 || field.SizeFrom != "" {
81 char := fmt.Sprintf("s%d", lvl)
82 g.P("var ", char, " ", fieldGoType(g, field))
84 g.P("if ", index, " < len(", name, ") { ", char, " = ", name, "[", index, "] }")
87 name = fmt.Sprintf("%s[%s]", name, index)
92 case field.TypeEnum != nil:
93 enum := field.TypeEnum
94 if _, ok := BaseTypesGo[enum.Type]; ok {
95 sizeBaseType(enum.Type, name, 0, "")
97 logrus.Panicf("\t// ??? ENUM %s %s\n", name, enum.Type)
99 case field.TypeAlias != nil:
100 alias := field.TypeAlias
101 if typ := alias.TypeStruct; typ != nil {
102 sizeFields(typ.Fields, name)
104 sizeBaseType(alias.Type, name, alias.Length, "")
106 case field.TypeStruct != nil:
107 typ := field.TypeStruct
108 sizeFields(typ.Fields, name)
109 case field.TypeUnion != nil:
110 union := field.TypeUnion
111 maxSize := getUnionSize(union)
112 sizeBaseType("u8", name, maxSize, "")
114 logrus.Panicf("\t// ??? buf[pos] = %s (%s)\n", name, field.Type)
122 sizeFields(fields, "m")
128 func genMessageMarshal(g *GenFile, name string, fields []*Field) {
129 g.P("func (m *", name, ") Marshal(b []byte) ([]byte, error) {")
131 g.P("b = make([]byte, m.Size())")
133 g.P("buf := ", govppCodecPkg.Ident("NewBuffer"), "(b)")
135 encodeFields(g, fields, "m", 0)
137 g.P("return buf.Bytes(), nil")
141 func encodeFields(g *GenFile, fields []*Field, parentName string, lvl int) {
142 getFieldName := func(name string) string {
143 return fmt.Sprintf("%s.%s", parentName, name)
146 for _, field := range fields {
147 name := getFieldName(field.GoName)
149 encodeField(g, field, name, getFieldName, lvl)
153 func encodeField(g *GenFile, field *Field, name string, getFieldName func(name string) string, lvl int) {
154 if f := field.FieldSizeOf; f != nil {
155 if _, ok := BaseTypesGo[field.Type]; ok {
156 val := fmt.Sprintf("len(%s)", getFieldName(f.GoName))
157 encodeBaseType(g, field.Type, "int", val, 0, "", false)
160 panic(fmt.Sprintf("failed to encode base type of sizefrom field: %s (%s)", field.Name, field.Type))
163 var sizeFromName string
164 if field.FieldSizeFrom != nil {
165 sizeFromName = getFieldName(field.FieldSizeFrom.GoName)
168 if _, ok := BaseTypesGo[field.Type]; ok {
169 encodeBaseType(g, field.Type, fieldGoType(g, field), name, field.Length, sizeFromName, true)
174 index := fmt.Sprintf("j%d", lvl)
175 if field.Length > 0 {
176 g.P("for ", index, " := 0; ", index, " < ", field.Length, "; ", index, "++ {")
177 } else if field.SizeFrom != "" {
178 g.P("for ", index, " := 0; ", index, " < len(", name, "); ", index, "++ {")
180 if field.Length == 0 || field.SizeFrom != "" {
181 char := fmt.Sprintf("v%d", lvl)
182 g.P("var ", char, " ", fieldGoType(g, field), "// ", field.GoName)
183 g.P("if ", index, " < len(", name, ") { ", char, " = ", name, "[", index, "] }")
186 name = fmt.Sprintf("%s[%s]", name, index)
191 case field.TypeEnum != nil:
192 encodeBaseType(g, field.TypeEnum.Type, fieldGoType(g, field), name, 0, "", false)
193 case field.TypeAlias != nil:
194 alias := field.TypeAlias
195 if typ := alias.TypeStruct; typ != nil {
196 encodeFields(g, typ.Fields, name, lvl+1)
198 if alias.Length > 0 {
199 encodeBaseType(g, alias.Type, BaseTypesGo[alias.Type], name, alias.Length, "", false)
201 encodeBaseType(g, alias.Type, fieldGoType(g, field), name, 0, "", false)
204 case field.TypeStruct != nil:
205 encodeFields(g, field.TypeStruct.Fields, name, lvl+1)
206 case field.TypeUnion != nil:
207 maxSize := getUnionSize(field.TypeUnion)
208 g.P("buf.EncodeBytes(", name, ".", fieldUnionData, "[:], ", maxSize, ")")
210 logrus.Panicf("\t// ??? buf[pos] = %s (%s)\n", name, field.Type)
218 func encodeBaseType(g *GenFile, typ, orig, name string, length int, sizefrom string, alloc bool) {
219 isArray := length > 0 || sizefrom != ""
224 g.P("buf.EncodeBytes(", name, ", ", length, ")")
226 g.P("buf.EncodeBytes(", name, "[:], ", length, ")")
229 case I8, I16, U16, I32, U32, I64, U64, F64, BOOL:
230 gotype := BaseTypesGo[typ]
232 g.P("for i := 0; i < ", length, "; i++ {")
233 } else if sizefrom != "" {
234 g.P("for i := 0; i < len(", name, "); i++ {")
237 g.P("var x ", gotype)
238 g.P("if i < len(", name, ") { x = ", gotype, "(", name, "[i]) }")
243 conv := func(s string) string {
244 if gotype, ok := BaseTypesGo[typ]; !ok || gotype != orig {
245 return fmt.Sprintf("%s(%s)", gotype, s)
250 case I8, I16, I32, I64:
251 typsize := BaseTypeSizes[typ]
252 g.P("buf.EncodeInt", typsize*8, "(", conv(name), ")")
253 case U8, U16, U32, U64:
254 typsize := BaseTypeSizes[typ]
255 g.P("buf.EncodeUint", typsize*8, "(", conv(name), ")")
257 g.P("buf.EncodeFloat64(", conv(name), ")")
259 g.P("buf.EncodeBool(", name, ")")
261 g.P("buf.EncodeString(", name, ", ", length, ")")
263 logrus.Panicf("// ??? %s %s\n", name, typ)
267 case I8, U8, I16, U16, I32, U32, I64, U64, F64, BOOL:
273 func genMessageUnmarshal(g *GenFile, name string, fields []*Field) {
274 g.P("func (m *", name, ") Unmarshal(b []byte) error {")
277 g.P("buf := ", govppCodecPkg.Ident("NewBuffer"), "(b)")
278 decodeFields(g, fields, "m", 0)
285 func decodeFields(g *GenFile, fields []*Field, parentName string, lvl int) {
286 getFieldName := func(name string) string {
287 return fmt.Sprintf("%s.%s", parentName, name)
290 for _, field := range fields {
291 name := getFieldName(field.GoName)
293 decodeField(g, field, name, getFieldName, lvl)
297 func decodeField(g *GenFile, field *Field, name string, getFieldName func(string) string, lvl int) {
298 var sizeFromName string
299 if field.FieldSizeFrom != nil {
300 sizeFromName = getFieldName(field.FieldSizeFrom.GoName)
303 if _, ok := BaseTypesGo[field.Type]; ok {
304 decodeBaseType(g, field.Type, fieldGoType(g, field), name, field.Length, sizeFromName, true)
309 index := fmt.Sprintf("j%d", lvl)
310 if field.Length > 0 {
311 g.P("for ", index, " := 0; ", index, " < ", field.Length, ";", index, "++ {")
312 } else if field.SizeFrom != "" {
313 g.P(name, " = make(", getFieldType(g, field), ", ", sizeFromName, ")")
314 g.P("for ", index, " := 0; ", index, " < len(", name, ");", index, "++ {")
316 name = fmt.Sprintf("%s[%s]", name, index)
319 if enum := field.TypeEnum; enum != nil {
320 if _, ok := BaseTypesGo[enum.Type]; ok {
321 decodeBaseType(g, enum.Type, fieldGoType(g, field), name, 0, "", false)
323 logrus.Panicf("\t// ??? ENUM %s %s\n", name, enum.Type)
325 } else if alias := field.TypeAlias; alias != nil {
326 if typ := alias.TypeStruct; typ != nil {
327 decodeFields(g, typ.Fields, name, lvl+1)
329 if alias.Length > 0 {
330 decodeBaseType(g, alias.Type, BaseTypesGo[alias.Type], name, alias.Length, "", false)
332 decodeBaseType(g, alias.Type, fieldGoType(g, field), name, 0, "", false)
335 } else if typ := field.TypeStruct; typ != nil {
336 decodeFields(g, typ.Fields, name, lvl+1)
337 } else if union := field.TypeUnion; union != nil {
338 maxSize := getUnionSize(union)
339 g.P("copy(", name, ".", fieldUnionData, "[:], buf.DecodeBytes(", maxSize, "))")
341 logrus.Panicf("\t// ??? %s (%v)\n", field.GoName, field.Type)
349 func decodeBaseType(g *GenFile, typ, orig, name string, length int, sizefrom string, alloc bool) {
350 isArray := length > 0 || sizefrom != ""
355 size = strconv.Itoa(length)
362 g.P(name, " = make([]byte, ", size, ")")
363 g.P("copy(", name, ", buf.DecodeBytes(len(", name, ")))")
365 g.P("copy(", name, "[:], buf.DecodeBytes(", size, "))")
368 case I8, I16, U16, I32, U32, I64, U64, F64, BOOL:
370 g.P(name, " = make([]", orig, ", ", size, ")")
372 g.P("for i := 0; i < len(", name, "); i++ {")
373 name = fmt.Sprintf("%s[i]", name)
376 conv := func(s string) string {
377 if gotype, ok := BaseTypesGo[typ]; !ok || gotype != orig {
378 return fmt.Sprintf("%s(%s)", orig, s)
383 case I8, I16, I32, I64:
384 typsize := BaseTypeSizes[typ]
385 g.P(name, " = ", conv(fmt.Sprintf("buf.DecodeInt%d()", typsize*8)))
386 case U8, U16, U32, U64:
387 typsize := BaseTypeSizes[typ]
388 g.P(name, " = ", conv(fmt.Sprintf("buf.DecodeUint%d()", typsize*8)))
390 g.P(name, " = ", conv("buf.DecodeFloat64()"))
392 g.P(name, " = buf.DecodeBool()")
394 g.P(name, " = buf.DecodeString(", length, ")")
396 logrus.Panicf("\t// ??? %s %s\n", name, typ)
400 case I8, U8, I16, U16, I32, U32, I64, U64, F64, BOOL: