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
127namespace
128{
129// Number of bits of the part that have been decoded already, that is, everything up to the field
130// about to be decoded: the part as a whole less whatever is still buffered in the Bitsets it feeds.
131std::ptrdiff_t decoded_offset(const dccl::Bitset& bits, const dccl::Bitset& part_bits)
132{
133 std::ptrdiff_t buffered = 0;
134 for (const dccl::Bitset* b = &bits; b; b = b->parent()) buffered += b->size();
135
136 return static_cast<std::ptrdiff_t>(part_bits.size()) - buffered;
137}
138
139// Brings decoded_bits_ up to the field about to be decoded, so that a codec like CRCCodec sees
140// exactly the bits its preceding fields were encoded from. They are copied out of the snapshot
141// taken in base_decode() rather than read back out of the Bitsets the fields decoded from, because
142// codecs are free to shift or otherwise modify those while decoding.
143void update_decoded_bits(dccl::internal::CodecData& codec_data, const dccl::Bitset& bits)
144{
145 const dccl::Bitset& part_bits = codec_data.part_bits_;
146 dccl::Bitset& decoded = codec_data.decoded_bits_;
147
148 auto offset = decoded_offset(bits, part_bits);
149 if (offset < static_cast<std::ptrdiff_t>(decoded.size()) ||
150 offset > static_cast<std::ptrdiff_t>(part_bits.size()))
151 return;
152
153 for (auto i = decoded.size(); i < static_cast<dccl::Bitset::size_type>(offset); ++i)
154 decoded.push_back(part_bits[i]);
155}
156
157} // namespace
158
159void dccl::FieldCodecBase::base_decode(Bitset* bits, google::protobuf::Message* field_value,
160 MessagePart part)
161{
162 BaseRAII scoped_globals(this, part, field_value);
163 // Reset the accumulated decoded bits and point root_bits_ to it so that codecs like
164 // CRCCodec can access all bits decoded before their own field via root_bitset().
165 // decoded_bits_ is populated incrementally by field_decode() for each field, using
166 // part_bits_ as the reference copy of the part being decoded.
167 manager().codec_data().decoded_bits_.clear();
168 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
169 manager().codec_data().part_bits_ = *bits;
170 dccl::any value(field_value);
171 field_decode(bits, &value, nullptr);
172}
173
174void dccl::FieldCodecBase::field_decode(Bitset* bits, dccl::any* field_value,
175 const google::protobuf::FieldDescriptor* field)
176{
177 internal::MessageStack msg_handler(root_message(), message_data(), field);
178
179 if (!field_value)
180 throw(Exception("Decode called with NULL dccl::any"));
181 else if (!bits)
182 throw(Exception("Decode called with NULL Bitset"));
183
184 if (field)
185 dlog.is(DEBUG2, DECODE) && dlog << "Starting decode for field: " << field->DebugString()
186 << std::flush;
187
188 if (root_message())
189 dlog.is(DEBUG3, DECODE) && dlog << "Message thus far is: " << root_message()->DebugString()
190 << std::flush;
191
192 // Fields of the root message only: the bits of a field of an embedded message are accounted
193 // for by the embedded message field as a whole.
194 if (field && msg_handler.field_size() == 1)
195 update_decoded_bits(manager().codec_data(), *bits);
196
197 Bitset these_bits(bits);
198
199 unsigned bits_to_transfer = 0;
200 field_min_size(&bits_to_transfer, field);
201 these_bits.get_more_bits(bits_to_transfer);
202
203 if (field)
204 dlog.is(DEBUG2, DECODE) && dlog << "... using these bits: " << these_bits << std::endl;
205
206 dccl::any wire_value = *field_value;
207
208 if (field)
209 {
210 // For field-level decodes: root_bits_ must point to decoded_bits_ (all bits decoded by
211 // previous sibling fields) so that codecs like CRCCodec can verify their value.
212 // Save and restore root_bits_ to handle nested message decoding correctly.
213 Bitset* prev_root_bits = manager().codec_data().root_bits_;
214 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
215
216 any_decode(&these_bits, &wire_value);
217 field_post_decode(wire_value, field_value);
218
219 manager().codec_data().root_bits_ = prev_root_bits;
220 }
221 else
222 {
223 // Message-level decode: don't add to decoded_bits_ (sub-field calls will do that).
224 any_decode(&these_bits, &wire_value);
225 field_post_decode(wire_value, field_value);
226 }
227}
228
229void dccl::FieldCodecBase::field_decode_repeated(Bitset* bits, std::vector<dccl::any>* field_values,
230 const google::protobuf::FieldDescriptor* field)
231{
232 internal::MessageStack msg_handler(root_message(), message_data(), field);
233
234 if (!field_values)
235 throw(Exception("Decode called with NULL field_values"));
236 else if (!bits)
237 throw(Exception("Decode called with NULL Bitset"));
238
239 if (field)
240 dlog.is(DEBUG2, DECODE) &&
241 dlog << "Starting repeated decode for field: " << field->DebugString() << std::endl;
242
243 if (field && msg_handler.field_size() == 1)
244 update_decoded_bits(manager().codec_data(), *bits);
245
246 Bitset these_bits(bits);
247
248 unsigned bits_to_transfer = 0;
249 field_min_size(&bits_to_transfer, field);
250 these_bits.get_more_bits(bits_to_transfer);
251
252 dlog.is(DEBUG2, DECODE) && dlog << "using these " << these_bits.size()
253 << " bits: " << these_bits << std::endl;
254
255 Bitset* prev_root_bits = manager().codec_data().root_bits_;
256 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
257
258 std::vector<dccl::any> wire_values = *field_values;
259 any_decode_repeated(&these_bits, &wire_values);
260
261 field_values->clear();
262 field_post_decode_repeated(wire_values, field_values);
263
264 manager().codec_data().root_bits_ = prev_root_bits;
265}
266
268 const google::protobuf::Descriptor* desc, MessagePart part)
269{
270 BaseRAII scoped_globals(this, part, desc);
271 *bit_size = 0;
272
273 internal::MessageStack msg_handler(root_message(), message_data());
274 if (desc)
275 msg_handler.push(desc);
276 else
277 throw(Exception("Max Size called with NULL Descriptor"));
278
279 field_max_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
280}
281
283 const google::protobuf::FieldDescriptor* field)
284{
285 internal::MessageStack msg_handler(root_message(), message_data(), field);
286
287 if (this_field())
288 *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
289 else
290 *bit_size += max_size();
291}
292
294 const google::protobuf::Descriptor* desc, MessagePart part)
295{
296 BaseRAII scoped_globals(this, part, desc);
297
298 *bit_size = 0;
299
300 internal::MessageStack msg_handler(root_message(), message_data());
301 if (desc)
302 msg_handler.push(desc);
303 else
304 throw(Exception("Min Size called with NULL Descriptor"));
305
306 field_min_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
307}
308
310 const google::protobuf::FieldDescriptor* field)
311
312{
313 internal::MessageStack msg_handler(root_message(), message_data(), field);
314
315 if (this_field())
316 *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
317 else
318 *bit_size += min_size();
319}
320
321void dccl::FieldCodecBase::base_validate(const google::protobuf::Descriptor* desc, MessagePart part)
322{
323 BaseRAII scoped_globals(this, part, desc);
324
325 internal::MessageStack msg_handler(root_message(), message_data());
326 if (desc)
327 msg_handler.push(desc);
328 else
329 throw(Exception("Validate called with NULL Descriptor"));
330
331 bool b = false;
332 field_validate(&b, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
333}
334
336 const google::protobuf::FieldDescriptor* field)
337{
338 internal::MessageStack msg_handler(root_message(), message_data(), field);
339
340 if (field && dccl_field_options().in_head() && variable_size())
341 throw(Exception("Variable size codec used in header - header fields must be encoded with "
342 "fixed size codec."));
343
344 if (field && dccl_field_options().in_head() && is_part_of_oneof(field))
345 throw(Exception(
346 "Oneof field used in header - oneof fields cannot be encoded in the header."));
347
348 validate();
349}
350
351void dccl::FieldCodecBase::base_info(std::ostream* os, const google::protobuf::Descriptor* desc,
352 MessagePart part)
353{
354 BaseRAII scoped_globals(this, part, desc);
355
356 internal::MessageStack msg_handler(root_message(), message_data());
357 if (desc)
358 msg_handler.push(desc);
359 else
360 throw(Exception("info called with NULL Descriptor"));
361
362 field_info(os, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
363}
364
366 const google::protobuf::FieldDescriptor* field)
367{
368 internal::MessageStack msg_handler(root_message(), message_data(), field);
369
370 std::stringstream ss;
371 int depth = msg_handler.count();
372
373 std::string name = ((this_field()) ? std::to_string(this_field()->number()) + ". " +
374 std::string(this_field()->name())
375 : std::string(this_descriptor()->full_name()));
376 if (this_field() && this_field()->is_repeated())
377 name += "[" +
378 (dccl_field_options().has_min_repeat()
379 ? (std::to_string(dccl_field_options().min_repeat()) + "-")
380 : "") +
381 std::to_string(dccl_field_options().max_repeat()) + "]";
382
383 if (!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
384 depth -= 1;
385
386 const int spaces = 8;
387 std::string indent =
388 std::string(spaces * (depth) + spaces / 2 * (field && is_part_of_oneof(field)),
389 ' '); // Add 4 spaces of indentation for fields belonging to oneofs
390
391 const int full_width = 40;
392
393 bool is_zero_size = false;
394
395 std::stringstream range;
396 if (variable_size())
397 {
398 unsigned max_sz = 0, min_sz = 0;
399 field_max_size(&max_sz, field);
400 field_min_size(&min_sz, field);
401 if (!max_sz)
402 is_zero_size = true;
403 range << min_sz << "-" << max_sz;
404 }
405 else
406 {
407 unsigned sz = 0;
408 field_max_size(&sz, field);
409 if (!sz)
410 is_zero_size = true;
411 range << sz;
412 }
413
414 int width = this_field() ? full_width - name.size() : full_width - name.size() + spaces;
415 ss << indent << name << std::setfill('.') << std::setw(std::max(1, width)) << range.str()
416 << " {"
417 << (this_field() ? manager()
418 .find(this_field(), codec_version(), has_codec_group(), codec_group())
419 ->name()
420 : manager().find(manager().codec_data().root_descriptor_)->name())
421 << "}";
422
423 if (!is_zero_size)
424 *os << ss.str() << "\n";
425
426 std::string specific_info = info();
427 if (!specific_info.empty())
428 *os << specific_info;
429}
430
431void dccl::FieldCodecBase::base_hash(std::size_t* hash, const google::protobuf::Descriptor* desc,
432 MessagePart part)
433{
434 BaseRAII scoped_globals(this, part, desc);
435
436 internal::MessageStack msg_handler(root_message(), message_data());
437 if (desc)
438 msg_handler.push(desc);
439 else
440 throw(Exception("Hash called with NULL Descriptor"));
441
442 field_hash(hash, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
443}
444
445void dccl::FieldCodecBase::field_hash(std::size_t* hash_value,
446 const google::protobuf::FieldDescriptor* field)
447{
448 internal::MessageStack msg_handler(root_message(), message_data(), field);
449
450 if (field && dccl_field_options().in_head() && variable_size())
451 throw(Exception("Variable size codec used in header - header fields must be encoded with "
452 "fixed size codec."));
453
454 if (field && dccl_field_options().in_head() && is_part_of_oneof(field))
455 throw(Exception(
456 "Oneof field used in header - oneof fields cannot be encoded in the header."));
457
458 if (this_field())
459 {
460 google::protobuf::FieldDescriptorProto field_to_hash;
461 this_field()->CopyTo(&field_to_hash);
462
463 // name doesn't affect encoding
464 field_to_hash.clear_name();
465 // we will handle dccl options separately, non-dccl options don't affect encoding
466 field_to_hash.clear_options();
467 field_to_hash.clear_type_name();
468 field_to_hash.clear_default_value();
469
470 dccl::DCCLFieldOptions dccl_opts = dccl_field_options();
471
472 hash_combine(*hash_value, field_to_hash.DebugString());
473 hash_combine(*hash_value, dccl_opts.DebugString());
474 }
475 else
476 {
477 // root level message
478 dccl::DCCLMessageOptions dccl_opts = this_descriptor()->options().GetExtension(dccl::msg);
479 dccl_opts.clear_max_bytes(); // max bytes doesn't affect encoding
480 dccl_opts.clear_dynamic_conditions(); // dynamic conditions don't affect wire format
481
482 hash_combine(*hash_value, dccl_opts.DebugString());
483 }
484
485 hash_combine(*hash_value, hash());
486}
487
488std::string dccl::FieldCodecBase::codec_group(const google::protobuf::Descriptor* desc)
489{
490 if (desc->options().GetExtension(dccl::msg).has_codec_group())
491 return desc->options().GetExtension(dccl::msg).codec_group();
492 else
493 return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
494}
495
496//
497// FieldCodecBase protected
498//
499
500std::string dccl::FieldCodecBase::info() { return std::string(); }
501
502void dccl::FieldCodecBase::any_encode_repeated(dccl::Bitset* bits,
503 const std::vector<dccl::any>& wire_values)
504{
505 // out_bits = [field_values[2]][field_values[1]][field_values[0]]
506
507 unsigned wire_vector_size = dccl_field_options().max_repeat();
508
509 if (wire_values.size() > wire_vector_size && strict())
510 throw(
511 dccl::OutOfRangeException(std::string("Repeated size exceeds max_repeat for field: ") +
512 FieldCodecBase::this_field()->DebugString(),
513 this->this_field(), this->this_descriptor()));
514
515 if (wire_values.size() < dccl_field_options().min_repeat() && strict())
517 std::string("Repeated size is less than min_repeat for field: ") +
518 FieldCodecBase::this_field()->DebugString(),
519 this->this_field(), this->this_descriptor()));
520
521 // for DCCL3 and beyond, add a prefix numeric field giving the vector size (rather than always going to max_repeat)
522 if (codec_version() > 2)
523 {
524 wire_vector_size = std::min(static_cast<int>(dccl_field_options().max_repeat()),
525 static_cast<int>(wire_values.size()));
526
527 wire_vector_size = std::max(static_cast<int>(dccl_field_options().min_repeat()),
528 static_cast<int>(wire_vector_size));
529
530 Bitset size_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
531 dccl_field_options().max_repeat()),
532 wire_vector_size - dccl_field_options().min_repeat());
533 bits->append(size_bits);
534
535 dlog.is(DEBUG2, ENCODE) && dlog << "repeated size field ... produced these "
536 << size_bits.size() << " bits: " << size_bits << std::endl;
537 }
538
539 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
540 for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
541 {
542 msg_handler.update_index(root_message(), this->this_field(), i);
543
544 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
545 dc.set_repeated_index(i);
546 if (dc.has_omit_if())
547 {
548 dc.regenerate(this_message(), root_message(), i);
549 if (dc.omit())
550 continue;
551 }
552
553 Bitset new_bits;
554 if (i < wire_values.size())
555 any_encode(&new_bits, wire_values[i]);
556 else
557 any_encode(&new_bits, dccl::any());
558 bits->append(new_bits);
559 }
560}
561
562void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits,
563 std::vector<dccl::any>* wire_values)
564{
565 unsigned wire_vector_size = dccl_field_options().max_repeat();
566 if (codec_version() > 2)
567 {
568 Bitset size_bits(repeated_bits);
569 size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
570 dccl_field_options().max_repeat()));
571
572 wire_vector_size = size_bits.to_ulong() + dccl_field_options().min_repeat();
573 }
574
575 wire_values->resize(wire_vector_size);
576
577 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
578 for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
579 {
580 msg_handler.update_index(root_message(), this->this_field(), i);
581
582 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
583 dc.set_repeated_index(i);
584 if (dc.has_omit_if())
585 {
586 dc.regenerate(this_message(), root_message(), i);
587 if (dc.omit())
588 continue;
589 }
590
591 Bitset these_bits(repeated_bits);
592 these_bits.get_more_bits(min_size());
593 any_decode(&these_bits, &(*wire_values)[i]);
594 }
595}
596
597unsigned dccl::FieldCodecBase::any_size_repeated(const std::vector<dccl::any>& wire_values)
598{
599 unsigned out = 0;
600 unsigned wire_vector_size = dccl_field_options().max_repeat();
601
602 if (codec_version() > 2)
603 {
604 wire_vector_size = std::min(static_cast<int>(dccl_field_options().max_repeat()),
605 static_cast<int>(wire_values.size()));
606 out += repeated_vector_field_size(dccl_field_options().min_repeat(),
607 dccl_field_options().max_repeat());
608 }
609
610 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
611 for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
612 {
613 msg_handler.update_index(root_message(), this->this_field(), i);
614 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
615 dc.set_repeated_index(i);
616 if (dc.has_omit_if())
617 {
618 dc.regenerate(this_message(), root_message(), i);
619 if (dc.omit())
620 continue;
621 }
622
623 if (i < wire_values.size())
624 out += any_size(wire_values[i]);
625 else
626 out += any_size(dccl::any());
627 }
628 return out;
629}
630
631void dccl::FieldCodecBase::check_repeat_settings() const
632{
633 if (!dccl_field_options().has_max_repeat())
634 throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field: " +
635 this_field()->DebugString(),
636 this->this_descriptor()));
637 else if (dccl_field_options().max_repeat() < 1)
638 throw(Exception("(dccl.field).max_repeat must not be less than 1: " +
639 this_field()->DebugString(),
640 this->this_descriptor()));
641 else if (dccl_field_options().max_repeat() < dccl_field_options().min_repeat())
642 throw(Exception("(dccl.field).max_repeat must not be less than (dccl.field).min_repeat: " +
643 this_field()->DebugString(),
644 this->this_descriptor()));
645}
646
647unsigned dccl::FieldCodecBase::max_size_repeated()
648{
649 check_repeat_settings();
650
651 if (codec_version() > 2)
652 return repeated_vector_field_size(dccl_field_options().min_repeat(),
653 dccl_field_options().max_repeat()) +
654 max_size() * dccl_field_options().max_repeat();
655 else
656 return max_size() * dccl_field_options().max_repeat();
657}
658
659unsigned dccl::FieldCodecBase::min_size_repeated()
660{
661 check_repeat_settings();
662
663 if (codec_version() > 2)
664 return repeated_vector_field_size(dccl_field_options().min_repeat(),
665 dccl_field_options().max_repeat()) +
666 min_size() * dccl_field_options().min_repeat();
667
668 else
669 return min_size() * dccl_field_options().max_repeat();
670}
671
672void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
673 const std::vector<dccl::any>& field_values)
674{
675 for (const auto& field_value : field_values)
676 {
677 dccl::any wire_value;
678 any_pre_encode(&wire_value, field_value);
679 wire_values->push_back(wire_value);
680 }
681}
682void dccl::FieldCodecBase::any_post_decode_repeated(const std::vector<dccl::any>& wire_values,
683 std::vector<dccl::any>* field_values)
684{
685 for (const auto& wire_value : wire_values)
686 {
687 dccl::any field_value;
688 any_post_decode(wire_value, &field_value);
689 field_values->push_back(field_value);
690 }
691}
692
693//
694// FieldCodecBase private
695//
696
697void dccl::FieldCodecBase::disp_size(const google::protobuf::FieldDescriptor* field,
698 const Bitset& new_bits, int depth, int vector_size /* = -1 */)
699{
700 if (!root_descriptor())
701 return;
702
703 if (dlog.check(DEBUG2))
704 {
705 std::string name =
706 ((field) ? std::string(field->name()) : std::string(root_descriptor()->full_name()));
707 if (vector_size >= 0)
708 name += "[" + std::to_string(vector_size) + "]";
709
710 dlog.is(DEBUG2, SIZE) && dlog << std::string(depth, '|') << name << std::setfill('.')
711 << std::setw(40 - name.size() - depth) << new_bits.size()
712 << std::endl;
713
714 if (!field)
715 dlog.is(DEBUG2, SIZE) && dlog << std::endl;
716 }
717}
718
719std::ostream& dccl::operator<<(std::ostream& os, const dccl::FieldCodecBase& field_codec)
720{
721 using google::protobuf::FieldDescriptor;
722 return os << "[FieldCodec '" << field_codec.name() << "']: field type: "
723 << field_codec.manager().type_helper().find(field_codec.field_type())->as_str()
724 << " ("
725 << field_codec.manager()
726 .type_helper()
727 .find(FieldDescriptor::TypeToCppType(field_codec.field_type()))
728 ->as_str()
729 << ") | wire type: "
730 << field_codec.manager().type_helper().find(field_codec.wire_type())->as_str();
731}
732
733const google::protobuf::FieldDescriptor* dccl::FieldCodecBase::this_field() const
734{
735 return message_data().top_field();
736}
737
738const google::protobuf::Descriptor* dccl::FieldCodecBase::this_descriptor() const
739{
740 return message_data().top_descriptor();
741}
742
743const google::protobuf::Message* dccl::FieldCodecBase::this_message()
744{
745 return message_data().top_message();
746}
747
748const google::protobuf::Message* dccl::FieldCodecBase::root_message()
749{
750 return manager().codec_data().root_message_;
751}
752
753const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor() const
754{
755 return manager().codec_data().root_descriptor_;
756}
757
759{
760 return manager().codec_data().root_bits_;
761}
762
763dccl::internal::MessageStackData& dccl::FieldCodecBase::message_data()
764{
765 return manager().codec_data().message_data_;
766}
767
768const dccl::internal::MessageStackData& dccl::FieldCodecBase::message_data() const
769{
770 return manager().codec_data().message_data_;
771}
772bool dccl::FieldCodecBase::has_codec_group()
773{
774 const google::protobuf::Descriptor* root_desc = root_descriptor();
775 if (root_desc)
776 {
777 return root_desc->options().GetExtension(dccl::msg).has_codec_group() ||
778 root_desc->options().GetExtension(dccl::msg).has_codec_version();
779 }
780 else
781 return false;
782}
783
784dccl::MessagePart dccl::FieldCodecBase::part() { return manager().codec_data().part_; }
785
786bool dccl::FieldCodecBase::strict() { return manager().codec_data().strict_; }
787
788int dccl::FieldCodecBase::codec_version()
789{
790 return root_descriptor()->options().GetExtension(dccl::msg).codec_version();
791}
792
793std::string dccl::FieldCodecBase::codec_group() { return codec_group(root_descriptor()); }
794
796dccl::FieldCodecBase::dynamic_conditions(const google::protobuf::FieldDescriptor* field)
797{
798 manager().codec_data().dynamic_conditions_.set_field(field);
799 return manager().codec_data().dynamic_conditions_;
800}
801
802dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
803 const google::protobuf::Descriptor* root_descriptor,
804 bool strict)
805 : field_codec_(field_codec)
806
807{
808 field_codec_->manager().codec_data().part_ = part;
809 field_codec_->manager().codec_data().strict_ = strict;
810 field_codec_->manager().codec_data().root_message_ = nullptr;
811 field_codec_->manager().codec_data().root_descriptor_ = root_descriptor;
812}
813dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
814 const google::protobuf::Message* root_message, bool strict)
815 : field_codec_(field_codec)
816
817{
818 field_codec_->manager().codec_data().part_ = part;
819 field_codec_->manager().codec_data().strict_ = strict;
820 field_codec_->manager().codec_data().root_message_ = root_message;
821 field_codec_->manager().codec_data().root_descriptor_ = root_message->GetDescriptor();
822}
823dccl::FieldCodecBase::BaseRAII::~BaseRAII()
824{
825 field_codec_->manager().codec_data().part_ = dccl::UNKNOWN;
826 field_codec_->manager().codec_data().strict_ = false;
827 field_codec_->manager().codec_data().root_message_ = nullptr;
828 field_codec_->manager().codec_data().root_descriptor_ = nullptr;
829 field_codec_->manager().codec_data().root_bits_ = nullptr;
830 field_codec_->manager().codec_data().decoded_bits_.clear();
831 field_codec_->manager().codec_data().part_bits_.clear();
832}
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:423
Bitset & append(const Bitset &bits)
Adds the bitset to the big end.
Definition bitset.h:364
const Bitset * parent() const
The parent Bitset that get_more_bits() draws from, or nullptr if there is none.
Definition bitset.h:64
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