DCCL v5
Loading...
Searching...
No Matches
field_codec.cpp
1// Copyright 2011-2023:
2// GobySoft, LLC (2013-)
3// Massachusetts Institute of Technology (2007-2014)
4// Community contributors (see AUTHORS file)
5// File authors:
6// Toby Schneider <toby@gobysoft.org>
7//
8//
9// This file is part of the Dynamic Compact Control Language Library
10// ("DCCL").
11//
12// DCCL is free software: you can redistribute it and/or modify
13// it under the terms of the GNU Lesser General Public License as published by
14// the Free Software Foundation, either version 2.1 of the License, or
15// (at your option) any later version.
16//
17// DCCL is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU Lesser General Public License for more details.
21//
22// You should have received a copy of the GNU Lesser General Public License
23// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
24#include "field_codec.h"
25#include "codec.h"
26
27using dccl::dlog;
28using namespace dccl::logger;
29
30//
31// FieldCodecBase public
32//
33dccl::FieldCodecBase::FieldCodecBase() = default;
34
35void dccl::FieldCodecBase::base_encode(Bitset* bits, const google::protobuf::Message& field_value,
36 MessagePart part, bool strict)
37{
38 BaseRAII scoped_globals(this, part, &field_value, strict);
39 manager().codec_data().root_bits_ = bits;
40
41 // we pass this through the FromProtoCppTypeBase to do dynamic_cast (RTTI) for
42 // custom message codecs so that these codecs can be written in the derived class (not google::protobuf::Message)
43 field_encode(bits,
44 manager().type_helper().find(field_value.GetDescriptor())->get_value(field_value),
45 nullptr);
46}
47
48void dccl::FieldCodecBase::field_encode(Bitset* bits, const dccl::any& field_value,
49 const google::protobuf::FieldDescriptor* field)
50{
51 internal::MessageStack msg_handler(root_message(), message_data(), field);
52
53 if (field)
54 dlog.is(DEBUG2, ENCODE) && dlog << "Starting encode for field: " << field->DebugString()
55 << std::flush;
56
57 // Update root_bits_ to point to the current accumulation BEFORE field_pre_encode and
58 // any_encode so that codecs like CRCCodec can access all bits encoded before this field
59 // via root_bitset(). Save and restore to handle nested message encoding correctly.
60 Bitset* prev_root_bits = manager().codec_data().root_bits_;
61 manager().codec_data().root_bits_ = bits;
62
63 dccl::any wire_value;
64 field_pre_encode(&wire_value, field_value);
65
66 Bitset new_bits;
67 any_encode(&new_bits, wire_value);
68
69 manager().codec_data().root_bits_ = prev_root_bits;
70
71 disp_size(field, new_bits, msg_handler.field_size());
72 bits->append(new_bits);
73
74 if (field)
75 dlog.is(DEBUG2, ENCODE) && dlog << "... produced these " << new_bits.size()
76 << " bits: " << new_bits << std::endl;
77}
78
80 const std::vector<dccl::any>& field_values,
81 const google::protobuf::FieldDescriptor* field)
82{
83 internal::MessageStack msg_handler(root_message(), message_data(), field);
84
85 std::vector<dccl::any> wire_values;
86 field_pre_encode_repeated(&wire_values, field_values);
87
88 Bitset new_bits;
89 any_encode_repeated(&new_bits, wire_values);
90 disp_size(field, new_bits, msg_handler.field_size(), wire_values.size());
91 bits->append(new_bits);
92}
93
94void dccl::FieldCodecBase::base_size(unsigned* bit_size, const google::protobuf::Message& msg,
95 MessagePart part)
96{
97 BaseRAII scoped_globals(this, part, &msg);
98
99 *bit_size = 0;
100
101 field_size(bit_size, &msg, nullptr);
102}
103
104void dccl::FieldCodecBase::field_size(unsigned* bit_size, const dccl::any& field_value,
105 const google::protobuf::FieldDescriptor* field)
106{
107 internal::MessageStack msg_handler(root_message(), message_data(), field);
108
109 dccl::any wire_value;
110 field_pre_encode(&wire_value, field_value);
111
112 *bit_size += any_size(wire_value);
113}
114
116 const std::vector<dccl::any>& field_values,
117 const google::protobuf::FieldDescriptor* field)
118{
119 internal::MessageStack msg_handler(root_message(), message_data(), field);
120
121 std::vector<dccl::any> wire_values;
122 field_pre_encode_repeated(&wire_values, field_values);
123
124 *bit_size += any_size_repeated(wire_values);
125}
126
127void dccl::FieldCodecBase::base_decode(Bitset* bits, google::protobuf::Message* field_value,
128 MessagePart part)
129{
130 BaseRAII scoped_globals(this, part, field_value);
131 // Reset the accumulated decoded bits and point root_bits_ to it so that codecs like
132 // CRCCodec can access all bits decoded before their own field via root_bitset().
133 // decoded_bits_ is populated incrementally by field_decode() for each field.
134 manager().codec_data().decoded_bits_.clear();
135 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
136 dccl::any value(field_value);
137 field_decode(bits, &value, nullptr);
138}
139
140void dccl::FieldCodecBase::field_decode(Bitset* bits, dccl::any* field_value,
141 const google::protobuf::FieldDescriptor* field)
142{
143 internal::MessageStack msg_handler(root_message(), message_data(), field);
144
145 if (!field_value)
146 throw(Exception("Decode called with NULL dccl::any"));
147 else if (!bits)
148 throw(Exception("Decode called with NULL Bitset"));
149
150 if (field)
151 dlog.is(DEBUG2, DECODE) && dlog << "Starting decode for field: " << field->DebugString()
152 << std::flush;
153
154 if (root_message())
155 dlog.is(DEBUG3, DECODE) && dlog << "Message thus far is: " << root_message()->DebugString()
156 << std::flush;
157
158 Bitset these_bits(bits);
159
160 unsigned bits_to_transfer = 0;
161 field_min_size(&bits_to_transfer, field);
162 these_bits.get_more_bits(bits_to_transfer);
163
164 if (field)
165 dlog.is(DEBUG2, DECODE) && dlog << "... using these bits: " << these_bits << std::endl;
166
167 dccl::any wire_value = *field_value;
168
169 if (field)
170 {
171 // For field-level decodes: root_bits_ must point to decoded_bits_ (all bits decoded by
172 // previous sibling fields) so that codecs like CRCCodec can verify their value.
173 // Save and restore root_bits_ to handle nested message decoding correctly.
174 Bitset* prev_root_bits = manager().codec_data().root_bits_;
175 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
176
177 any_decode(&these_bits, &wire_value);
178 field_post_decode(wire_value, field_value);
179
180 // Append this field's bits to decoded_bits_ so the next sibling field sees them.
181 manager().codec_data().decoded_bits_.append(these_bits);
182
183 manager().codec_data().root_bits_ = prev_root_bits;
184 }
185 else
186 {
187 // Message-level decode: don't add to decoded_bits_ (sub-field calls will do that).
188 any_decode(&these_bits, &wire_value);
189 field_post_decode(wire_value, field_value);
190 }
191}
192
193void dccl::FieldCodecBase::field_decode_repeated(Bitset* bits, std::vector<dccl::any>* field_values,
194 const google::protobuf::FieldDescriptor* field)
195{
196 internal::MessageStack msg_handler(root_message(), message_data(), field);
197
198 if (!field_values)
199 throw(Exception("Decode called with NULL field_values"));
200 else if (!bits)
201 throw(Exception("Decode called with NULL Bitset"));
202
203 if (field)
204 dlog.is(DEBUG2, DECODE) &&
205 dlog << "Starting repeated decode for field: " << field->DebugString() << std::endl;
206
207 Bitset these_bits(bits);
208
209 unsigned bits_to_transfer = 0;
210 field_min_size(&bits_to_transfer, field);
211 these_bits.get_more_bits(bits_to_transfer);
212
213 dlog.is(DEBUG2, DECODE) && dlog << "using these " << these_bits.size()
214 << " bits: " << these_bits << std::endl;
215
216 std::vector<dccl::any> wire_values = *field_values;
217 any_decode_repeated(&these_bits, &wire_values);
218
219 field_values->clear();
220 field_post_decode_repeated(wire_values, field_values);
221}
222
224 const google::protobuf::Descriptor* desc, MessagePart part)
225{
226 BaseRAII scoped_globals(this, part, desc);
227 *bit_size = 0;
228
229 internal::MessageStack msg_handler(root_message(), message_data());
230 if (desc)
231 msg_handler.push(desc);
232 else
233 throw(Exception("Max Size called with NULL Descriptor"));
234
235 field_max_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
236}
237
239 const google::protobuf::FieldDescriptor* field)
240{
241 internal::MessageStack msg_handler(root_message(), message_data(), field);
242
243 if (this_field())
244 *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
245 else
246 *bit_size += max_size();
247}
248
250 const google::protobuf::Descriptor* desc, MessagePart part)
251{
252 BaseRAII scoped_globals(this, part, desc);
253
254 *bit_size = 0;
255
256 internal::MessageStack msg_handler(root_message(), message_data());
257 if (desc)
258 msg_handler.push(desc);
259 else
260 throw(Exception("Min Size called with NULL Descriptor"));
261
262 field_min_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
263}
264
266 const google::protobuf::FieldDescriptor* field)
267
268{
269 internal::MessageStack msg_handler(root_message(), message_data(), field);
270
271 if (this_field())
272 *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
273 else
274 *bit_size += min_size();
275}
276
277void dccl::FieldCodecBase::base_validate(const google::protobuf::Descriptor* desc, MessagePart part)
278{
279 BaseRAII scoped_globals(this, part, desc);
280
281 internal::MessageStack msg_handler(root_message(), message_data());
282 if (desc)
283 msg_handler.push(desc);
284 else
285 throw(Exception("Validate called with NULL Descriptor"));
286
287 bool b = false;
288 field_validate(&b, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
289}
290
292 const google::protobuf::FieldDescriptor* field)
293{
294 internal::MessageStack msg_handler(root_message(), message_data(), field);
295
296 if (field && dccl_field_options().in_head() && variable_size())
297 throw(Exception("Variable size codec used in header - header fields must be encoded with "
298 "fixed size codec."));
299
300 if (field && dccl_field_options().in_head() && is_part_of_oneof(field))
301 throw(Exception(
302 "Oneof field used in header - oneof fields cannot be encoded in the header."));
303
304 validate();
305}
306
307void dccl::FieldCodecBase::base_info(std::ostream* os, const google::protobuf::Descriptor* desc,
308 MessagePart part)
309{
310 BaseRAII scoped_globals(this, part, desc);
311
312 internal::MessageStack msg_handler(root_message(), message_data());
313 if (desc)
314 msg_handler.push(desc);
315 else
316 throw(Exception("info called with NULL Descriptor"));
317
318 field_info(os, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
319}
320
322 const google::protobuf::FieldDescriptor* field)
323{
324 internal::MessageStack msg_handler(root_message(), message_data(), field);
325
326 std::stringstream ss;
327 int depth = msg_handler.count();
328
329 std::string name = ((this_field()) ? std::to_string(this_field()->number()) + ". " +
330 std::string(this_field()->name())
331 : std::string(this_descriptor()->full_name()));
332 if (this_field() && this_field()->is_repeated())
333 name += "[" +
334 (dccl_field_options().has_min_repeat()
335 ? (std::to_string(dccl_field_options().min_repeat()) + "-")
336 : "") +
337 std::to_string(dccl_field_options().max_repeat()) + "]";
338
339 if (!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
340 depth -= 1;
341
342 const int spaces = 8;
343 std::string indent =
344 std::string(spaces * (depth) + spaces / 2 * (field && is_part_of_oneof(field)),
345 ' '); // Add 4 spaces of indentation for fields belonging to oneofs
346
347 const int full_width = 40;
348
349 bool is_zero_size = false;
350
351 std::stringstream range;
352 if (variable_size())
353 {
354 unsigned max_sz = 0, min_sz = 0;
355 field_max_size(&max_sz, field);
356 field_min_size(&min_sz, field);
357 if (!max_sz)
358 is_zero_size = true;
359 range << min_sz << "-" << max_sz;
360 }
361 else
362 {
363 unsigned sz = 0;
364 field_max_size(&sz, field);
365 if (!sz)
366 is_zero_size = true;
367 range << sz;
368 }
369
370 int width = this_field() ? full_width - name.size() : full_width - name.size() + spaces;
371 ss << indent << name << std::setfill('.') << std::setw(std::max(1, width)) << range.str()
372 << " {"
373 << (this_field() ? manager()
374 .find(this_field(), codec_version(), has_codec_group(), codec_group())
375 ->name()
376 : manager().find(manager().codec_data().root_descriptor_)->name())
377 << "}";
378
379 if (!is_zero_size)
380 *os << ss.str() << "\n";
381
382 std::string specific_info = info();
383 if (!specific_info.empty())
384 *os << specific_info;
385}
386
387void dccl::FieldCodecBase::base_hash(std::size_t* hash, const google::protobuf::Descriptor* desc,
388 MessagePart part)
389{
390 BaseRAII scoped_globals(this, part, desc);
391
392 internal::MessageStack msg_handler(root_message(), message_data());
393 if (desc)
394 msg_handler.push(desc);
395 else
396 throw(Exception("Hash called with NULL Descriptor"));
397
398 field_hash(hash, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
399}
400
401void dccl::FieldCodecBase::field_hash(std::size_t* hash_value,
402 const google::protobuf::FieldDescriptor* field)
403{
404 internal::MessageStack msg_handler(root_message(), message_data(), field);
405
406 if (field && dccl_field_options().in_head() && variable_size())
407 throw(Exception("Variable size codec used in header - header fields must be encoded with "
408 "fixed size codec."));
409
410 if (field && dccl_field_options().in_head() && is_part_of_oneof(field))
411 throw(Exception(
412 "Oneof field used in header - oneof fields cannot be encoded in the header."));
413
414 if (this_field())
415 {
416 google::protobuf::FieldDescriptorProto field_to_hash;
417 this_field()->CopyTo(&field_to_hash);
418
419 // name doesn't affect encoding
420 field_to_hash.clear_name();
421 // we will handle dccl options separately, non-dccl options don't affect encoding
422 field_to_hash.clear_options();
423 field_to_hash.clear_type_name();
424 field_to_hash.clear_default_value();
425
426 dccl::DCCLFieldOptions dccl_opts = dccl_field_options();
427
428 hash_combine(*hash_value, field_to_hash.DebugString());
429 hash_combine(*hash_value, dccl_opts.DebugString());
430 }
431 else
432 {
433 // root level message
434 dccl::DCCLMessageOptions dccl_opts = this_descriptor()->options().GetExtension(dccl::msg);
435 dccl_opts.clear_max_bytes(); // max bytes doesn't affect encoding
436 dccl_opts.clear_dynamic_conditions(); // dynamic conditions don't affect wire format
437
438 hash_combine(*hash_value, dccl_opts.DebugString());
439 }
440
441 hash_combine(*hash_value, hash());
442}
443
444std::string dccl::FieldCodecBase::codec_group(const google::protobuf::Descriptor* desc)
445{
446 if (desc->options().GetExtension(dccl::msg).has_codec_group())
447 return desc->options().GetExtension(dccl::msg).codec_group();
448 else
449 return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
450}
451
452//
453// FieldCodecBase protected
454//
455
456std::string dccl::FieldCodecBase::info() { return std::string(); }
457
458void dccl::FieldCodecBase::any_encode_repeated(dccl::Bitset* bits,
459 const std::vector<dccl::any>& wire_values)
460{
461 // out_bits = [field_values[2]][field_values[1]][field_values[0]]
462
463 unsigned wire_vector_size = dccl_field_options().max_repeat();
464
465 if (wire_values.size() > wire_vector_size && strict())
466 throw(
467 dccl::OutOfRangeException(std::string("Repeated size exceeds max_repeat for field: ") +
468 FieldCodecBase::this_field()->DebugString(),
469 this->this_field(), this->this_descriptor()));
470
471 if (wire_values.size() < dccl_field_options().min_repeat() && strict())
473 std::string("Repeated size is less than min_repeat for field: ") +
474 FieldCodecBase::this_field()->DebugString(),
475 this->this_field(), this->this_descriptor()));
476
477 // for DCCL3 and beyond, add a prefix numeric field giving the vector size (rather than always going to max_repeat)
478 if (codec_version() > 2)
479 {
480 wire_vector_size = std::min(static_cast<int>(dccl_field_options().max_repeat()),
481 static_cast<int>(wire_values.size()));
482
483 wire_vector_size = std::max(static_cast<int>(dccl_field_options().min_repeat()),
484 static_cast<int>(wire_vector_size));
485
486 Bitset size_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
487 dccl_field_options().max_repeat()),
488 wire_vector_size - dccl_field_options().min_repeat());
489 bits->append(size_bits);
490
491 dlog.is(DEBUG2, ENCODE) && dlog << "repeated size field ... produced these "
492 << size_bits.size() << " bits: " << size_bits << std::endl;
493 }
494
495 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
496 for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
497 {
498 msg_handler.update_index(root_message(), this->this_field(), i);
499
500 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
501 dc.set_repeated_index(i);
502 if (dc.has_omit_if())
503 {
504 dc.regenerate(this_message(), root_message(), i);
505 if (dc.omit())
506 continue;
507 }
508
509 Bitset new_bits;
510 if (i < wire_values.size())
511 any_encode(&new_bits, wire_values[i]);
512 else
513 any_encode(&new_bits, dccl::any());
514 bits->append(new_bits);
515 }
516}
517
518void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits,
519 std::vector<dccl::any>* wire_values)
520{
521 unsigned wire_vector_size = dccl_field_options().max_repeat();
522 if (codec_version() > 2)
523 {
524 Bitset size_bits(repeated_bits);
525 size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
526 dccl_field_options().max_repeat()));
527
528 wire_vector_size = size_bits.to_ulong() + dccl_field_options().min_repeat();
529 }
530
531 wire_values->resize(wire_vector_size);
532
533 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
534 for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
535 {
536 msg_handler.update_index(root_message(), this->this_field(), i);
537
538 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
539 dc.set_repeated_index(i);
540 if (dc.has_omit_if())
541 {
542 dc.regenerate(this_message(), root_message(), i);
543 if (dc.omit())
544 continue;
545 }
546
547 Bitset these_bits(repeated_bits);
548 these_bits.get_more_bits(min_size());
549 any_decode(&these_bits, &(*wire_values)[i]);
550 }
551}
552
553unsigned dccl::FieldCodecBase::any_size_repeated(const std::vector<dccl::any>& wire_values)
554{
555 unsigned out = 0;
556 unsigned wire_vector_size = dccl_field_options().max_repeat();
557
558 if (codec_version() > 2)
559 {
560 wire_vector_size = std::min(static_cast<int>(dccl_field_options().max_repeat()),
561 static_cast<int>(wire_values.size()));
562 out += repeated_vector_field_size(dccl_field_options().min_repeat(),
563 dccl_field_options().max_repeat());
564 }
565
566 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
567 for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
568 {
569 msg_handler.update_index(root_message(), this->this_field(), i);
570 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
571 dc.set_repeated_index(i);
572 if (dc.has_omit_if())
573 {
574 dc.regenerate(this_message(), root_message(), i);
575 if (dc.omit())
576 continue;
577 }
578
579 if (i < wire_values.size())
580 out += any_size(wire_values[i]);
581 else
582 out += any_size(dccl::any());
583 }
584 return out;
585}
586
587void dccl::FieldCodecBase::check_repeat_settings() const
588{
589 if (!dccl_field_options().has_max_repeat())
590 throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field: " +
591 this_field()->DebugString(),
592 this->this_descriptor()));
593 else if (dccl_field_options().max_repeat() < 1)
594 throw(Exception("(dccl.field).max_repeat must not be less than 1: " +
595 this_field()->DebugString(),
596 this->this_descriptor()));
597 else if (dccl_field_options().max_repeat() < dccl_field_options().min_repeat())
598 throw(Exception("(dccl.field).max_repeat must not be less than (dccl.field).min_repeat: " +
599 this_field()->DebugString(),
600 this->this_descriptor()));
601}
602
603unsigned dccl::FieldCodecBase::max_size_repeated()
604{
605 check_repeat_settings();
606
607 if (codec_version() > 2)
608 return repeated_vector_field_size(dccl_field_options().min_repeat(),
609 dccl_field_options().max_repeat()) +
610 max_size() * dccl_field_options().max_repeat();
611 else
612 return max_size() * dccl_field_options().max_repeat();
613}
614
615unsigned dccl::FieldCodecBase::min_size_repeated()
616{
617 check_repeat_settings();
618
619 if (codec_version() > 2)
620 return repeated_vector_field_size(dccl_field_options().min_repeat(),
621 dccl_field_options().max_repeat()) +
622 min_size() * dccl_field_options().min_repeat();
623
624 else
625 return min_size() * dccl_field_options().max_repeat();
626}
627
628void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
629 const std::vector<dccl::any>& field_values)
630{
631 for (const auto& field_value : field_values)
632 {
633 dccl::any wire_value;
634 any_pre_encode(&wire_value, field_value);
635 wire_values->push_back(wire_value);
636 }
637}
638void dccl::FieldCodecBase::any_post_decode_repeated(const std::vector<dccl::any>& wire_values,
639 std::vector<dccl::any>* field_values)
640{
641 for (const auto& wire_value : wire_values)
642 {
643 dccl::any field_value;
644 any_post_decode(wire_value, &field_value);
645 field_values->push_back(field_value);
646 }
647}
648
649//
650// FieldCodecBase private
651//
652
653void dccl::FieldCodecBase::disp_size(const google::protobuf::FieldDescriptor* field,
654 const Bitset& new_bits, int depth, int vector_size /* = -1 */)
655{
656 if (!root_descriptor())
657 return;
658
659 if (dlog.check(DEBUG2))
660 {
661 std::string name =
662 ((field) ? std::string(field->name()) : std::string(root_descriptor()->full_name()));
663 if (vector_size >= 0)
664 name += "[" + std::to_string(vector_size) + "]";
665
666 dlog.is(DEBUG2, SIZE) && dlog << std::string(depth, '|') << name << std::setfill('.')
667 << std::setw(40 - name.size() - depth) << new_bits.size()
668 << std::endl;
669
670 if (!field)
671 dlog.is(DEBUG2, SIZE) && dlog << std::endl;
672 }
673}
674
675std::ostream& dccl::operator<<(std::ostream& os, const dccl::FieldCodecBase& field_codec)
676{
677 using google::protobuf::FieldDescriptor;
678 return os << "[FieldCodec '" << field_codec.name() << "']: field type: "
679 << field_codec.manager().type_helper().find(field_codec.field_type())->as_str()
680 << " ("
681 << field_codec.manager()
682 .type_helper()
683 .find(FieldDescriptor::TypeToCppType(field_codec.field_type()))
684 ->as_str()
685 << ") | wire type: "
686 << field_codec.manager().type_helper().find(field_codec.wire_type())->as_str();
687}
688
689const google::protobuf::FieldDescriptor* dccl::FieldCodecBase::this_field() const
690{
691 return message_data().top_field();
692}
693
694const google::protobuf::Descriptor* dccl::FieldCodecBase::this_descriptor() const
695{
696 return message_data().top_descriptor();
697}
698
699const google::protobuf::Message* dccl::FieldCodecBase::this_message()
700{
701 return message_data().top_message();
702}
703
704const google::protobuf::Message* dccl::FieldCodecBase::root_message()
705{
706 return manager().codec_data().root_message_;
707}
708
709const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor() const
710{
711 return manager().codec_data().root_descriptor_;
712}
713
715{
716 return manager().codec_data().root_bits_;
717}
718
719dccl::internal::MessageStackData& dccl::FieldCodecBase::message_data()
720{
721 return manager().codec_data().message_data_;
722}
723
724const dccl::internal::MessageStackData& dccl::FieldCodecBase::message_data() const
725{
726 return manager().codec_data().message_data_;
727}
728bool dccl::FieldCodecBase::has_codec_group()
729{
730 const google::protobuf::Descriptor* root_desc = root_descriptor();
731 if (root_desc)
732 {
733 return root_desc->options().GetExtension(dccl::msg).has_codec_group() ||
734 root_desc->options().GetExtension(dccl::msg).has_codec_version();
735 }
736 else
737 return false;
738}
739
740dccl::MessagePart dccl::FieldCodecBase::part() { return manager().codec_data().part_; }
741
742bool dccl::FieldCodecBase::strict() { return manager().codec_data().strict_; }
743
744int dccl::FieldCodecBase::codec_version()
745{
746 return root_descriptor()->options().GetExtension(dccl::msg).codec_version();
747}
748
749std::string dccl::FieldCodecBase::codec_group() { return codec_group(root_descriptor()); }
750
752dccl::FieldCodecBase::dynamic_conditions(const google::protobuf::FieldDescriptor* field)
753{
754 manager().codec_data().dynamic_conditions_.set_field(field);
755 return manager().codec_data().dynamic_conditions_;
756}
757
758dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
759 const google::protobuf::Descriptor* root_descriptor,
760 bool strict)
761 : field_codec_(field_codec)
762
763{
764 field_codec_->manager().codec_data().part_ = part;
765 field_codec_->manager().codec_data().strict_ = strict;
766 field_codec_->manager().codec_data().root_message_ = nullptr;
767 field_codec_->manager().codec_data().root_descriptor_ = root_descriptor;
768}
769dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
770 const google::protobuf::Message* root_message, bool strict)
771 : field_codec_(field_codec)
772
773{
774 field_codec_->manager().codec_data().part_ = part;
775 field_codec_->manager().codec_data().strict_ = strict;
776 field_codec_->manager().codec_data().root_message_ = root_message;
777 field_codec_->manager().codec_data().root_descriptor_ = root_message->GetDescriptor();
778}
779dccl::FieldCodecBase::BaseRAII::~BaseRAII()
780{
781 field_codec_->manager().codec_data().part_ = dccl::UNKNOWN;
782 field_codec_->manager().codec_data().strict_ = false;
783 field_codec_->manager().codec_data().root_message_ = nullptr;
784 field_codec_->manager().codec_data().root_descriptor_ = nullptr;
785 field_codec_->manager().codec_data().root_bits_ = nullptr;
786 field_codec_->manager().codec_data().decoded_bits_.clear();
787}
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition bitset.h:43
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition bitset.h:420
Bitset & append(const Bitset &bits)
Adds the bitset to the big end.
Definition bitset.h:361
Exception class for DCCL.
Definition exception.h:47
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition field_codec.h:53
const Bitset * root_bitset() const
Returns the root Bitset for the current encode or decode operation.
void field_encode(Bitset *bits, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Encode a non-repeated field.
void field_size(unsigned *bit_size, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
void base_hash(std::size_t *hash, const google::protobuf::Descriptor *desc, MessagePart part)
Provide a hash of the DCCL message definition to detect changes in the DCCL message.
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
google::protobuf::FieldDescriptor::CppType wire_type() const
the C++ type used "on the wire". This is the type visible after pre_encode and before post_decode fun...
Definition field_codec.h:74
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
MessagePart part()
the part of the message currently being encoded (head or body)
void field_encode_repeated(Bitset *bits, const std::vector< dccl::any > &field_values, const google::protobuf::FieldDescriptor *field)
Encode a repeated field.
std::string name() const
the name of the codec used to identifier it in the .proto custom option extension
Definition field_codec.h:65
void base_validate(const google::protobuf::Descriptor *desc, MessagePart part)
Validate this part of the message to make sure all required extensions are set.
void field_decode(Bitset *bits, dccl::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
void base_info(std::ostream *os, const google::protobuf::Descriptor *desc, MessagePart part)
Get human readable information (size of fields, etc.) about this part of the DCCL message.
void base_min_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the minimum size of a message given its Descriptor alone (no data)
void base_max_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the maximum size of a message given its Descriptor alone (no data)
void field_hash(std::size_t *hash, const google::protobuf::FieldDescriptor *field)
Provide a hash for this field definition.
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
void base_size(unsigned *bit_size, const google::protobuf::Message &msg, MessagePart part)
Calculate the size (in bits) of a part of the base message when it is encoded.
google::protobuf::FieldDescriptor::Type field_type() const
the type exposed to the user in the original and decoded Protobuf messages
Definition field_codec.h:69
void field_min_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the lower bound on this field's size (in bits)
void base_encode(Bitset *bits, const google::protobuf::Message &msg, MessagePart part, bool strict)
Encode this part (body or head) of the base message.
void field_validate(bool *b, const google::protobuf::FieldDescriptor *field)
Validate this field, checking that all required option extensions are set (e.g. (dccl....
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field's size (in bits)
void field_decode_repeated(Bitset *bits, std::vector< dccl::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
void field_size_repeated(unsigned *bit_size, const std::vector< dccl::any > &field_values, const google::protobuf::FieldDescriptor *field)
Calculate the size of a repeated field.
void field_info(std::ostream *os, const google::protobuf::FieldDescriptor *field)
Write human readable information about the field and its bounds to the provided stream.
bool is(logger::Verbosity verbosity, logger::Group group=logger::GENERAL)
Indicates the verbosity of the Logger until the next std::flush or std::endl. The boolean return is u...
Definition logger.h:191
bool check(logger::Verbosity verbosity)
Same as is() but doesn't set the verbosity or lock the mutex.
Definition logger.h:180
bool is_part_of_oneof(const google::protobuf::FieldDescriptor *field_desc)
Checks whether a given field is part to a oneof or not.
Definition oneof.h:35
void hash_combine(std::size_t &seed, const T &v)
hash combine - from boost::hash_combine
Definition common.h:152