DCCL v3
field_codec.h
1 // Copyright 2009-2017 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (for 2013-)
3 // Massachusetts Institute of Technology (for 2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Dynamic Compact Control Language Library
8 // ("DCCL").
9 //
10 // DCCL is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // DCCL is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
22 #ifndef DCCLFIELDCODEC20110322H
23 #define DCCLFIELDCODEC20110322H
24 
25 #include <map>
26 #include <string>
27 
28 #include <boost/any.hpp>
29 #include <boost/lexical_cast.hpp>
30 
31 #include <google/protobuf/message.h>
32 #include <google/protobuf/descriptor.pb.h>
33 #include <google/protobuf/descriptor.h>
34 
35 #include "common.h"
36 #include "exception.h"
37 #include "dccl/option_extensions.pb.h"
38 #include "internal/type_helper.h"
39 #include "internal/field_codec_message_stack.h"
40 #include "dccl/binary.h"
41 
42 namespace dccl
43 {
44  class Codec;
45 
48  {
49  public:
51 
52 
54  virtual ~FieldCodecBase() { }
56 
58 
59  std::string name() const { return name_; }
64  google::protobuf::FieldDescriptor::Type field_type() const { return field_type_; }
69  google::protobuf::FieldDescriptor::CppType wire_type() const { return wire_type_; }
70 
71 
75  const google::protobuf::FieldDescriptor* this_field() const
76  { return !internal::MessageStack::field_.empty() ? internal::MessageStack::field_.back() : 0; }
77 
91  static const google::protobuf::Descriptor* this_descriptor()
92  { return !internal::MessageStack::desc_.empty() ? internal::MessageStack::desc_.back() : 0; }
93 
94  // currently encoded or (partially) decoded root message
95  static const google::protobuf::Message* root_message()
96  { return root_message_; }
97 
98  static bool has_codec_group()
99  {
100  if(root_descriptor_)
101  {
102  return root_descriptor_->options().GetExtension(dccl::msg).has_codec_group() ||
103  root_descriptor_->options().GetExtension(dccl::msg).has_codec_version();
104  }
105  else
106  return false;
107  }
108 
109  static std::string codec_group(const google::protobuf::Descriptor* desc);
110 
111  static std::string codec_group()
112  { return codec_group(root_descriptor_); }
113 
114  static int codec_version()
115  { return root_descriptor_->options().GetExtension(dccl::msg).codec_version(); }
116 
118  static MessagePart part() { return part_; }
119 
120  static bool strict() { return strict_; }
121 
123  void set_force_use_required(bool force_required = true)
124  {
125  force_required_ = force_required;
126  }
127 
129 
140 
141 
147  void base_encode(Bitset* bits,
148  const google::protobuf::Message& msg,
149  MessagePart part,
150  bool strict);
151 
157  void base_size(unsigned* bit_size, const google::protobuf::Message& msg, MessagePart part);
158 
164  void base_decode(Bitset* bits,
166  MessagePart part);
167 
173  void base_max_size(unsigned* bit_size, const google::protobuf::Descriptor* desc, MessagePart part);
174 
180  void base_min_size(unsigned* bit_size, const google::protobuf::Descriptor* desc, MessagePart part);
181 
186  void base_validate(const google::protobuf::Descriptor* desc, MessagePart part);
187 
193  void base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessagePart part);
195 
197  //
206 
207 
212  void field_pre_encode(boost::any* wire_value, const boost::any& field_value)
213  { any_pre_encode(wire_value, field_value); }
214 
219  void field_pre_encode_repeated(std::vector<boost::any>* wire_values,
220  const std::vector<boost::any>& field_values)
221  { any_pre_encode_repeated(wire_values, field_values); }
222 
223  // traverse const
224 
230  void field_encode(Bitset* bits,
231  const boost::any& field_value,
232  const google::protobuf::FieldDescriptor* field);
233 
239  void field_encode_repeated(Bitset* bits,
240  const std::vector<boost::any>& field_values,
241  const google::protobuf::FieldDescriptor* field);
242 
248  void field_size(unsigned* bit_size, const boost::any& field_value,
249  const google::protobuf::FieldDescriptor* field);
250 
256  void field_size_repeated(unsigned* bit_size, const std::vector<boost::any>& field_values,
257  const google::protobuf::FieldDescriptor* field);
258 
259  // traverse mutable
265  void field_decode(Bitset* bits,
266  boost::any* field_value,
267  const google::protobuf::FieldDescriptor* field);
268 
274  void field_decode_repeated(Bitset* bits,
275  std::vector<boost::any>* field_values,
276  const google::protobuf::FieldDescriptor* field);
277 
282  void field_post_decode(const boost::any& wire_value, boost::any* field_value)
283  { any_post_decode(wire_value, field_value); }
284 
289  void field_post_decode_repeated(const std::vector<boost::any>& wire_values,
290  std::vector<boost::any>* field_values)
291  { any_post_decode_repeated(wire_values, field_values); }
292 
293 
294  // traverse schema (Descriptor)
295 
300  void field_max_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
305  void field_min_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
306 
312  void field_validate(bool* b, const google::protobuf::FieldDescriptor* field);
313 
318  void field_info(std::ostream* os, const google::protobuf::FieldDescriptor* field);
320 
321  protected:
322 
327  {
328  if(this_field())
329  return this_field()->options().GetExtension(dccl::field);
330  else
331  throw(Exception("Cannot call dccl_field on base message (has no *field* option extension"));
332 
333  }
334 
340  void require(bool b, const std::string& description)
341  {
342  if(!b)
343  {
344  if(this_field())
345  throw(Exception("Field " + this_field()->name() + " failed validation: " + description));
346  else
347  throw(Exception("Message " + this_descriptor()->name() + " failed validation: " + description));
348  }
349 
350  }
351 
354  {
355  if(force_required_)
356  return true;
357 
358  const google::protobuf::FieldDescriptor* field = this_field();
359  if(!field)
360  return true;
361  else if(codec_version() > 2) // use required for both repeated and required fields
362  return field->is_required() || field->is_repeated();
363  else // use required only for required fields
364  return field->is_required();
365  }
366 
367 
368  //
369  // VIRTUAL
370  //
371 
372  // contain boost::any
377  virtual void any_encode(Bitset* bits, const boost::any& wire_value) = 0;
378 
383  virtual void any_decode(Bitset* bits, boost::any* wire_value) = 0;
384 
389  virtual void any_pre_encode(boost::any* wire_value,
390  const boost::any& field_value)
391  { *wire_value = field_value; }
392 
397  virtual void any_post_decode(const boost::any& wire_value,
398  boost::any* field_value)
399  { *field_value = wire_value; }
400 
405  virtual unsigned any_size(const boost::any& wire_value) = 0;
406 
407  // no boost::any
409  virtual void validate() { }
410 
414  virtual std::string info();
415 
419  virtual unsigned max_size() = 0;
420 
424  virtual unsigned min_size() = 0;
425 
426  virtual void any_encode_repeated(Bitset* bits, const std::vector<boost::any>& wire_values);
427  virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* field_values);
428 
429  virtual void any_pre_encode_repeated(std::vector<boost::any>* wire_values,
430  const std::vector<boost::any>& field_values);
431 
432  virtual void any_post_decode_repeated(const std::vector<boost::any>& wire_values,
433  std::vector<boost::any>* field_values);
434 
435  virtual unsigned any_size_repeated(const std::vector<boost::any>& wire_values);
436  virtual unsigned max_size_repeated();
437  virtual unsigned min_size_repeated();
438 
439  friend class FieldCodecManager;
440  private:
441  // codec information
442  void set_name(const std::string& name)
443  { name_ = name; }
444  void set_field_type(google::protobuf::FieldDescriptor::Type type)
445  { field_type_ = type; }
446  void set_wire_type(google::protobuf::FieldDescriptor::CppType type)
447  { wire_type_ = type; }
448 
449  bool variable_size()
450  {
451  if(this_field() && this_field()->is_repeated())
452  return max_size_repeated() != min_size_repeated();
453  else
454  return max_size() != min_size();
455  }
456 
457  int repeated_vector_field_size(int max_repeat)
458  { return dccl::ceil_log2(max_repeat+1); }
459 
460  void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size = -1);
461 
462 
463  private:
464  // sets global statics relating the current message begin processed
465  // and unsets them on destruction
466  struct BaseRAII
467  {
468  BaseRAII(MessagePart part,
469  const google::protobuf::Descriptor* root_descriptor,
470  bool strict = false)
471  {
472  FieldCodecBase::part_ = part;
473  FieldCodecBase::strict_ = strict;
474  FieldCodecBase::root_message_ = 0;
475  FieldCodecBase::root_descriptor_ = root_descriptor;
476  }
477 
478  BaseRAII(MessagePart part,
479  const google::protobuf::Message* root_message,
480  bool strict = false)
481  {
482  FieldCodecBase::part_ = part;
483  FieldCodecBase::strict_ = strict;
484  FieldCodecBase::root_message_ = root_message;
485  FieldCodecBase::root_descriptor_ = root_message->GetDescriptor();
486  }
487  ~BaseRAII()
488  {
489  FieldCodecBase::part_ = dccl::UNKNOWN;
490  FieldCodecBase::strict_ = false;
491  FieldCodecBase::root_message_ = 0;
492  FieldCodecBase::root_descriptor_ = 0;
493  }
494  };
495 
496 
497  static MessagePart part_;
498  static bool strict_;
499  static const google::protobuf::Message* root_message_;
500  static const google::protobuf::Descriptor* root_descriptor_;
501 
502  std::string name_;
503  google::protobuf::FieldDescriptor::Type field_type_;
504  google::protobuf::FieldDescriptor::CppType wire_type_;
505 
506  bool force_required_;
507 
508  };
509 
510  inline std::ostream& operator<<(std::ostream& os, const FieldCodecBase& field_codec )
511  {
512  using google::protobuf::FieldDescriptor;
513  using internal::TypeHelper;
514  return os << "[FieldCodec '" << field_codec.name() << "']: field type: "
515  << TypeHelper::find(field_codec.field_type())->as_str()
516  << " (" << TypeHelper::find(FieldDescriptor::TypeToCppType(field_codec.field_type()))->as_str()
517  << ") | wire type: " << TypeHelper::find(field_codec.wire_type())->as_str();
518  }
519 
520  inline Exception type_error(const std::string& action,
521  const std::type_info& expected,
522  const std::type_info& got)
523  {
524  std::string e = "error " + action + ", expected: ";
525  e += expected.name();
526  e += ", got ";
527  e += got.name();
528  return Exception(e);
529  }
530 
531 
532 }
533 
534 
535 #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:44
dccl::FieldCodecBase::any_decode
virtual void any_decode(Bitset *bits, boost::any *wire_value)=0
Virtual method used to decode.
dccl::FieldCodecBase::any_pre_encode
virtual void any_pre_encode(boost::any *wire_value, const boost::any &field_value)
Virtual method used to pre-encode (convert from FieldType to WireType). The default implementation of...
Definition: field_codec.h:389
dccl::FieldCodecBase::field_decode_repeated
void field_decode_repeated(Bitset *bits, std::vector< boost::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
Definition: field_codec.cpp:174
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:380
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:47
dccl::DCCLFieldOptions
Definition: option_extensions.pb.h:278
dccl::FieldCodecBase::max_size
virtual unsigned max_size()=0
Calculate maximum size of the field in bits.
dccl::FieldCodecBase::this_field
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
Definition: field_codec.h:75
dccl
Dynamic Compact Control Language namespace.
Definition: gen_units_class_plugin.h:49
dccl::Exception
Exception class for DCCL.
Definition: exception.h:31
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:251
dccl::FieldCodecBase::any_post_decode
virtual void any_post_decode(const boost::any &wire_value, boost::any *field_value)
Virtual method used to post-decode (convert from WireType to FieldType). The default implementation o...
Definition: field_codec.h:397
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:234
dccl::FieldCodecBase::field_encode_repeated
void field_encode_repeated(Bitset *bits, const std::vector< boost::any > &field_values, const google::protobuf::FieldDescriptor *field)
Encode a repeated field.
Definition: field_codec.cpp:77
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:205
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:340
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::validate
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec.h:409
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:64
dccl::ceil_log2
unsigned ceil_log2(dccl::uint64 v)
Definition: binary.h:180
dccl::FieldCodecBase::field_size_repeated
void field_size_repeated(unsigned *bit_size, const std::vector< boost::any > &field_values, const google::protobuf::FieldDescriptor *field)
Calculate the size of a repeated field.
Definition: field_codec.cpp:117
dccl::FieldCodecBase::field_decode
void field_decode(Bitset *bits, boost::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
Definition: field_codec.cpp:142
dccl::FieldCodecBase::this_descriptor
static const google::protobuf::Descriptor * this_descriptor()
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
Definition: field_codec.h:91
dccl::FieldCodecBase::field_post_decode
void field_post_decode(const boost::any &wire_value, boost::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:282
dccl::Bitset
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition: bitset.h:38
dccl::FieldCodecBase::field_encode
void field_encode(Bitset *bits, const boost::any &field_value, const google::protobuf::FieldDescriptor *field)
Encode a non-repeated field.
Definition: field_codec.cpp:59
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:280
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:221
dccl::FieldCodecBase::any_encode
virtual void any_encode(Bitset *bits, const boost::any &wire_value)=0
Virtual method used to encode.
dccl::FieldCodecBase::field_pre_encode_repeated
void field_pre_encode_repeated(std::vector< boost::any > *wire_values, const std::vector< boost::any > &field_values)
Pre-encodes a repeated field.
Definition: field_codec.h:219
dccl::FieldCodecManager
A class for managing the various field codecs. Here you can add and remove field codecs....
Definition: field_codec_manager.h:44
Message
dccl::FieldCodecBase::field_post_decode_repeated
void field_post_decode_repeated(const std::vector< boost::any > &wire_values, std::vector< boost::any > *field_values)
Post-decodes a repeated field.
Definition: field_codec.h:289
dccl::FieldCodecBase::field_pre_encode
void field_pre_encode(boost::any *wire_value, const boost::any &field_value)
Pre-encodes a non-repeated (i.e. optional or required) field by converting the FieldType representati...
Definition: field_codec.h:212
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:291
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:305
dccl::FieldCodecBase::use_required
bool use_required()
Whether to use the required or optional encoding.
Definition: field_codec.h:353
dccl::FieldCodecBase::part
static MessagePart part()
the part of the message currently being encoded (head or body).
Definition: field_codec.h:118
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:264
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:93
dccl::FieldCodecBase::base_decode
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
Definition: field_codec.cpp:132
dccl::FieldCodecBase::any_size
virtual unsigned any_size(const boost::any &wire_value)=0
Virtual method for calculating the size of a field (in bits).
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:60
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:326
dccl::FieldCodecBase::field_size
void field_size(unsigned *bit_size, const boost::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
Definition: field_codec.cpp:105
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:69