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 //
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 #ifndef DCCLFIELDCODEC20110322H
25 #define DCCLFIELDCODEC20110322H
26 
27 #include <map>
28 #include <string>
29 
30 #include <google/protobuf/descriptor.h>
31 #include <google/protobuf/descriptor.pb.h>
32 #include <google/protobuf/message.h>
33 
34 #include "any.h"
35 #include "binary.h"
36 #include "common.h"
37 #include "dynamic_conditions.h"
38 #include "exception.h"
39 #include "internal/field_codec_message_stack.h"
40 #include "internal/type_helper.h"
41 #include "oneof.h"
42 #include "option_extensions.pb.h"
43 
44 namespace dccl
45 {
46 class Codec;
47 namespace internal
48 {
49 class MessageStack;
50 }
51 
54 {
55  public:
57 
58 
60  virtual ~FieldCodecBase() = default;
62 
64 
65  std::string name() const { return name_; }
70  google::protobuf::FieldDescriptor::Type field_type() const { return field_type_; }
75  google::protobuf::FieldDescriptor::CppType wire_type() const { return wire_type_; }
76 
80  const google::protobuf::FieldDescriptor* this_field() const;
81 
95  const google::protobuf::Descriptor* this_descriptor() const;
96 
97  const google::protobuf::Message* this_message();
98 
99  // currently encoded or (partially) decoded root message
100  const google::protobuf::Message* root_message();
101 
102  const google::protobuf::Descriptor* root_descriptor() const;
103 
104  internal::MessageStackData& message_data();
105 
106  const internal::MessageStackData& message_data() const;
107 
108  bool has_codec_group();
109 
110  static std::string codec_group(const google::protobuf::Descriptor* desc);
111 
112  std::string codec_group();
113 
114  int codec_version();
115 
117  MessagePart part();
118 
119  bool strict();
120 
122  void set_force_use_required(bool force_required = true) { force_required_ = force_required; }
123 
125 
136 
137 
143  void base_encode(Bitset* bits, const google::protobuf::Message& msg, MessagePart part,
144  bool strict);
145 
151  void base_size(unsigned* bit_size, const google::protobuf::Message& msg, MessagePart part);
152 
158  void base_decode(Bitset* bits, google::protobuf::Message* msg, MessagePart part);
159 
165  void base_max_size(unsigned* bit_size, const google::protobuf::Descriptor* desc,
166  MessagePart part);
167 
173  void base_min_size(unsigned* bit_size, const google::protobuf::Descriptor* desc,
174  MessagePart part);
175 
180  void base_validate(const google::protobuf::Descriptor* desc, MessagePart part);
181 
187  void base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessagePart part);
188 
194  void base_hash(std::size_t* hash, const google::protobuf::Descriptor* desc, MessagePart part);
196 
198  //
207 
208 
213  void field_pre_encode(dccl::any* wire_value, const dccl::any& field_value)
214  {
215  any_pre_encode(wire_value, field_value);
216  }
217 
222  void field_pre_encode_repeated(std::vector<dccl::any>* wire_values,
223  const std::vector<dccl::any>& field_values)
224  {
225  any_pre_encode_repeated(wire_values, field_values);
226  }
227 
228  // traverse const
229 
235  void field_encode(Bitset* bits, const dccl::any& field_value,
236  const google::protobuf::FieldDescriptor* field);
237 
243  void field_encode_repeated(Bitset* bits, const std::vector<dccl::any>& field_values,
244  const google::protobuf::FieldDescriptor* field);
245 
251  void field_size(unsigned* bit_size, const dccl::any& field_value,
252  const google::protobuf::FieldDescriptor* field);
253 
259  void field_size_repeated(unsigned* bit_size, const std::vector<dccl::any>& field_values,
260  const google::protobuf::FieldDescriptor* field);
261 
262  // traverse mutable
268  void field_decode(Bitset* bits, dccl::any* field_value,
269  const google::protobuf::FieldDescriptor* field);
270 
276  void field_decode_repeated(Bitset* bits, std::vector<dccl::any>* field_values,
277  const google::protobuf::FieldDescriptor* field);
278 
283  void field_post_decode(const dccl::any& wire_value, dccl::any* field_value)
284  {
285  any_post_decode(wire_value, field_value);
286  }
287 
292  void field_post_decode_repeated(const std::vector<dccl::any>& wire_values,
293  std::vector<dccl::any>* field_values)
294  {
295  any_post_decode_repeated(wire_values, field_values);
296  }
297 
298  // traverse schema (Descriptor)
299 
304  void field_max_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
309  void field_min_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
310 
316  void field_validate(bool* b, const google::protobuf::FieldDescriptor* field);
317 
322  void field_info(std::ostream* os, const google::protobuf::FieldDescriptor* field);
323 
328  void field_hash(std::size_t* hash, const google::protobuf::FieldDescriptor* field);
330 
335  {
336  if (this_field())
337  return this_field()->options().GetExtension(dccl::field);
338  else
339  throw(Exception(
340  "Cannot call dccl_field on base message (has no *field* option extension"));
341  }
342 
348  void require(bool b, const std::string& description)
349  {
350  if (!b)
351  {
352  if (this_field())
353  throw(Exception("Field " + this_field()->name() +
354  " failed validation: " + description,
355  this->this_descriptor()));
356  else
357  throw(Exception("Message " + this_descriptor()->name() +
358  " failed validation: " + description,
359  this->this_descriptor()));
360  }
361  }
362 
363  DynamicConditions& dynamic_conditions(const google::protobuf::FieldDescriptor* field);
364 
365  FieldCodecManagerLocal& manager()
366  {
367  if (manager_)
368  return *manager_;
369  else
370  throw(Exception("FieldCodecManagerLocal is not set"), this->this_descriptor());
371  }
372 
373  const FieldCodecManagerLocal& manager() const
374  {
375  if (manager_)
376  return *manager_;
377  else
378  throw(Exception("FieldCodecManagerLocal is not set"), this->this_descriptor());
379  }
380 
381  virtual void set_manager(FieldCodecManagerLocal* manager) { manager_ = manager; }
382 
383  protected:
386  {
387  if (force_required_)
388  return true;
389 
390  const google::protobuf::FieldDescriptor* field = this_field();
391  DynamicConditions& dc = dynamic_conditions(field);
392  // expensive, so don't do this unless we're going to use it
393  if (dc.has_required_if())
394  dc.regenerate(this_message(), root_message());
395 
396  if (!field)
397  return true;
398  else if (codec_version() > 3) // use required for repeated, required and oneof fields
399  return field->is_required() || field->is_repeated() || is_part_of_oneof(field) ||
400  (dc.has_required_if() && dc.required());
401  else if (codec_version() > 2) // use required for both repeated and required fields
402  return field->is_required() || field->is_repeated() ||
403  (dc.has_required_if() && dc.required());
404  else // use required only for required fields
405  return field->is_required();
406  }
407 
408  //
409  // VIRTUAL
410  //
411 
412  // contain dccl::any
417  virtual void any_encode(Bitset* bits, const dccl::any& wire_value) = 0;
418 
423  virtual void any_decode(Bitset* bits, dccl::any* wire_value) = 0;
424 
429  virtual void any_pre_encode(dccl::any* wire_value, const dccl::any& field_value)
430  {
431  *wire_value = field_value;
432  }
433 
438  virtual void any_post_decode(const dccl::any& wire_value, dccl::any* field_value)
439  {
440  *field_value = wire_value;
441  }
442 
447  virtual unsigned any_size(const dccl::any& wire_value) = 0;
448 
449  // no dccl::any
451  virtual void validate() {}
452 
456  virtual std::string info();
457 
459  virtual std::size_t hash() { return 0; }
460 
464  virtual unsigned max_size() = 0;
465 
469  virtual unsigned min_size() = 0;
470 
471  virtual void any_encode_repeated(Bitset* bits, const std::vector<dccl::any>& wire_values);
472  virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<dccl::any>* field_values);
473 
474  virtual void any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
475  const std::vector<dccl::any>& field_values);
476 
477  virtual void any_post_decode_repeated(const std::vector<dccl::any>& wire_values,
478  std::vector<dccl::any>* field_values);
479 
480  virtual unsigned any_size_repeated(const std::vector<dccl::any>& wire_values);
481  virtual unsigned max_size_repeated();
482  virtual unsigned min_size_repeated();
483  void check_repeat_settings() const;
484 
485  friend class FieldCodecManagerLocal;
486 
487  private:
488  // codec information
489  void set_name(const std::string& name) { name_ = name; }
490  void set_field_type(google::protobuf::FieldDescriptor::Type type) { field_type_ = type; }
491  void set_wire_type(google::protobuf::FieldDescriptor::CppType type) { wire_type_ = type; }
492 
493  bool variable_size()
494  {
495  if (this_field() && this_field()->is_repeated())
496  return max_size_repeated() != min_size_repeated();
497  else
498  return max_size() != min_size();
499  }
500 
501  int repeated_vector_field_size(int min_repeat, int max_repeat)
502  {
503  return dccl::ceil_log2(max_repeat - min_repeat + 1);
504  }
505 
506  void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits,
507  int depth, int vector_size = -1);
508 
509  private:
510  // sets global statics relating the current message begin processed
511  // and unsets them on destruction
512  struct BaseRAII
513  {
514  BaseRAII(FieldCodecBase* field_codec, MessagePart part,
515  const google::protobuf::Descriptor* root_descriptor, bool strict = false);
516 
517  BaseRAII(FieldCodecBase* field_codec, MessagePart part,
518  const google::protobuf::Message* root_message, bool strict = false);
519  ~BaseRAII();
520 
521  private:
522  FieldCodecBase* field_codec_;
523  };
524  friend struct BaseRAII;
525 
526  std::string name_;
527  google::protobuf::FieldDescriptor::Type field_type_;
528  google::protobuf::FieldDescriptor::CppType wire_type_;
529 
530  bool force_required_{false};
531 
532  FieldCodecManagerLocal* manager_{nullptr};
533 };
534 
535 std::ostream& operator<<(std::ostream& os, const FieldCodecBase& field_codec);
536 
537 inline Exception type_error(const std::string& action, const std::type_info& expected,
538  const std::type_info& got)
539 {
540  std::string e = "error " + action + ", expected: ";
541  e += expected.name();
542  e += ", got ";
543  e += got.name();
544  return Exception(e);
545 }
546 
547 } // namespace dccl
548 
549 #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:36
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:213
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: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::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:53
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:292
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_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:283
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:366
dccl::DynamicConditions
Definition: dynamic_conditions.h:39
dccl
Dynamic Compact Control Language namespace.
Definition: any.h:46
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::Exception
Exception class for DCCL.
Definition: exception.h:46
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:429
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:438
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::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:348
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:122
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::validate
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec.h:451
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::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:222
dccl::Bitset
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition: bitset.h:42
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:258
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: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::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::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:288
dccl::FieldCodecBase::use_required
bool use_required()
Whether to use the required or optional encoding.
Definition: field_codec.h:385
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::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:334
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::hash
virtual std::size_t hash()
Generate a field specific hash to be combined with the descriptor hash.
Definition: field_codec.h:459
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