+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
+
+