structSerializeImpl sname fields
 = do sayln' $ structSerializeProto sname ++ " {"
      sayln' $ "  int ret = 0;"
      sayln' $ "  "
      flip mapM_ fields $ \(StructField{ field_name = fname, field_array = farray, field_type = ftype })
        -> case farray of
            Scalar ->
              case ftype of
                FStruct csname ->
                  do sayln' $ "  ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ ");"
                     sayln' $ "  if (ret) return ret;"
                _ ->
                  do sayln' $ "  ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ ");"
                     sayln' $ "  if (ret) return ret;"
            Fixed _ ->
              do sayln' $ "  for (int i = 0; i < " ++ arrayLenFixed sname fname ++ "; i++) {"
                 case ftype of
                    FStruct csname ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                    _ ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                 sayln' $ "  }"
            Max _ ->
              do sayln' $ "  ret = " ++ serialize (FInt IKUnsigned IS32) ++ "(out, out_len, pos, in->" ++ arrayLen fname ++ ");"
                 sayln' $ "  if (ret) return ret;"
                 sayln' $ "  for (int i = 0; i < in->" ++ arrayLen fname ++ "; i++) {"
                 case ftype of
                    FStruct csname ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                    _ ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                 sayln' $ "  }"
      sayln' $ "  "
      sayln' $ "  return ret;"
      sayln' $ "}"
structSerializeImpl sname fields
 = do sayln' $ structSerializeProto sname ++ " {"
      sayln' $ "  int ret = 0;"
      sayln' $ "  "
      flip mapM_ fields $ \(StructField{ field_name = fname, field_array = farray, field_type = ftype })
        -> case farray of
            Scalar ->
              case ftype of
                FStruct csname ->
                  do sayln' $ "  ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ ");"
                     sayln' $ "  if (ret) return ret;"
                _ ->
                  do sayln' $ "  ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ ");"
                     sayln' $ "  if (ret) return ret;"
            Fixed _ ->
              do sayln' $ "  for (int i = 0; i < " ++ arrayLenFixed sname fname ++ "; i++) {"
                 case ftype of
                    FStruct csname ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                    _ ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                 sayln' $ "  }"
            Max _ ->
              do sayln' $ "  ret = " ++ serialize (FInt IKUnsigned IS32) ++ "(out, out_len, pos, in->" ++ arrayLen fname ++ ");"
                 sayln' $ "  if (ret) return ret;"
                 sayln' $ "  for (int i = 0; i < in->" ++ arrayLen fname ++ "; i++) {"
                 case ftype of
                    FStruct csname ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                    _ ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                 sayln' $ "  }"
      sayln' $ "  "
      sayln' $ "  return ret;"
      sayln' $ "}"
structSerializeImpl sname fields
 = do sayln' $ structSerializeProto sname ++ " {"
      sayln' $ "  int ret = 0;"
      sayln' $ "  "
      flip mapM_ fields $ \(StructField{ field_name = fname, field_array = farray, field_type = ftype })
        -> case farray of
            Scalar ->
              case ftype of
                FStruct csname ->
                  do sayln' $ "  ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ ");"
                     sayln' $ "  if (ret) return ret;"
                _ ->
                  do sayln' $ "  ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ ");"
                     sayln' $ "  if (ret) return ret;"
            Fixed _ ->
              do sayln' $ "  for (int i = 0; i < " ++ arrayLenFixed sname fname ++ "; i++) {"
                 case ftype of
                    FStruct csname ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                    _ ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                 sayln' $ "  }"
            Max _ ->
              do sayln' $ "  ret = " ++ serialize (FInt IKUnsigned IS32) ++ "(out, out_len, pos, in->" ++ arrayLen fname ++ ");"
                 sayln' $ "  if (ret) return ret;"
                 sayln' $ "  for (int i = 0; i < in->" ++ arrayLen fname ++ "; i++) {"
                 case ftype of
                    FStruct csname ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, &in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                    _ ->
                      do sayln' $ "    ret = " ++ serialize ftype ++ "(out, out_len, pos, in->" ++ fname ++ "[i]);"
                         sayln' $ "    if (ret) return ret;"
                 sayln' $ "  }"
      sayln' $ "  "
      sayln' $ "  return ret;"
      sayln' $ "}"