DCCL v4
field_codec.h
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 // Chris Murphy <cmurphy@aphysci.com>
8 //
9 //
10 // This file is part of the Dynamic Compact Control Language Library
11 // ("DCCL").
12 //
13 // DCCL is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU Lesser General Public License as published by
15 // the Free Software Foundation, either version 2.1 of the License, or
16 // (at your option) any later version.
17 //
18 // DCCL is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Lesser General Public License for more details.
22 //
23 // You should have received a copy of the GNU Lesser General Public License
24 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
25 #ifndef DCCLFIELDCODEC20110322H
26 #define DCCLFIELDCODEC20110322H
27 
28 #include <map>
29 #include <string>
30 
31 #include <google/protobuf/descriptor.h>
32 #include <google/protobuf/descriptor.pb.h>
33 #include <google/protobuf/message.h>
34 
35 #include "any.h"
36 #include "binary.h"
37 #include "common.h"
38 #include "dynamic_conditions.h"
39 #include "exception.h"
40 #include "internal/field_codec_message_stack.h"
41 #include "internal/type_helper.h"
42 #include "oneof.h"
43 #include "option_extensions.pb.h"
44 
45 namespace dccl
46 {
47 class Codec;
48 namespace internal
49 {
50 class MessageStack;
51 }
52 
55 {
56  public:
58 
59 
61  virtual ~FieldCodecBase() = default;
63 
65 
66  std::string name() const { return name_; }
71  google::protobuf::FieldDescriptor::Type field_type() const { return field_type_; }
76  google::protobuf::FieldDescriptor::CppType wire_type() const { return wire_type_; }
77 
81  const google::protobuf::FieldDescriptor* this_field() const;
82 
96  const google::protobuf::Descriptor* this_descriptor() const;
97 
98  const google::protobuf::Message* this_message();
99 
100  // currently encoded or (partially) decoded root message
101  const google::protobuf::Message* root_message();
102 
103  const google::protobuf::Descriptor* root_descriptor() const;
104 
105  internal::MessageStackData& message_data();
106 
107  const internal::MessageStackData& message_data() const;
108 
109  bool has_codec_group();
110 
111  static std::string codec_group(const google::protobuf::Descriptor* desc);
112 
113  std::string codec_group();
114 
115  int codec_version();
116 
118  MessagePart part();
119 
120  bool strict();
121 
123  void set_force_use_required(bool force_required = true) { force_required_ = force_required; }
124 
126 
137 
138 
144  void base_encode(Bitset* bits, const google::protobuf::Message& msg, MessagePart part,
145  bool strict);
146 
152  void base_size(unsigned* bit_size, const google::protobuf::Message& msg, MessagePart part);
153 
159  void base_decode(Bitset* bits, google::protobuf::Message* msg, MessagePart part);
160 
166  void base_max_size(unsigned* bit_size, const google::protobuf::Descriptor* desc,
167  MessagePart part);
168 
174  void base_min_size(unsigned* bit_size, const google::protobuf::Descriptor* desc,
175  MessagePart part);
176 
181  void base_validate(const google::protobuf::Descriptor* desc, MessagePart part);
182 
188  void base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessagePart part);
189 
195  void base_hash(std::size_t* hash, const google::protobuf::Descriptor* desc, MessagePart part);
197 
199  //
208 
209 
214  void field_pre_encode(dccl::any* wire_value, const dccl::any& field_value)
215  {
216  any_pre_encode(wire_value, field_value);
217  }
218 
223  void field_pre_encode_repeated(std::vector<dccl::any>* wire_values,
224  const std::vector<dccl::any>& field_values)
225  {
226  any_pre_encode_repeated(wire_values, field_values);
227  }
228 
229  // traverse const
230 
236  void field_encode(Bitset* bits, const dccl::any& field_value,
237  const google::protobuf::FieldDescriptor* field);
238 
244  void field_encode_repeated(Bitset* bits, const std::vector<dccl::any>& field_values,
245  const google::protobuf::FieldDescriptor* field);
246 
252  void field_size(unsigned* bit_size, const dccl::any& field_value,
253  const google::protobuf::FieldDescriptor* field);
254 
260  void field_size_repeated(unsigned* bit_size, const std::vector<dccl::any>& field_values,
261  const google::protobuf::FieldDescriptor* field);
262 
263  // traverse mutable
269  void field_decode(Bitset* bits, dccl::any* field_value,
270  const google::protobuf::FieldDescriptor* field);
271 
277  void field_decode_repeated(Bitset* bits, std::vector<dccl::any>* field_values,
278  const google::protobuf::FieldDescriptor* field);
279 
284  void field_post_decode(const dccl::any& wire_value, dccl::any* field_value)
285  {
286  any_post_decode(wire_value, field_value);
287  }
288 
293  void field_post_decode_repeated(const std::vector<dccl::any>& wire_values,
294  std::vector<dccl::any>* field_values)
295  {
296  any_post_decode_repeated(wire_values, field_values);
297  }
298 
299  // traverse schema (Descriptor)
300 
305  void field_max_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
310  void field_min_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
311 
317  void field_validate(bool* b, const google::protobuf::FieldDescriptor* field);
318 
323  void field_info(std::ostream* os, const google::protobuf::FieldDescriptor* field);
324 
329  void field_hash(std::size_t* hash, const google::protobuf::FieldDescriptor* field);
331 
336  {
337  if (this_field())
338  return this_field()->options().GetExtension(dccl::field);
339  else
340  throw(Exception(
341  "Cannot call dccl_field on base message (has no *field* option extension"));
342  }
343 
349  void require(bool b, const std::string& description)
350  {
351  if (!b)
352  {
353  if (this_field())
354  throw(Exception("Field " + this_field()->name() +
355  " failed validation: " + description,
356  this->this_descriptor()));
357  else
358  throw(Exception("Message " + this_descriptor()->name() +
359  " failed validation: " + description,
360  this->this_descriptor()));
361  }
362  }
363 
364  DynamicConditions& dynamic_conditions(const google::protobuf::FieldDescriptor* field);
365 
366  FieldCodecManagerLocal& manager()
367  {
368  if (manager_)
369  return *manager_;
370  else
371  throw(Exception("FieldCodecManagerLocal is not set"), this->this_descriptor());
372  }
373 
374  const FieldCodecManagerLocal& manager() const
375  {
376  if (manager_)
377  return *manager_;
378  else
379  throw(Exception("FieldCodecManagerLocal is not set"), this->this_descriptor());
380  }
381 
382  virtual void set_manager(FieldCodecManagerLocal* manager) { manager_ = manager; }
383 
384  protected:
387  {
388  if (force_required_)
389  return true;
390 
391  const google::protobuf::FieldDescriptor* field = this_field();
392  DynamicConditions& dc = dynamic_conditions(field);
393  // expensive, so don't do this unless we're going to use it
394  if (dc.has_required_if())
395  dc.regenerate(this_message(), root_message());
396 
397  if (!field)
398  return true;
399  else if (codec_version() > 3) // use required for repeated, required and oneof fields
400  return field->is_required() || field->is_repeated() || is_part_of_oneof(field) ||
401  (dc.has_required_if() && dc.required());
402  else if (codec_version() > 2) // use required for both repeated and required fields
403  return field->is_required() || field->is_repeated() ||
404  (dc.has_required_if() && dc.required());
405  else // use required only for required fields
406  return field->is_required();
407  }
408 
409  //
410  // VIRTUAL
411  //
412 
413  // contain dccl::any
418  virtual void any_encode(Bitset* bits, const dccl::any& wire_value) = 0;
419 
424  virtual void any_decode(Bitset* bits, dccl::any* wire_value) = 0;
425 
430  virtual void any_pre_encode(dccl::any* wire_value, const dccl::any& field_value)
431  {
432  *wire_value = field_value;
433  }
434 
439  virtual void any_post_decode(const dccl::any& wire_value, dccl::any* field_value)
440  {
441  *field_value = wire_value;
442  }
443 
448  virtual unsigned any_size(const dccl::any& wire_value) = 0;
449 
450  // no dccl::any
452  virtual void validate() {}
453 
457  virtual std::string info();
458 
460  virtual std::size_t hash() { return 0; }
461 
465  virtual unsigned max_size() = 0;
466 
470  virtual unsigned min_size() = 0;
471 
472  virtual void any_encode_repeated(Bitset* bits, const std::vector<dccl::any>& wire_values);
473  virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<dccl::any>* field_values);
474 
475  virtual void any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
476  const std::vector<dccl::any>& field_values);
477 
478  virtual void any_post_decode_repeated(const std::vector<dccl::any>& wire_values,
479  std::vector<dccl::any>* field_values);
480 
481  virtual unsigned any_size_repeated(const std::vector<dccl::any>& wire_values);
482  virtual unsigned max_size_repeated();
483  virtual unsigned min_size_repeated();
484  void check_repeat_settings() const;
485 
486  friend class FieldCodecManagerLocal;
487 
488  private:
489  // codec information
490  void set_name(const std::string& name) { name_ = name; }
491  void set_field_type(google::protobuf::FieldDescriptor::Type type) { field_type_ = type; }
492  void set_wire_type(google::protobuf::FieldDescriptor::CppType type) { wire_type_ = type; }
493 
494  bool variable_size()
495  {
496  if (this_field() && this_field()->is_repeated())
497  return max_size_repeated() != min_size_repeated();
498  else
499  return max_size() != min_size();
500  }
501 
502  int repeated_vector_field_size(int min_repeat, int max_repeat)
503  {
504  return dccl::ceil_log2(max_repeat - min_repeat + 1);
505  }
506 
507  void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits,
508  int depth, int vector_size = -1);
509 
510  private:
511  // sets global statics relating the current message begin processed
512  // and unsets them on destruction
513  struct BaseRAII
514  {
515  BaseRAII(FieldCodecBase* field_codec, MessagePart part,
516  const google::protobuf::Descriptor* root_descriptor, bool strict = false);
517 
518  BaseRAII(FieldCodecBase* field_codec, MessagePart part,
519  const google::protobuf::Message* root_message, bool strict = false);
520  ~BaseRAII();
521 
522  private:
523  FieldCodecBase* field_codec_;
524  };
525  friend struct BaseRAII;
526 
527  std::string name_;
528  google::protobuf::FieldDescriptor::Type field_type_;
529  google::protobuf::FieldDescriptor::CppType wire_type_;
530 
531  bool force_required_{false};
532 
533  FieldCodecManagerLocal* manager_{nullptr};
534 };
535 
536 std::ostream& operator<<(std::ostream& os, const FieldCodecBase& field_codec);
537 
538 inline Exception type_error(const std::string& action, const std::type_info& expected,
539  const std::type_info& got)
540 {
541  std::string e = "error " + action + ", expected: ";
542  e += expected.name();
543  e += ", got ";
544  e += got.name();
545  return Exception(e);
546 }
547 
548 } // namespace dccl
549 
550 #endif
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::field_pre_encode
void field_pre_encode(dccl::any *wire_value, const dccl::any &field_value)
Pre-encodes a non-repeated (i.e. optional or required) field by converting the FieldType representati...
Definition: field_codec.h:214
dccl::FieldCodecManagerLocal
A class for managing the various field codecs. Here you can add and remove field codecs....
Definition: field_codec_manager.h:39
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::min_size
virtual unsigned min_size()=0
Calculate minimum size of the field in bits.
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_post_decode_repeated
void field_post_decode_repeated(const std::vector< dccl::any > &wire_values, std::vector< dccl::any > *field_values)
Post-decodes a repeated field.
Definition: field_codec.h:293
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_post_decode
void field_post_decode(const dccl::any &wire_value, dccl::any *field_value)
Post-decodes a non-repeated (i.e. optional or required) field by converting the WireType (the type us...
Definition: field_codec.h:284
dccl::FieldCodecBase::max_size
virtual unsigned max_size()=0
Calculate maximum size of the field in bits.
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::DynamicConditions
Definition: dynamic_conditions.h:39
dccl
Dynamic Compact Control Language namespace.
Definition: any.h:49
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::Exception
Exception class for DCCL.
Definition: exception.h:47
dccl::FieldCodecBase::any_pre_encode
virtual void any_pre_encode(dccl::any *wire_value, const dccl::any &field_value)
Virtual method used to pre-encode (convert from FieldType to WireType). The default implementation of...
Definition: field_codec.h:430
dccl::FieldCodecBase::any_post_decode
virtual void any_post_decode(const dccl::any &wire_value, dccl::any *field_value)
Virtual method used to post-decode (convert from WireType to FieldType). The default implementation o...
Definition: field_codec.h:439
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::FieldCodecBase::require
void require(bool b, const std::string &description)
Essentially an assertion to be used in the validate() virtual method.
Definition: field_codec.h:349
dccl::internal::MessageStack
Definition: field_codec_message_stack.h:72
dccl::FieldCodecBase::set_force_use_required
void set_force_use_required(bool force_required=true)
Force the codec to always use the "required" field encoding, regardless of the FieldDescriptor settin...
Definition: field_codec.h:123
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::validate
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec.h:452
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::ceil_log2
unsigned ceil_log2(dccl::uint64 v)
Definition: binary.h:178
dccl::FieldCodecBase::field_pre_encode_repeated
void field_pre_encode_repeated(std::vector< dccl::any > *wire_values, const std::vector< dccl::any > &field_values)
Pre-encodes a repeated field.
Definition: field_codec.h:223
dccl::Bitset
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition: bitset.h:41
dccl::FieldCodecBase::any_decode
virtual void any_decode(Bitset *bits, dccl::any *wire_value)=0
Virtual method used to decode.
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::FieldCodecBase::any_encode
virtual void any_encode(Bitset *bits, const dccl::any &wire_value)=0
Virtual method used to encode.
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::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::any_size
virtual unsigned any_size(const dccl::any &wire_value)=0
Virtual method for calculating the size of a field (in bits).
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::use_required
bool use_required()
Whether to use the required or optional encoding.
Definition: field_codec.h:386
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::FieldCodecBase::dccl_field_options
dccl::DCCLFieldOptions dccl_field_options() const
Get the DCCL field option extension value for the current field.
Definition: field_codec.h:335
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::hash
virtual std::size_t hash()
Generate a field specific hash to be combined with the descriptor hash.
Definition: field_codec.h:460
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