+def calc_size_fun(objs, modulename):
+ '''Main entry point for calculate size function generation'''
+ output = '''\
+
+/****** Calculate size functions *****/\n\
+#ifdef vl_calcsizefun
+#ifndef included_{module}_calcsizefun
+#define included_{module}_calcsizefun
+
+'''
+ output = output.format(module=modulename)
+
+ signature = '''\
+/* calculate message size of message in network byte order */
+static inline uword vl_api_{name}_t_calc_size (vl_api_{name}_t *a)
+{{
+'''
+
+ for o in objs:
+ tname = o.__class__.__name__
+
+ output += signature.format(name=o.name)
+ output += f" return sizeof(*a)"
+ if tname == 'Using':
+ if 'length' in o.alias:
+ try:
+ tmp = int(o.alias['length'])
+ if tmp == 0:
+ raise (f"Unexpected length '0' for alias {o}")
+ except:
+ # output += f" + vl_api_{o.alias.name}_t_calc_size({o.name})"
+ print("culprit:")
+ print(o)
+ print(dir(o.alias))
+ print(o.alias)
+ raise
+ elif tname == 'Enum' or tname == 'EnumFlag':
+ pass
+ else:
+ for b in o.block:
+ if b.type == 'Option':
+ continue
+ elif b.type == 'Field':
+ if b.fieldtype.startswith('vl_api_'):
+ output += f" - sizeof(a->{b.fieldname})"
+ output += f" + {b.fieldtype}_calc_size(&a->{b.fieldname})"
+ elif b.type == 'Array':
+ if b.lengthfield:
+ m = list(filter(lambda x: x.fieldname == b.lengthfield, o.block))
+ if len(m) != 1:
+ raise Exception(f"Expected 1 match for field '{b.lengthfield}', got '{m}'")
+ lf = m[0]
+ if lf.fieldtype in ENDIAN_STRINGS:
+ output += f" + {ENDIAN_STRINGS[lf.fieldtype]}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
+ elif lf.fieldtype == "u8":
+ output += f" + a->{b.lengthfield} * sizeof(a->{b.fieldname}[0])"
+ else:
+ raise Exception(f"Don't know how to endian swap {lf.fieldtype}")
+ else:
+ # Fixed length strings decay to nul terminated u8
+ if b.fieldtype == 'string':
+ if b.modern_vla:
+ output += f" + vl_api_string_len(&a->{b.fieldname})"
+
+ output += ";\n"
+ output += '}\n\n'
+ output += "\n#endif"
+ output += "\n#endif /* vl_calcsizefun */\n\n"
+
+ return output
+
+