DCCL v4
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 #include "exception.h"
27 
28 using dccl::dlog;
29 using namespace dccl::logger;
30 
31 //
32 // FieldCodecBase public
33 //
34 dccl::FieldCodecBase::FieldCodecBase() = default;
35 
37  MessagePart part, bool strict)
38 {
39  BaseRAII scoped_globals(this, part, &field_value, strict);
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 
48 void 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  dccl::any wire_value;
58  field_pre_encode(&wire_value, field_value);
59 
60  Bitset new_bits;
61  any_encode(&new_bits, wire_value);
62  disp_size(field, new_bits, msg_handler.field_size());
63  bits->append(new_bits);
64 
65  if (field)
66  dlog.is(DEBUG2, ENCODE) && dlog << "... produced these " << new_bits.size()
67  << " bits: " << new_bits << std::endl;
68 }
69 
71  const std::vector<dccl::any>& field_values,
72  const google::protobuf::FieldDescriptor* field)
73 {
74  internal::MessageStack msg_handler(root_message(), message_data(), field);
75 
76  std::vector<dccl::any> wire_values;
77  field_pre_encode_repeated(&wire_values, field_values);
78 
79  Bitset new_bits;
80  any_encode_repeated(&new_bits, wire_values);
81  disp_size(field, new_bits, msg_handler.field_size(), wire_values.size());
82  bits->append(new_bits);
83 }
84 
85 void dccl::FieldCodecBase::base_size(unsigned* bit_size, const google::protobuf::Message& msg,
86  MessagePart part)
87 {
88  BaseRAII scoped_globals(this, part, &msg);
89 
90  *bit_size = 0;
91 
92  field_size(bit_size, &msg, nullptr);
93 }
94 
95 void dccl::FieldCodecBase::field_size(unsigned* bit_size, const dccl::any& field_value,
96  const google::protobuf::FieldDescriptor* field)
97 {
98  internal::MessageStack msg_handler(root_message(), message_data(), field);
99 
100  dccl::any wire_value;
101  field_pre_encode(&wire_value, field_value);
102 
103  *bit_size += any_size(wire_value);
104 }
105 
107  const std::vector<dccl::any>& field_values,
108  const google::protobuf::FieldDescriptor* field)
109 {
110  internal::MessageStack msg_handler(root_message(), message_data(), field);
111 
112  std::vector<dccl::any> wire_values;
113  field_pre_encode_repeated(&wire_values, field_values);
114 
115  *bit_size += any_size_repeated(wire_values);
116 }
117 
119  MessagePart part)
120 {
121  BaseRAII scoped_globals(this, part, field_value);
122  dccl::any value(field_value);
123  field_decode(bits, &value, nullptr);
124 }
125 
126 void dccl::FieldCodecBase::field_decode(Bitset* bits, dccl::any* field_value,
127  const google::protobuf::FieldDescriptor* field)
128 {
129  internal::MessageStack msg_handler(root_message(), message_data(), field);
130 
131  if (!field_value)
132  throw(Exception("Decode called with NULL dccl::any"));
133  else if (!bits)
134  throw(Exception("Decode called with NULL Bitset"));
135 
136  if (field)
137  dlog.is(DEBUG2, DECODE) && dlog << "Starting decode for field: " << field->DebugString()
138  << std::flush;
139 
140  if (root_message())
141  dlog.is(DEBUG3, DECODE) && dlog << "Message thus far is: " << root_message()->DebugString()
142  << std::flush;
143 
144  Bitset these_bits(bits);
145 
146  unsigned bits_to_transfer = 0;
147  field_min_size(&bits_to_transfer, field);
148  these_bits.get_more_bits(bits_to_transfer);
149 
150  if (field)
151  dlog.is(DEBUG2, DECODE) && dlog << "... using these bits: " << these_bits << std::endl;
152 
153  dccl::any wire_value = *field_value;
154 
155  any_decode(&these_bits, &wire_value);
156 
157  field_post_decode(wire_value, field_value);
158 }
159 
160 void dccl::FieldCodecBase::field_decode_repeated(Bitset* bits, std::vector<dccl::any>* field_values,
161  const google::protobuf::FieldDescriptor* field)
162 {
163  internal::MessageStack msg_handler(root_message(), message_data(), field);
164 
165  if (!field_values)
166  throw(Exception("Decode called with NULL field_values"));
167  else if (!bits)
168  throw(Exception("Decode called with NULL Bitset"));
169 
170  if (field)
171  dlog.is(DEBUG2, DECODE) &&
172  dlog << "Starting repeated decode for field: " << field->DebugString() << std::endl;
173 
174  Bitset these_bits(bits);
175 
176  unsigned bits_to_transfer = 0;
177  field_min_size(&bits_to_transfer, field);
178  these_bits.get_more_bits(bits_to_transfer);
179 
180  dlog.is(DEBUG2, DECODE) && dlog << "using these " << these_bits.size()
181  << " bits: " << these_bits << std::endl;
182 
183  std::vector<dccl::any> wire_values = *field_values;
184  any_decode_repeated(&these_bits, &wire_values);
185 
186  field_values->clear();
187  field_post_decode_repeated(wire_values, field_values);
188 }
189 
190 void dccl::FieldCodecBase::base_max_size(unsigned* bit_size,
191  const google::protobuf::Descriptor* desc, MessagePart part)
192 {
193  BaseRAII scoped_globals(this, part, desc);
194  *bit_size = 0;
195 
196  internal::MessageStack msg_handler(root_message(), message_data());
197  if (desc)
198  msg_handler.push(desc);
199  else
200  throw(Exception("Max Size called with NULL Descriptor"));
201 
202  field_max_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
203 }
204 
205 void dccl::FieldCodecBase::field_max_size(unsigned* bit_size,
206  const google::protobuf::FieldDescriptor* field)
207 {
208  internal::MessageStack msg_handler(root_message(), message_data(), field);
209 
210  if (this_field())
211  *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
212  else
213  *bit_size += max_size();
214 }
215 
216 void dccl::FieldCodecBase::base_min_size(unsigned* bit_size,
217  const google::protobuf::Descriptor* desc, MessagePart part)
218 {
219  BaseRAII scoped_globals(this, part, desc);
220 
221  *bit_size = 0;
222 
223  internal::MessageStack msg_handler(root_message(), message_data());
224  if (desc)
225  msg_handler.push(desc);
226  else
227  throw(Exception("Min Size called with NULL Descriptor"));
228 
229  field_min_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
230 }
231 
232 void dccl::FieldCodecBase::field_min_size(unsigned* bit_size,
233  const google::protobuf::FieldDescriptor* field)
234 
235 {
236  internal::MessageStack msg_handler(root_message(), message_data(), field);
237 
238  if (this_field())
239  *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
240  else
241  *bit_size += min_size();
242 }
243 
244 void dccl::FieldCodecBase::base_validate(const google::protobuf::Descriptor* desc, MessagePart part)
245 {
246  BaseRAII scoped_globals(this, part, desc);
247 
248  internal::MessageStack msg_handler(root_message(), message_data());
249  if (desc)
250  msg_handler.push(desc);
251  else
252  throw(Exception("Validate called with NULL Descriptor"));
253 
254  bool b = false;
255  field_validate(&b, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
256 }
257 
259  const google::protobuf::FieldDescriptor* field)
260 {
261  internal::MessageStack msg_handler(root_message(), message_data(), field);
262 
263  if (field && dccl_field_options().in_head() && variable_size())
264  throw(Exception("Variable size codec used in header - header fields must be encoded with "
265  "fixed size codec."));
266 
267  if (field && dccl_field_options().in_head() && is_part_of_oneof(field))
268  throw(Exception(
269  "Oneof field used in header - oneof fields cannot be encoded in the header."));
270 
271  validate();
272 }
273 
274 void dccl::FieldCodecBase::base_info(std::ostream* os, const google::protobuf::Descriptor* desc,
275  MessagePart part)
276 {
277  BaseRAII scoped_globals(this, part, desc);
278 
279  internal::MessageStack msg_handler(root_message(), message_data());
280  if (desc)
281  msg_handler.push(desc);
282  else
283  throw(Exception("info called with NULL Descriptor"));
284 
285  field_info(os, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
286 }
287 
288 void dccl::FieldCodecBase::field_info(std::ostream* os,
289  const google::protobuf::FieldDescriptor* field)
290 {
291  internal::MessageStack msg_handler(root_message(), message_data(), field);
292 
293  std::stringstream ss;
294  int depth = msg_handler.count();
295 
296  std::string name =
297  ((this_field()) ? std::to_string(this_field()->number()) + ". " + this_field()->name()
298  : this_descriptor()->full_name());
299  if (this_field() && this_field()->is_repeated())
300  name += "[" +
301  (dccl_field_options().has_min_repeat()
302  ? (std::to_string(dccl_field_options().min_repeat()) + "-")
303  : "") +
304  std::to_string(dccl_field_options().max_repeat()) + "]";
305 
306  if (!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
307  depth -= 1;
308 
309  const int spaces = 8;
310  std::string indent =
311  std::string(spaces * (depth) + spaces / 2 * (field && is_part_of_oneof(field)),
312  ' '); // Add 4 spaces of indentation for fields belonging to oneofs
313 
314  const int full_width = 40;
315 
316  bool is_zero_size = false;
317 
318  std::stringstream range;
319  if (variable_size())
320  {
321  unsigned max_sz = 0, min_sz = 0;
322  field_max_size(&max_sz, field);
323  field_min_size(&min_sz, field);
324  if (!max_sz)
325  is_zero_size = true;
326  range << min_sz << "-" << max_sz;
327  }
328  else
329  {
330  unsigned sz = 0;
331  field_max_size(&sz, field);
332  if (!sz)
333  is_zero_size = true;
334  range << sz;
335  }
336 
337  int width = this_field() ? full_width - name.size() : full_width - name.size() + spaces;
338  ss << indent << name << std::setfill('.') << std::setw(std::max(1, width)) << range.str()
339  << " {"
340  << (this_field() ? manager().find(this_field(), codec_version(), has_codec_group(), codec_group())->name()
341  : manager().find(manager().codec_data().root_descriptor_)->name())
342  << "}";
343 
344  if (!is_zero_size)
345  *os << ss.str() << "\n";
346 
347  std::string specific_info = info();
348  if (!specific_info.empty())
349  *os << specific_info;
350 }
351 
352 void dccl::FieldCodecBase::base_hash(std::size_t* hash, const google::protobuf::Descriptor* desc,
353  MessagePart part)
354 {
355  BaseRAII scoped_globals(this, part, desc);
356 
357  internal::MessageStack msg_handler(root_message(), message_data());
358  if (desc)
359  msg_handler.push(desc);
360  else
361  throw(Exception("Hash called with NULL Descriptor"));
362 
363  field_hash(hash, static_cast<google::protobuf::FieldDescriptor*>(nullptr));
364 }
365 
366 void dccl::FieldCodecBase::field_hash(std::size_t* hash_value,
367  const google::protobuf::FieldDescriptor* field)
368 {
369  internal::MessageStack msg_handler(root_message(), message_data(), field);
370 
371  if (field && dccl_field_options().in_head() && variable_size())
372  throw(Exception("Variable size codec used in header - header fields must be encoded with "
373  "fixed size codec."));
374 
375  if (field && dccl_field_options().in_head() && is_part_of_oneof(field))
376  throw(Exception(
377  "Oneof field used in header - oneof fields cannot be encoded in the header."));
378 
379  if (this_field())
380  {
381  google::protobuf::FieldDescriptorProto field_to_hash;
382  this_field()->CopyTo(&field_to_hash);
383 
384  // name doesn't affect encoding
385  field_to_hash.clear_name();
386  // we will handle dccl options separately, non-dccl options don't affect encoding
387  field_to_hash.clear_options();
388  field_to_hash.clear_type_name();
389  field_to_hash.clear_default_value();
390 
391  dccl::DCCLFieldOptions dccl_opts = dccl_field_options();
392 
393  hash_combine(*hash_value, field_to_hash.DebugString());
394  hash_combine(*hash_value, dccl_opts.DebugString());
395  }
396  else
397  {
398  // root level message
399  dccl::DCCLMessageOptions dccl_opts = this_descriptor()->options().GetExtension(dccl::msg);
400  dccl_opts.clear_max_bytes(); // max bytes doesn't affect encoding
401 
402  hash_combine(*hash_value, dccl_opts.DebugString());
403  }
404 
405  hash_combine(*hash_value, hash());
406 }
407 
408 std::string dccl::FieldCodecBase::codec_group(const google::protobuf::Descriptor* desc)
409 {
410  if (desc->options().GetExtension(dccl::msg).has_codec_group())
411  return desc->options().GetExtension(dccl::msg).codec_group();
412  else
413  return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
414 }
415 
416 //
417 // FieldCodecBase protected
418 //
419 
420 std::string dccl::FieldCodecBase::info() { return std::string(); }
421 
422 void dccl::FieldCodecBase::any_encode_repeated(dccl::Bitset* bits,
423  const std::vector<dccl::any>& wire_values)
424 {
425  // out_bits = [field_values[2]][field_values[1]][field_values[0]]
426 
427  unsigned wire_vector_size = dccl_field_options().max_repeat();
428 
429  if (wire_values.size() > wire_vector_size && strict())
430  throw(
431  dccl::OutOfRangeException(std::string("Repeated size exceeds max_repeat for field: ") +
432  FieldCodecBase::this_field()->DebugString(),
433  this->this_field(), this->this_descriptor()));
434 
435  if (wire_values.size() < dccl_field_options().min_repeat() && strict())
437  std::string("Repeated size is less than min_repeat for field: ") +
438  FieldCodecBase::this_field()->DebugString(),
439  this->this_field(), this->this_descriptor()));
440 
441  // for DCCL3 and beyond, add a prefix numeric field giving the vector size (rather than always going to max_repeat)
442  if (codec_version() > 2)
443  {
444  wire_vector_size = std::min(static_cast<int>(dccl_field_options().max_repeat()),
445  static_cast<int>(wire_values.size()));
446 
447  wire_vector_size = std::max(static_cast<int>(dccl_field_options().min_repeat()),
448  static_cast<int>(wire_vector_size));
449 
450  Bitset size_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
451  dccl_field_options().max_repeat()),
452  wire_vector_size - dccl_field_options().min_repeat());
453  bits->append(size_bits);
454 
455  dlog.is(DEBUG2, ENCODE) && dlog << "repeated size field ... produced these "
456  << size_bits.size() << " bits: " << size_bits << std::endl;
457  }
458 
459  internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
460  for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
461  {
462  msg_handler.update_index(root_message(), this->this_field(), i);
463 
464  DynamicConditions& dc = this->dynamic_conditions(this->this_field());
465  dc.set_repeated_index(i);
466  if (dc.has_omit_if())
467  {
468  dc.regenerate(this_message(), root_message(), i);
469  if (dc.omit())
470  continue;
471  }
472 
473  Bitset new_bits;
474  if (i < wire_values.size())
475  any_encode(&new_bits, wire_values[i]);
476  else
477  any_encode(&new_bits, dccl::any());
478  bits->append(new_bits);
479  }
480 }
481 
482 void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits,
483  std::vector<dccl::any>* wire_values)
484 {
485  unsigned wire_vector_size = dccl_field_options().max_repeat();
486  if (codec_version() > 2)
487  {
488  Bitset size_bits(repeated_bits);
489  size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
490  dccl_field_options().max_repeat()));
491 
492  wire_vector_size = size_bits.to_ulong() + dccl_field_options().min_repeat();
493  }
494 
495  wire_values->resize(wire_vector_size);
496 
497  internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
498  for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
499  {
500  msg_handler.update_index(root_message(), this->this_field(), i);
501 
502  DynamicConditions& dc = this->dynamic_conditions(this->this_field());
503  dc.set_repeated_index(i);
504  if (dc.has_omit_if())
505  {
506  dc.regenerate(this_message(), root_message(), i);
507  if (dc.omit())
508  continue;
509  }
510 
511  Bitset these_bits(repeated_bits);
512  these_bits.get_more_bits(min_size());
513  any_decode(&these_bits, &(*wire_values)[i]);
514  }
515 }
516 
517 unsigned dccl::FieldCodecBase::any_size_repeated(const std::vector<dccl::any>& wire_values)
518 {
519  unsigned out = 0;
520  unsigned wire_vector_size = dccl_field_options().max_repeat();
521 
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  out += repeated_vector_field_size(dccl_field_options().min_repeat(),
527  dccl_field_options().max_repeat());
528  }
529 
530  internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
531  for (unsigned i = 0, n = wire_vector_size; i < n; ++i)
532  {
533  msg_handler.update_index(root_message(), this->this_field(), i);
534  DynamicConditions& dc = this->dynamic_conditions(this->this_field());
535  dc.set_repeated_index(i);
536  if (dc.has_omit_if())
537  {
538  dc.regenerate(this_message(), root_message(), i);
539  if (dc.omit())
540  continue;
541  }
542 
543  if (i < wire_values.size())
544  out += any_size(wire_values[i]);
545  else
546  out += any_size(dccl::any());
547  }
548  return out;
549 }
550 
551 void dccl::FieldCodecBase::check_repeat_settings() const
552 {
553  if (!dccl_field_options().has_max_repeat())
554  throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field: " +
555  this_field()->DebugString(),
556  this->this_descriptor()));
557  else if (dccl_field_options().max_repeat() < 1)
558  throw(Exception("(dccl.field).max_repeat must not be less than 1: " +
559  this_field()->DebugString(),
560  this->this_descriptor()));
561  else if (dccl_field_options().max_repeat() < dccl_field_options().min_repeat())
562  throw(Exception("(dccl.field).max_repeat must not be less than (dccl.field).min_repeat: " +
563  this_field()->DebugString(),
564  this->this_descriptor()));
565 }
566 
567 unsigned dccl::FieldCodecBase::max_size_repeated()
568 {
569  check_repeat_settings();
570 
571  if (codec_version() > 2)
572  return repeated_vector_field_size(dccl_field_options().min_repeat(),
573  dccl_field_options().max_repeat()) +
574  max_size() * dccl_field_options().max_repeat();
575  else
576  return max_size() * dccl_field_options().max_repeat();
577 }
578 
579 unsigned dccl::FieldCodecBase::min_size_repeated()
580 {
581  check_repeat_settings();
582 
583  if (codec_version() > 2)
584  return repeated_vector_field_size(dccl_field_options().min_repeat(),
585  dccl_field_options().max_repeat()) +
586  min_size() * dccl_field_options().min_repeat();
587 
588  else
589  return min_size() * dccl_field_options().max_repeat();
590 }
591 
592 void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
593  const std::vector<dccl::any>& field_values)
594 {
595  for (const auto& field_value : field_values)
596  {
597  dccl::any wire_value;
598  any_pre_encode(&wire_value, field_value);
599  wire_values->push_back(wire_value);
600  }
601 }
602 void dccl::FieldCodecBase::any_post_decode_repeated(const std::vector<dccl::any>& wire_values,
603  std::vector<dccl::any>* field_values)
604 {
605  for (const auto& wire_value : wire_values)
606  {
607  dccl::any field_value;
608  any_post_decode(wire_value, &field_value);
609  field_values->push_back(field_value);
610  }
611 }
612 
613 //
614 // FieldCodecBase private
615 //
616 
617 void dccl::FieldCodecBase::disp_size(const google::protobuf::FieldDescriptor* field,
618  const Bitset& new_bits, int depth, int vector_size /* = -1 */)
619 {
620  if (!root_descriptor())
621  return;
622 
623  if (dlog.check(DEBUG2))
624  {
625  std::string name = ((field) ? field->name() : root_descriptor()->full_name());
626  if (vector_size >= 0)
627  name += "[" + std::to_string(vector_size) + "]";
628 
629  dlog.is(DEBUG2, SIZE) && dlog << std::string(depth, '|') << name << std::setfill('.')
630  << std::setw(40 - name.size() - depth) << new_bits.size()
631  << std::endl;
632 
633  if (!field)
634  dlog.is(DEBUG2, SIZE) && dlog << std::endl;
635  }
636 }
637 
638 std::ostream& dccl::operator<<(std::ostream& os, const dccl::FieldCodecBase& field_codec)
639 {
640  using google::protobuf::FieldDescriptor;
641  return os << "[FieldCodec '" << field_codec.name() << "']: field type: "
642  << field_codec.manager().type_helper().find(field_codec.field_type())->as_str()
643  << " ("
644  << field_codec.manager()
645  .type_helper()
646  .find(FieldDescriptor::TypeToCppType(field_codec.field_type()))
647  ->as_str()
648  << ") | wire type: "
649  << field_codec.manager().type_helper().find(field_codec.wire_type())->as_str();
650 }
651 
652 const google::protobuf::FieldDescriptor* dccl::FieldCodecBase::this_field() const
653 {
654  return message_data().top_field();
655 }
656 
657 const google::protobuf::Descriptor* dccl::FieldCodecBase::this_descriptor() const
658 {
659  return message_data().top_descriptor();
660 }
661 
662 const google::protobuf::Message* dccl::FieldCodecBase::this_message()
663 {
664  return message_data().top_message();
665 }
666 
667 const google::protobuf::Message* dccl::FieldCodecBase::root_message()
668 {
669  return manager().codec_data().root_message_;
670 }
671 
672 const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor() const
673 {
674  return manager().codec_data().root_descriptor_;
675 }
676 
677 dccl::internal::MessageStackData& dccl::FieldCodecBase::message_data()
678 {
679  return manager().codec_data().message_data_;
680 }
681 
682 const dccl::internal::MessageStackData& dccl::FieldCodecBase::message_data() const
683 {
684  return manager().codec_data().message_data_;
685 }
686 bool dccl::FieldCodecBase::has_codec_group()
687 {
688  const google::protobuf::Descriptor* root_desc = root_descriptor();
689  if (root_desc)
690  {
691  return root_desc->options().GetExtension(dccl::msg).has_codec_group() ||
692  root_desc->options().GetExtension(dccl::msg).has_codec_version();
693  }
694  else
695  return false;
696 }
697 
698 dccl::MessagePart dccl::FieldCodecBase::part() { return manager().codec_data().part_; }
699 
700 bool dccl::FieldCodecBase::strict() { return manager().codec_data().strict_; }
701 
702 int dccl::FieldCodecBase::codec_version()
703 {
704  return root_descriptor()->options().GetExtension(dccl::msg).codec_version();
705 }
706 
707 std::string dccl::FieldCodecBase::codec_group() { return codec_group(root_descriptor()); }
708 
710 dccl::FieldCodecBase::dynamic_conditions(const google::protobuf::FieldDescriptor* field)
711 {
712  manager().codec_data().dynamic_conditions_.set_field(field);
713  return manager().codec_data().dynamic_conditions_;
714 }
715 
716 dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
717  const google::protobuf::Descriptor* root_descriptor,
718  bool strict)
719  : field_codec_(field_codec)
720 
721 {
722  field_codec_->manager().codec_data().part_ = part;
723  field_codec_->manager().codec_data().strict_ = strict;
724  field_codec_->manager().codec_data().root_message_ = nullptr;
725  field_codec_->manager().codec_data().root_descriptor_ = root_descriptor;
726 }
727 dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
728  const google::protobuf::Message* root_message, bool strict)
729  : field_codec_(field_codec)
730 
731 {
732  field_codec_->manager().codec_data().part_ = part;
733  field_codec_->manager().codec_data().strict_ = strict;
734  field_codec_->manager().codec_data().root_message_ = root_message;
735  field_codec_->manager().codec_data().root_descriptor_ = root_message->GetDescriptor();
736 }
737 dccl::FieldCodecBase::BaseRAII::~BaseRAII()
738 {
739  field_codec_->manager().codec_data().part_ = dccl::UNKNOWN;
740  field_codec_->manager().codec_data().strict_ = false;
741  field_codec_->manager().codec_data().root_message_ = nullptr;
742  field_codec_->manager().codec_data().root_descriptor_ = nullptr;
743 }
dccl::FieldCodecBase::base_encode
void base_encode(Bitset *bits, const google::protobuf::Message &msg, MessagePart part, bool strict)
Encode this part (body or head) of the base message.
Definition: field_codec.cpp:36
dccl::FieldCodecBase::this_descriptor
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
Definition: field_codec.cpp:657
dccl::FieldCodecBase::info
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
Definition: field_codec.cpp:420
dccl::FieldCodecBase
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition: field_codec.h:53
dccl::DCCLFieldOptions
Definition: option_extensions.pb.h:476
dccl::FieldCodecBase::field_decode_repeated
void field_decode_repeated(Bitset *bits, std::vector< dccl::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
Definition: field_codec.cpp:160
dccl::FieldCodecBase::field_hash
void field_hash(std::size_t *hash, const google::protobuf::FieldDescriptor *field)
Provide a hash for this field definition.
Definition: field_codec.cpp:366
dccl::DCCLMessageOptions
Definition: option_extensions.pb.h:783
dccl::DynamicConditions
Definition: dynamic_conditions.h:39
dccl::Bitset::get_more_bits
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition: bitset.h:420
dccl::FieldCodecBase::this_field
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
Definition: field_codec.cpp:652
dccl::FieldCodecBase::field_decode
void field_decode(Bitset *bits, dccl::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
Definition: field_codec.cpp:126
dccl::Logger::is
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:192
dccl::Exception
Exception class for DCCL.
Definition: exception.h:46
dccl::FieldCodecBase::field_min_size
void field_min_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the lower bound on this field's size (in bits)
Definition: field_codec.cpp:232
dccl::FieldCodecBase::base_min_size
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)
Definition: field_codec.cpp:216
dccl::FieldCodecBase::base_max_size
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)
Definition: field_codec.cpp:190
dccl::internal::MessageStack
Definition: field_codec_message_stack.h:72
dccl::FieldCodecBase::field_encode
void field_encode(Bitset *bits, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Encode a non-repeated field.
Definition: field_codec.cpp:48
dccl::FieldCodecBase::field_type
google::protobuf::FieldDescriptor::Type field_type() const
the type exposed to the user in the original and decoded Protobuf messages
Definition: field_codec.h:70
dccl::Bitset::append
Bitset & append(const Bitset &bits)
Adds the bitset to the big end.
Definition: bitset.h:361
dccl::Bitset
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition: bitset.h:42
dccl::FieldCodecBase::field_validate
void field_validate(bool *b, const google::protobuf::FieldDescriptor *field)
Validate this field, checking that all required option extensions are set (e.g. (dccl....
Definition: field_codec.cpp:258
dccl::OutOfRangeException
Definition: exception.h:67
dccl::FieldCodecBase::field_max_size
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field's size (in bits)
Definition: field_codec.cpp:205
dccl::FieldCodecBase::field_size
void field_size(unsigned *bit_size, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
Definition: field_codec.cpp:95
dccl::Logger::check
bool check(logger::Verbosity verbosity)
Same as is() but doesn't set the verbosity or lock the mutex.
Definition: logger.h:181
dccl::FieldCodecBase::base_hash
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.
Definition: field_codec.cpp:352
dccl::FieldCodecBase::field_encode_repeated
void field_encode_repeated(Bitset *bits, const std::vector< dccl::any > &field_values, const google::protobuf::FieldDescriptor *field)
Encode a repeated field.
Definition: field_codec.cpp:70
Message
dccl::internal::MessageStackData
Definition: field_codec_message_stack.h:42
dccl::FieldCodecBase::field_size_repeated
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.
Definition: field_codec.cpp:106
dccl::FieldCodecBase::base_info
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.
Definition: field_codec.cpp:274
dccl::FieldCodecBase::field_info
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.
Definition: field_codec.cpp:288
dccl::FieldCodecBase::base_validate
void base_validate(const google::protobuf::Descriptor *desc, MessagePart part)
Validate this part of the message to make sure all required extensions are set.
Definition: field_codec.cpp:244
dccl::FieldCodecBase::base_size
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.
Definition: field_codec.cpp:85
dccl::FieldCodecBase::part
MessagePart part()
the part of the message currently being encoded (head or body)
Definition: field_codec.cpp:698
dccl::FieldCodecBase::base_decode
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
Definition: field_codec.cpp:118
dccl::FieldCodecBase::name
std::string name() const
the name of the codec used to identifier it in the .proto custom option extension
Definition: field_codec.h:66
dccl::is_part_of_oneof
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:36
dccl::FieldCodecBase::wire_type
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:75