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