YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/gen_yrpc/messages_generator.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include "yb/gen_yrpc/messages_generator.h"
15
16
#include <boost/algorithm/string/predicate.hpp>
17
#include <google/protobuf/io/printer.h>
18
19
#include "yb/gen_yrpc/model.h"
20
21
using google::protobuf::internal::WireFormatLite;
22
23
namespace yb {
24
namespace gen_yrpc {
25
26
namespace {
27
28
0
void NextCtorField(YBPrinter printer, bool* first) {
29
0
  if (*first) {
30
0
    printer("\n    : ");
31
0
    *first = false;
32
0
  } else {
33
0
    printer(",\n      ");
34
0
  }
35
0
}
36
37
class Message {
38
 public:
39
  explicit Message(const google::protobuf::Descriptor* message)
40
0
      : message_(message) {
41
0
  }
42
43
0
  bool generated() const {
44
0
    return generated_;
45
0
  }
46
47
0
  void CycleDependency(const google::protobuf::FieldDescriptor* field) {
48
0
    cycle_dependencies_.insert(field);
49
0
  }
50
51
0
  void Declaration(YBPrinter printer) {
52
0
    ScopedSubstituter message_substituter(printer, message_);
53
54
0
    for (int j = 0; j != message_->field_count(); ++j) {
55
0
      const auto* field = message_->field(j);
56
0
      if (field->is_repeated() || StoreAsPointer(field)) {
57
0
        continue;
58
0
      }
59
0
      if (!need_has_fields_enum_) {
60
0
        need_has_fields_enum_ = true;
61
0
        printer("YB_DEFINE_ENUM($message_name$Fields,\n");
62
0
      }
63
0
      ScopedSubstituter field_substituter(printer, field);
64
65
0
      printer("  (k$field_camelcase_name$)\n");
66
0
    }
67
68
0
    if (need_has_fields_enum_) {
69
0
      printer(");\n\n");
70
0
    }
71
72
0
    printer(
73
0
        "class $message_lw_name$ : public ::yb::rpc::LightweightMessage {\n"
74
0
        " public:\n"
75
0
    );
76
77
0
    ScopedIndent public_scope(printer);
78
79
0
    printer(
80
0
        "explicit $message_lw_name$(::yb::Arena* arena);\n"
81
0
        "$message_lw_name$(::yb::Arena* arena, const $message_lw_name$& rhs);\n"
82
0
        "\n"
83
0
        "$message_lw_name$(::yb::Arena* arena, const $message_pb_name$& rhs) \n"
84
0
        "    : $message_lw_name$(arena) {\n"
85
0
        "  CopyFrom(rhs);\n"
86
0
        "}\n"
87
0
        "\n"
88
0
        "void operator=(const $message_lw_name$& rhs) {\n"
89
0
        "  CopyFrom(rhs);\n"
90
0
        "}\n"
91
0
        "\n"
92
0
        "void operator=(const $message_pb_name$& rhs) {\n"
93
0
        "  CopyFrom(rhs);\n"
94
0
        "}\n"
95
0
        "\n"
96
0
        "CHECKED_STATUS ParseFromCodedStream("
97
0
            "google::protobuf::io::CodedInputStream* cis) override;\n"
98
0
        "size_t SerializedSize() const override;\n"
99
0
        "uint8_t* SerializeToArray(uint8_t* out) const override;\n"
100
0
        "void AppendToDebugString(std::string* out) const override;\n"
101
0
        "\n"
102
0
        "void Clear() override;\n"
103
0
        "void CopyFrom(const $message_lw_name$& rhs);\n"
104
0
        "void CopyFrom(const $message_pb_name$& rhs);\n"
105
0
        "\n"
106
0
    );
107
108
0
    if (!message_->options().map_entry()) {
109
0
      printer(
110
0
          "void ToGoogleProtobuf($message_pb_name$* out) const;\n"
111
0
          "\n"
112
0
          "$message_pb_name$ ToGoogleProtobuf() const {\n"
113
0
          "  $message_pb_name$ result;\n"
114
0
          "  ToGoogleProtobuf(&result);\n"
115
0
          "  return result;\n"
116
0
          "}\n"
117
0
          "\n"
118
0
      );
119
0
    }
120
121
0
    bool has_nested_using = false;
122
0
    for (auto i = 0; i != message_->enum_type_count(); ++i) {
123
0
      const auto* nested = message_->enum_type(i);
124
0
      printer("using " + nested->name() + " = $message_name$::" + nested->name() + ";\n");
125
0
      has_nested_using = true;
126
0
    }
127
128
0
    for (auto i = 0; i != message_->nested_type_count(); ++i) {
129
0
      const auto* nested = message_->nested_type(i);
130
0
      printer("using " + MakeLightweightName(nested->name()) + " = " +
131
0
              RelativeClassPath(UnnestedName(nested, Lightweight::kTrue, true),
132
0
                                message_->full_name()) + ";\n");
133
0
      has_nested_using = true;
134
0
    }
135
136
0
    if (has_nested_using) {
137
0
      printer("\n");
138
0
    }
139
140
0
    for (int j = 0; j != message_->field_count(); ++j) {
141
0
      const auto* field = message_->field(j);
142
0
      ScopedSubstituter field_substituter(printer, field);
143
144
0
      if (IsSimple(field)) {
145
0
        printer(
146
0
            "$field_stored_type$ $field_name$() const {\n"
147
0
            "  return $field_name$_;\n"
148
0
            "}\n\n"
149
0
        );
150
0
        if (StoredAsSlice(field)) {
151
0
          printer(
152
0
              "void dup_$field_name$($field_stored_type$ value) {\n"
153
0
              "  has_fields_.Set($message_name$Fields::k$field_camelcase_name$);\n"
154
0
              "  $field_name$_ = arena_.DupSlice(value);\n"
155
0
              "}\n\n"
156
0
              "void ref_$field_name$($field_stored_type$ value) {\n"
157
0
              "  has_fields_.Set($message_name$Fields::k$field_camelcase_name$);\n"
158
0
              "  $field_name$_ = value;\n"
159
0
              "}\n\n"
160
0
          );
161
0
        } else {
162
0
          printer(
163
0
              "void set_$field_name$($field_stored_type$ value) {\n"
164
0
              "  has_fields_.Set($message_name$Fields::k$field_camelcase_name$);\n"
165
0
              "  $field_name$_ = value;\n"
166
0
              "}\n\n"
167
0
          );
168
0
        }
169
0
      } else if (StoreAsPointer(field)) {
170
0
        printer(
171
0
            "const $field_stored_type$& $field_name$() const {\n"
172
0
            "  return $field_name$_ ? *$field_name$_ "
173
0
                ": ::yb::rpc::empty_message<$field_stored_type$>();\n"
174
0
            "}\n\n"
175
0
            "$field_stored_type$& ref_$field_name$($field_stored_type$* value) {\n"
176
0
            "  $field_name$_ = value;\n"
177
0
            "  return *$field_name$_;\n"
178
0
            "}\n\n"
179
0
        );
180
0
      } else {
181
0
        printer(
182
0
            "const $field_stored_type$& $field_name$() const {\n"
183
0
            "  return $field_name$_;\n"
184
0
            "}\n\n"
185
0
        );
186
0
      }
187
188
0
      printer(
189
0
          "$field_stored_type$* mutable_$field_name$() {\n"
190
0
      );
191
192
0
      ScopedIndent mutable_ident(printer);
193
194
0
      if (StoreAsPointer(field)) {
195
0
        printer(
196
0
          "if (!$field_name$_) {\n"
197
0
          "  $field_name$_ = arena_.NewObject<$field_stored_type$>(&arena_);\n"
198
0
          "}\n"
199
0
          "return $field_name$_;\n"
200
0
        );
201
0
      } else {
202
0
        if (!field->is_repeated()) {
203
0
          printer(
204
0
              "has_fields_.Set($message_name$Fields::k$field_camelcase_name$);\n"
205
0
          );
206
0
        }
207
208
0
        printer(
209
0
            "return &$field_name$_;\n"
210
0
        );
211
0
      }
212
213
0
      mutable_ident.Reset("}\n\n");
214
215
0
      if (!field->is_repeated()) {
216
0
        printer("bool has_$field_name$() const {\n");
217
0
        if (StoreAsPointer(field)) {
218
0
          printer("  return $field_name$_ != nullptr;\n");
219
0
        } else {
220
0
          printer("  return has_fields_.Test($message_name$Fields::k$field_camelcase_name$);\n");
221
0
        }
222
0
        printer("}\n\n");
223
0
        printer("void clear_$field_name$() {\n");
224
0
        if (StoreAsPointer(field)) {
225
0
          printer("  $field_name$_ = nullptr;\n");
226
0
        } else {
227
0
          if (IsMessage(field)) {
228
0
            printer("  $field_name$_.Clear();\n");
229
0
          } else {
230
0
            printer("  $field_name$_ = $field_stored_type$();\n");
231
0
          }
232
0
          printer("  has_fields_.Reset($message_name$Fields::k$field_camelcase_name$);\n");
233
0
        }
234
0
        printer("}\n\n");
235
0
      } else if (IsMessage(field)) {
236
0
        printer(
237
0
            "$field_type$* add_$field_name$() {\n"
238
0
            "  return &$field_name$_.emplace_back();\n"
239
0
            "}\n\n"
240
0
        );
241
0
      }
242
0
    }
243
244
0
    if (NeedArena(message_)) {
245
0
      printer(
246
0
          "::yb::Arena& arena() const {\n"
247
0
          "  return arena_;"
248
0
          "}\n\n"
249
0
      );
250
0
    }
251
252
0
    printer(
253
0
        "size_t cached_size() const {\n"
254
0
        "  return cached_size_;\n"
255
0
        "}\n\n"
256
0
    );
257
258
0
    public_scope.Reset();
259
260
0
    printer(" private:\n");
261
262
0
    ScopedIndent private_scope(printer);
263
264
0
    if (NeedArena(message_)) {
265
0
      printer(
266
0
          "::yb::Arena& arena_;\n"
267
0
      );
268
0
    }
269
0
    if (need_has_fields_enum_) {
270
0
      printer(
271
0
          "::yb::EnumBitSet<$message_name$Fields> has_fields_;\n"
272
0
      );
273
0
    }
274
0
    printer(
275
0
        "mutable size_t cached_size_ = 0;\n"
276
0
    );
277
278
0
    for (int j = 0; j != message_->field_count(); ++j) {
279
0
      const auto* field = message_->field(j);
280
0
      ScopedSubstituter field_substituter(printer, field);
281
282
0
      if (StoreAsPointer(field)) {
283
0
        printer(
284
0
            "$field_stored_type$* $field_name$_ = nullptr;\n"
285
0
        );
286
0
      } else if (IsSimple(field)) {
287
0
        printer(
288
0
            "$field_stored_type$ $field_name$_ = $field_stored_type$();\n"
289
0
        );
290
0
      } else {
291
0
        printer(
292
0
            "$field_stored_type$ $field_name$_;\n"
293
0
        );
294
0
        if (field->is_packed() && !FixedSize(field)) {
295
0
          printer(
296
0
              "mutable size_t $field_name$_cached_size_ = 0;\n"
297
0
          );
298
0
        }
299
0
      }
300
0
    }
301
302
0
    private_scope.Reset("};\n\n");
303
304
0
    generated_ = true;
305
0
  }
306
307
0
  void Definition(YBPrinter printer) const {
308
0
    ScopedSubstituter message_substituter(printer, message_);
309
310
0
    Ctor(printer);
311
0
    CopyCtor(printer);
312
0
    AppendToDebugString(printer);
313
0
    Clear(printer);
314
0
    CopyFrom(printer, Lightweight::kTrue);
315
0
    CopyFrom(printer, Lightweight::kFalse);
316
0
    Parse(printer);
317
0
    Serialize(printer);
318
0
    Size(printer);
319
0
    if (!message_->options().map_entry()) {
320
0
      ToGoogleProtobuf(printer);
321
0
    }
322
0
  }
323
324
 private:
325
0
  void Ctor(YBPrinter printer) const {
326
0
    printer("$message_lw_name$::$message_lw_name$(::yb::Arena* arena)");
327
0
    bool first = true;
328
0
    if (NeedArena(message_)) {
329
0
      NextCtorField(printer, &first);
330
0
      printer("arena_(*arena)");
331
0
    }
332
0
    for (int j = 0; j != message_->field_count(); ++j) {
333
0
      const auto* field = message_->field(j);
334
0
      if (!field->is_repeated() && (!IsMessage(field) || StoreAsPointer(field))) {
335
0
        continue;
336
0
      }
337
0
      NextCtorField(printer, &first);
338
0
      ScopedSubstituter field_substituter(printer, field);
339
0
      printer("$field_name$_(arena)");
340
0
    }
341
0
    printer(" {\n}\n\n");
342
0
  }
343
344
0
  void CopyCtor(YBPrinter printer) const {
345
0
    printer(
346
0
        "$message_lw_name$::$message_lw_name$(::yb::Arena* arena, const $message_lw_name$& rhs)"
347
0
    );
348
0
    bool first = true;
349
0
    if (NeedArena(message_)) {
350
0
      NextCtorField(printer, &first);
351
0
      printer("arena_(*arena)");
352
0
    }
353
0
    if (need_has_fields_enum_) {
354
0
      NextCtorField(printer, &first);
355
0
      printer("has_fields_(rhs.has_fields_)");
356
0
    }
357
0
    for (int j = 0; j != message_->field_count(); ++j) {
358
0
      NextCtorField(printer, &first);
359
0
      const auto* field = message_->field(j);
360
0
      ScopedSubstituter field_substituter(printer, field);
361
0
      if (StoreAsPointer(field)) {
362
0
        printer(
363
0
            "$field_name$_(rhs.$field_name$_ "
364
0
                "? arena->NewObject<$field_stored_type$>(arena, *rhs.$field_name$_) : nullptr)"
365
0
        );
366
0
      } else if (IsMessage(field)) {
367
0
        printer("$field_name$_(arena, rhs.$field_name$_)");
368
0
      } else if (field->is_repeated()) {
369
0
        if (StoredAsSlice(field)) {
370
0
          printer("$field_name$_(arena)");
371
0
        } else {
372
0
          printer("$field_name$_(rhs.$field_name$_.begin(), rhs.$field_name$_.end(), arena)");
373
0
        }
374
0
      } else if (StoredAsSlice(field)) {
375
0
        printer("$field_name$_(arena->DupSlice(rhs.$field_name$_))");
376
0
      } else {
377
0
        printer("$field_name$_(rhs.$field_name$_)");
378
0
      }
379
0
    }
380
0
    printer(" {\n");
381
0
    ScopedIndent body_indent(printer);
382
0
    for (int j = 0; j != message_->field_count(); ++j) {
383
0
      const auto* field = message_->field(j);
384
0
      ScopedSubstituter field_substituter(printer, field);
385
0
      if (!field->is_repeated() || !StoredAsSlice(field)) {
386
0
        continue;
387
0
      }
388
0
      printer(
389
0
          "$field_name$_.reserve(rhs.$field_name$_.size());\n"
390
0
          "for (const auto& entry : rhs.$field_name$_) {\n"
391
0
          "  $field_name$_.push_back(arena->DupSlice(entry));\n"
392
0
          "}\n"
393
0
      );
394
0
    }
395
0
    body_indent.Reset("}\n\n");
396
0
  }
397
398
0
  void AppendToDebugString(YBPrinter printer) const {
399
0
    printer("void $message_lw_name$::AppendToDebugString(std::string* out) const {\n");
400
0
    ScopedIndent indent(printer);
401
0
    if (message_->field_count()) {
402
0
      printer("bool first = true;");
403
0
    }
404
0
    std::vector<const google::protobuf::FieldDescriptor*> fields;
405
0
    for (int j = 0; j != message_->field_count(); ++j) {
406
0
      fields.push_back(message_->field(j));
407
0
    }
408
0
    std::sort(fields.begin(), fields.end(), [](const auto* lhs, const auto* rhs) {
409
0
      return lhs->number() < rhs->number();
410
0
    });
411
0
    for (const auto* field : fields) {
412
0
      ScopedSubstituter field_substituter(printer, field);
413
0
      if (field->is_repeated()) {
414
0
        printer("for (const auto& entry : $field_name$_) {\n");
415
0
      } else {
416
0
        printer("if (has_$field_name$()) {\n");
417
0
      }
418
0
      if (IsMessage(field)) {
419
0
        printer("  ::yb::rpc::AppendFieldTitle(\"$field_name$\", \" { \", &first, out);\n");
420
0
        printer("  $field_value$.AppendToDebugString(out);\n");
421
0
        printer("  *out += \" }\";\n");
422
0
      } else if (StoredAsSlice(field)) {
423
0
        printer("  ::yb::rpc::AppendFieldTitle(\"$field_name$\", \": \\\"\", &first, out);\n");
424
0
        printer("  *out += $field_value$.ToBuffer();\n");
425
0
        printer("  *out += '\"';\n");
426
0
      } else {
427
0
        printer("  ::yb::rpc::AppendFieldTitle(\"$field_name$\", \": \", &first, out);\n");
428
0
        if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE) {
429
0
          printer("  *out += ::SimpleDtoa($field_value$);\n");
430
0
        } else if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_FLOAT) {
431
0
          printer("  *out += ::SimpleFtoa($field_value$);\n");
432
0
        } else if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_ENUM) {
433
0
          printer("  *out += $nonlw_field_type$_Name($field_value$);\n");
434
0
        } else {
435
0
          printer("  *out += std::to_string($field_value$);\n");
436
0
        }
437
0
      }
438
0
      printer("}\n");
439
0
    }
440
0
    indent.Reset("}\n\n");
441
0
  }
442
443
0
  void Clear(YBPrinter printer) const {
444
0
    printer("void $message_lw_name$::Clear() {\n");
445
0
    for (int j = 0; j != message_->field_count(); ++j) {
446
0
      const auto* field = message_->field(j);
447
0
      ScopedSubstituter field_substituter(printer, field);
448
0
      if (field->is_repeated()) {
449
0
        printer("  $field_name$_.clear();\n");
450
0
      } else {
451
0
        printer("  clear_$field_name$();\n");
452
0
      }
453
0
    }
454
0
    printer("}\n\n");
455
0
  }
456
457
0
  void CopyFrom(YBPrinter printer, Lightweight lightweight) const {
458
0
    printer("void $message_lw_name$::CopyFrom(const ");
459
0
    printer(lightweight ? "$message_lw_name$" : "$message_pb_name$");
460
0
    printer("& rhs) {\n");
461
0
    ScopedIndent copy_from_indent(printer);
462
0
    for (int j = 0; j != message_->field_count(); ++j) {
463
0
      const auto* field = message_->field(j);
464
0
      ScopedSubstituter field_substituter(printer, field);
465
0
      std::string source = lightweight ? "rhs.$field_name$_" : "rhs.$field_name$()";
466
0
      if (lightweight && StoreAsPointer(field)) {
467
0
        source = "*" + source;
468
0
      } else if (!lightweight && message_->options().map_entry()) {
469
0
        if (field->name() == "key") {
470
0
          source = "rhs.first";
471
0
        } else {
472
0
          source = "rhs.second";
473
0
        }
474
0
      }
475
0
      if (field->is_repeated()) {
476
0
        if (StoredAsSlice(field)) {
477
0
          printer(
478
0
              "$field_name$_.reserve(" + source + ".size());\n"
479
0
              "for (const auto& entry : " + source + ") {\n"
480
0
              "  $field_name$_.push_back(arena_.DupSlice(entry));\n"
481
0
              "}\n"
482
0
          );
483
0
        } else if (lightweight) {
484
0
          printer("$field_name$_ = " + source + ";\n");
485
0
        } else if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_ENUM) {
486
0
          printer(
487
0
              "$field_name$_.reserve(" + source + ".size());\n"
488
0
              "for (auto entry : " + source + ") {\n"
489
0
              "  $field_name$_.push_back(static_cast<$field_type$>(entry));\n"
490
0
              "}\n"
491
0
          );
492
0
        } else {
493
0
          printer("$field_name$_.assign(" + source + ".begin(), " + source + ".end());\n");
494
0
        }
495
0
      } else {
496
0
        bool check_has =
497
0
            (field->file()->syntax() == google::protobuf::FileDescriptor::Syntax::SYNTAX_PROTO2 ||
498
0
             lightweight) &&
499
0
            !message_->options().map_entry();
500
0
        if (StoreAsPointer(field)) {
501
0
          if (lightweight) {
502
0
            printer("if (rhs.$field_name$_) {\n");
503
0
          } else {
504
0
            printer("if (rhs.has_$field_name$()) {\n");
505
0
          }
506
0
          printer(
507
0
              "  mutable_$field_name$()->CopyFrom(" + source + ");\n"
508
0
          );
509
0
        } else {
510
0
          if (check_has) {
511
0
            printer("if (rhs.has_$field_name$()) {\n");
512
0
          } else {
513
0
            printer("{\n");
514
0
          }
515
0
          if (IsMessage(field)) {
516
0
            printer("  $field_name$_.CopyFrom(" + source + ");\n");
517
0
          } else if (StoredAsSlice(field)) {
518
0
            printer("  $field_name$_ = arena_.DupSlice(" + source + ");\n");
519
0
          } else {
520
0
            printer("  $field_name$_ = " + source + ";\n");
521
0
          }
522
0
          if (!lightweight) {
523
0
            printer("  has_fields_.Set($message_name$Fields::k$field_camelcase_name$);\n");
524
0
          }
525
0
        }
526
0
        if (check_has) {
527
0
          printer(
528
0
              "} else {\n"
529
0
              "  clear_$field_name$();\n"
530
0
          );
531
0
        }
532
0
        printer("}\n");
533
0
      }
534
0
    }
535
0
    if (need_has_fields_enum_ && lightweight) {
536
0
      printer("has_fields_ = rhs.has_fields_;\n");
537
0
    }
538
0
    copy_from_indent.Reset("}\n\n");
539
0
  }
540
541
0
  void Parse(YBPrinter printer) const {
542
0
    printer(
543
0
        "Status $message_lw_name$::ParseFromCodedStream("
544
0
            "google::protobuf::io::CodedInputStream* input) {\n"
545
0
    );
546
547
0
    ScopedIndent method_indent(printer);
548
549
0
    printer(
550
0
        "for (;;) {\n"
551
0
    );
552
553
0
    ScopedIndent loop_indent(printer);
554
0
    printer(
555
0
        "auto p = input->ReadTagWithCutoffNoLastTag($cutoff$);\n"
556
0
        "if (!p.second && !p.first) {\n"
557
0
        "  return Status::OK();\n"
558
0
        "}\n"
559
0
        "switch(::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(p.first)) {\n"
560
0
    );
561
562
0
    ScopedIndent switch_indent(printer);
563
0
    for (int j = 0; j != message_->field_count(); ++j) {
564
0
      const auto* field = message_->field(j);
565
0
      ScopedSubstituter field_substituter(printer, field);
566
567
0
      printer(
568
0
          "case $field_number$: { // $field_name$\n"
569
0
      );
570
0
      ScopedIndent case_indent(printer);
571
0
      auto parse_failed = "  return ::yb::rpc::ParseFailed(\"$field_name$\");\n";
572
0
      if (field->is_repeated()) {
573
0
        if (IsMessage(field)) {
574
0
          printer(
575
0
              "if (!$field_serialization$::Read(input, &$field_name$_.emplace_back())) {\n"
576
0
          );
577
0
          printer(parse_failed);
578
0
          printer("}\n");
579
0
        } else {
580
0
          if (field->is_packable()) {
581
0
            auto packed_tag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
582
0
                field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
583
0
            printer(
584
0
                "if (p.first == " + std::to_string(packed_tag) + ") {\n"
585
0
            );
586
0
            ScopedIndent if_packed_indent(printer);
587
0
            printer(
588
0
                "int length;\n"
589
0
                "if (!input->ReadVarintSizeAsInt(&length)) {\n"
590
0
            );
591
0
            printer(parse_failed);
592
0
            printer(
593
0
                "}\n"
594
0
                "auto old_limit = input->PushLimit(length);\n"
595
0
                "while (input->BytesUntilLimit() > 0) {\n"
596
0
            );
597
0
            ScopedIndent while_indent(printer);
598
0
            printer(
599
0
                "$field_name$_.emplace_back();\n"
600
0
                "if (!$field_serialization$::Read(input, &$field_name$_.back())) {\n"
601
0
            );
602
0
            printer(parse_failed);
603
0
            printer("}\n");
604
0
            while_indent.Reset("}\n\n");
605
0
            printer(
606
0
                "input->PopLimit(old_limit);\n"
607
0
            );
608
0
            if_packed_indent.Reset();
609
0
            printer("} else {\n");
610
0
            printer.printer().Indent();
611
0
          }
612
0
          printer(
613
0
              "$field_name$_.emplace_back();\n"
614
0
              "if (!$field_serialization$::Read(input, &$field_name$_.back())) {\n"
615
0
          );
616
0
          printer(parse_failed);
617
0
          printer("}\n");
618
0
          if (field->is_packable()) {
619
0
            printer.printer().Outdent();
620
0
            printer("}\n");
621
0
          }
622
0
        }
623
0
      } else {
624
0
        printer("if (!$field_serialization$::Read(input, mutable_$field_name$())) {\n");
625
0
        printer(parse_failed);
626
0
        printer(
627
0
            "}\n"
628
0
        );
629
0
      }
630
0
      printer(
631
0
          "break;\n"
632
0
      );
633
0
      case_indent.Reset("}\n");
634
0
    }
635
636
0
    switch_indent.Reset("}\n");
637
0
    loop_indent.Reset("}\n");
638
0
    method_indent.Reset("}\n\n");
639
0
  }
640
641
0
  void Size(YBPrinter printer) const {
642
0
    printer(
643
0
        "size_t $message_lw_name$::SerializedSize() const {\n"
644
0
    );
645
646
0
    ScopedIndent method_indent(printer);
647
648
0
    printer("size_t result = 0;\n");
649
650
0
    for (int j = 0; j != message_->field_count(); ++j) {
651
0
      auto* field = message_->field(j);
652
0
      ScopedSubstituter field_substituter(printer, field);
653
0
      if (!field->is_repeated()) {
654
0
        printer("if (has_$field_name$()) ");
655
0
      }
656
0
      printer("{\n");
657
0
      ScopedIndent field_indent(printer);
658
0
      auto tag_size = WireFormatLite::TagSize(field->number(), FieldType(field));
659
0
      auto fixed_size = FixedSize(field);
660
0
      if (fixed_size) {
661
0
        if (field->is_packed()) {
662
0
          printer(
663
0
              "size_t body_size = " + std::to_string(fixed_size) + " * $field_name$_.size();\n"
664
0
              "result += " + std::to_string(tag_size) +
665
0
              " + ::google::protobuf::io::CodedOutputStream::VarintSize32("
666
0
                  "narrow_cast<uint32_t>(body_size)) + body_size"
667
0
          );
668
0
        } else {
669
0
          printer("result += " + std::to_string(tag_size + fixed_size));
670
0
          if (field->is_repeated()) {
671
0
            printer(" * $field_name$_.size()");
672
0
          }
673
0
        }
674
0
        printer(";\n");
675
0
      } else {
676
0
        printer(
677
0
            "result += ::yb::rpc::$field_serialization_prefix$Size<$field_serialization$, " +
678
0
            std::to_string(tag_size) + ">("
679
0
        );
680
0
        if (StoreAsPointer(field)) {
681
0
          printer("*");
682
0
        }
683
0
        printer("$field_name$_");
684
0
        if (field->is_packed()) {
685
0
          printer(", &$field_name$_cached_size_");
686
0
        }
687
0
        printer(");\n");
688
0
      }
689
0
      field_indent.Reset("}\n");
690
0
    }
691
692
693
0
    printer(
694
0
        "cached_size_ = result;\n"
695
0
        "return result;\n"
696
0
    );
697
0
    method_indent.Reset("}\n\n");
698
0
  }
699
700
0
  void Serialize(YBPrinter printer) const {
701
0
    printer(
702
0
        "uint8_t* $message_lw_name$::SerializeToArray(uint8_t* out) const {\n");
703
704
0
    ScopedIndent method_indent(printer);
705
706
0
    for (int j = 0; j != message_->field_count(); ++j) {
707
0
      auto* field = message_->field(j);
708
0
      ScopedSubstituter field_substituter(printer, field);
709
710
0
      if (!field->is_repeated()) {
711
0
        printer("if (has_$field_name$()) {\n");
712
0
        printer.printer().Indent();
713
0
      }
714
715
0
      auto tag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
716
0
          field->number(),
717
0
          field->is_packed() ? WireFormatLite::WIRETYPE_LENGTH_DELIMITED : WireType(field));
718
0
      printer(
719
0
          "out = ::yb::rpc::$field_serialization_prefix$Write<$field_serialization$, " +
720
0
          std::to_string(tag) + ">("
721
0
      );
722
0
      if (StoreAsPointer(field)) {
723
0
        printer("*");
724
0
      }
725
0
      printer("$field_name$_, ");
726
0
      if (field->is_packed()) {
727
0
        auto fixed_size = FixedSize(field);
728
0
        if (fixed_size) {
729
0
          printer(std::to_string(fixed_size) + " * $field_name$_.size(), ");
730
0
        } else {
731
0
          printer("$field_name$_cached_size_, ");
732
0
        }
733
0
      }
734
0
      printer("out);\n");
735
0
      if (!field->is_repeated()) {
736
0
        printer.printer().Outdent();
737
0
        printer("}\n");
738
0
      }
739
0
    }
740
741
0
    printer("return out;\n");
742
0
    method_indent.Reset("}\n\n");
743
0
  }
744
745
0
  void ToGoogleProtobuf(YBPrinter printer) const {
746
0
    printer(
747
0
      "void $message_lw_name$::ToGoogleProtobuf($message_pb_name$* out) const {\n"
748
0
    );
749
750
0
    ScopedIndent method_indent(printer);
751
752
0
    for (int j = 0; j != message_->field_count(); ++j) {
753
0
      const auto* field = message_->field(j);
754
0
      ScopedSubstituter field_substituter(printer, field);
755
0
      if (IsMessage(field) && !field->is_map()) {
756
0
        if (!field->is_repeated()) {
757
0
          printer("if (has_$field_name$()) {\n");
758
0
          printer.printer().Indent();
759
0
        }
760
0
        printer("$field_name$().ToGoogleProtobuf(out->mutable_$field_name$());\n");
761
0
        if (!field->is_repeated()) {
762
0
          printer.printer().Outdent();
763
0
          printer("}\n");
764
0
        }
765
0
      } else if (field->is_repeated()) {
766
0
        printer("{\n");
767
0
        ScopedIndent block_indent(printer);
768
0
        printer(
769
0
            "auto& repeated = *out->mutable_$field_name$();\n"
770
0
        );
771
0
        if (field->is_map()) {
772
0
          printer(
773
0
              "repeated.clear();\n"
774
0
              "for (const auto& entry : $field_name$_) {\n"
775
0
          );
776
0
          const auto* key_field = field->message_type()->FindFieldByName("key");
777
0
          const auto* value_field = field->message_type()->FindFieldByName("value");
778
0
          printer("  repeated[entry.key()");
779
0
          if (StoredAsSlice(key_field)) {
780
0
            printer(".ToBuffer()");
781
0
          }
782
0
          printer("] = entry.value()");
783
0
          if (StoredAsSlice(value_field)) {
784
0
            printer(".ToBuffer()");
785
0
          }
786
0
          printer(";\n");
787
0
        } else {
788
0
          printer(
789
0
              "repeated.Clear();\n"
790
0
              "repeated.Reserve(narrow_cast<int>($field_name$_.size()));\n"
791
0
              "for (const auto& entry : $field_name$_) {\n"
792
0
          );
793
0
          if (StoredAsSlice(field)) {
794
0
            printer("  repeated.Add()->assign(entry.cdata(), entry.size());\n");
795
0
          } else {
796
0
            printer("  repeated.Add(entry);\n");
797
0
          }
798
0
        }
799
800
0
        printer("}\n");
801
0
        block_indent.Reset("}\n");
802
0
      } else {
803
0
        printer("if (has_$field_name$()) {\n");
804
805
0
        if (StoredAsSlice(field)) {
806
0
          if (message_->options().map_entry()) {
807
0
            if (field->name() == "key") {
808
0
              printer("  out->first.assign(");
809
0
            } else {
810
0
              printer("  out->second.assign(");
811
0
            }
812
0
          } else {
813
0
            printer("  out->set_$field_name$(");
814
0
          }
815
0
          printer("$field_name$_.cdata(), $field_name$_.size());\n");
816
0
        } else {
817
0
          if (message_->options().map_entry()) {
818
0
            if (field->name() == "key") {
819
0
              printer("  out->first = $field_name$_;");
820
0
            } else {
821
0
              printer("  out->second = $field_name$_;");
822
0
            }
823
0
          } else {
824
0
            printer("  out->set_$field_name$($field_name$_);\n");
825
0
          }
826
0
        }
827
828
0
        if (!message_->options().map_entry()) {
829
0
          printer(
830
0
              "} else {\n"
831
0
              "  out->clear_$field_name$();\n"
832
0
          );
833
0
        }
834
0
        printer("}\n");
835
0
      }
836
0
    }
837
838
0
    method_indent.Reset("}\n\n");
839
0
  }
840
841
0
  bool StoreAsPointer(const google::protobuf::FieldDescriptor* field) const {
842
0
    return cycle_dependencies_.count(field) || IsPointerField(field);
843
0
  }
844
845
  const google::protobuf::Descriptor* message_;
846
  bool generated_ = false;
847
  bool need_has_fields_enum_ = false;
848
  std::unordered_set<const google::protobuf::FieldDescriptor*> cycle_dependencies_;
849
};
850
851
} // namespace
852
853
class MessagesGenerator::Impl {
854
 public:
855
0
  void Header(YBPrinter printer, const google::protobuf::FileDescriptor* file) {
856
0
    printer(
857
0
        "// THIS FILE IS AUTOGENERATED FROM $path$\n"
858
0
        "\n"
859
0
        "#pragma once\n"
860
0
        "\n"
861
0
    );
862
863
0
    bool generating_any = false;
864
0
    for (int i = 0; i != file->message_type_count(); ++i) {
865
0
      if (IsLwAny(file->message_type(i))) {
866
0
        generating_any = true;
867
0
        break;
868
0
      }
869
0
    }
870
871
0
    if (generating_any) {
872
0
      printer("#include <google/protobuf/any.pb.h>\n");
873
0
    }
874
875
0
    printer(
876
0
        "#include \"yb/rpc/lightweight_message.h\"\n"
877
0
        "#include \"yb/util/memory/arena_list.h\"\n"
878
0
        "#include \"yb/util/memory/mc_types.h\"\n"
879
0
        "#include \"$path_no_extension$.pb.h\"\n"
880
0
        "\n"
881
0
    );
882
883
0
    auto deps = ListDependencies(file);
884
0
    if (!deps.empty()) {
885
0
      for (const auto& dep : deps) {
886
0
        printer(
887
0
            "#include \"" + dep + ".messages.h\"\n"
888
0
        );
889
0
      }
890
0
      printer("\n");
891
0
    }
892
893
0
    printer(
894
0
        "$open_namespace$\n"
895
0
    );
896
897
0
    for (int i = 0; i != file->message_type_count(); ++i) {
898
0
      MessageForward(printer, file->message_type(i));
899
0
    }
900
901
0
    printer("\n");
902
903
0
    for (int i = 0; i != file->message_type_count(); ++i) {
904
0
      MessageDeclaration(printer, file->message_type(i));
905
0
    }
906
907
0
    printer(
908
0
        "$close_namespace$"
909
0
    );
910
0
  }
911
912
0
  void Source(YBPrinter printer, const google::protobuf::FileDescriptor* file) {
913
0
    printer(
914
0
        "// THIS FILE IS AUTOGENERATED FROM $path$\n"
915
0
        "\n"
916
0
        "#include \"$path_no_extension$.messages.h\"\n"
917
0
        "\n"
918
0
        "#include \"yb/gutil/strings/numbers.h\"\n"
919
0
        "\n"
920
0
        "$open_namespace$\n"
921
0
    );
922
923
0
    for (int i = 0; i != file->message_type_count(); ++i) {
924
0
      MessageDefinition(printer, file->message_type(i));
925
0
    }
926
927
0
    printer("$close_namespace$");
928
0
  }
929
930
 private:
931
0
  void MessageForward(YBPrinter printer, const google::protobuf::Descriptor* message) {
932
0
    for (auto i = 0; i != message->nested_type_count(); ++i) {
933
0
      MessageForward(printer, message->nested_type(i));
934
0
    }
935
936
0
    ScopedSubstituter message_substituter(printer, message);
937
0
    printer("class $message_lw_name$;\n");
938
0
  }
939
940
0
  bool MessageDeclaration(YBPrinter printer, const google::protobuf::Descriptor* message) {
941
0
    auto insert_result = messages_.emplace(message, nullptr);
942
0
    if (insert_result.second) {
943
0
      insert_result.first->second = std::make_unique<Message>(message);
944
0
    } else {
945
0
      return insert_result.first->second->generated();
946
0
    }
947
948
0
    for (auto i = 0; i != message->nested_type_count(); ++i) {
949
0
      MessageDeclaration(printer, message->nested_type(i));
950
0
    }
951
952
0
    for (int j = 0; j != message->field_count(); ++j) {
953
0
      auto* field = message->field(j);
954
0
      if (!field->is_repeated() && field->message_type() &&
955
0
          field->message_type()->file() == message->file()) {
956
0
        if (!MessageDeclaration(printer, field->message_type())) {
957
0
          printer("// CYCLE " + message->name() + "\n");
958
0
          insert_result.first->second->CycleDependency(field);
959
0
        }
960
0
      }
961
0
    }
962
963
0
    insert_result.first->second->Declaration(printer);
964
0
    return true;
965
0
  }
966
967
0
  void MessageDefinition(YBPrinter printer, const google::protobuf::Descriptor* message) {
968
0
    for (int i = 0; i != message->nested_type_count(); ++i) {
969
0
      MessageDefinition(printer, message->nested_type(i));
970
0
    }
971
972
0
    messages_[message]->Definition(printer);
973
0
  }
974
975
  std::unordered_map<const google::protobuf::Descriptor*, std::unique_ptr<Message>> messages_;
976
};
977
978
0
MessagesGenerator::MessagesGenerator() : impl_(new Impl) {
979
0
}
980
981
0
MessagesGenerator::~MessagesGenerator() {
982
0
}
983
984
0
void MessagesGenerator::Header(YBPrinter printer, const google::protobuf::FileDescriptor* file) {
985
0
  impl_->Header(printer, file);
986
0
}
987
988
0
void MessagesGenerator::Source(YBPrinter printer, const google::protobuf::FileDescriptor* file) {
989
0
  impl_->Source(printer, file);
990
0
}
991
992
} // namespace gen_yrpc
993
} // namespace yb