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 
122 
124 
135 
136 
142  void base_encode(Bitset* bits,
143  const google::protobuf::Message& msg,
144  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,
161  MessagePart part);
162 
168  void base_max_size(unsigned* bit_size, const google::protobuf::Descriptor* desc, MessagePart part);
169 
175  void base_min_size(unsigned* bit_size, const google::protobuf::Descriptor* desc, 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);
190 
192  //
201 
202 
207  void field_pre_encode(boost::any* wire_value, const boost::any& field_value)
208  { any_pre_encode(wire_value, field_value); }
209 
214  void field_pre_encode_repeated(std::vector<boost::any>* wire_values,
215  const std::vector<boost::any>& field_values)
216  { any_pre_encode_repeated(wire_values, field_values); }
217 
218  // traverse const
219 
225  void field_encode(Bitset* bits,
226  const boost::any& field_value,
227  const google::protobuf::FieldDescriptor* field);
228 
234  void field_encode_repeated(Bitset* bits,
235  const std::vector<boost::any>& field_values,
236  const google::protobuf::FieldDescriptor* field);
237 
243  void field_size(unsigned* bit_size, const boost::any& field_value,
244  const google::protobuf::FieldDescriptor* field);
245 
251  void field_size_repeated(unsigned* bit_size, const std::vector<boost::any>& wire_values,
252  const google::protobuf::FieldDescriptor* field);
253 
254  // traverse mutable
260  void field_decode(Bitset* bits,
261  boost::any* field_value,
262  const google::protobuf::FieldDescriptor* field);
263 
269  void field_decode_repeated(Bitset* bits,
270  std::vector<boost::any>* field_values,
271  const google::protobuf::FieldDescriptor* field);
272 
277  void field_post_decode(const boost::any& wire_value, boost::any* field_value)
278  { any_post_decode(wire_value, field_value); }
279 
284  void field_post_decode_repeated(const std::vector<boost::any>& wire_values,
285  std::vector<boost::any>* field_values)
286  { any_post_decode_repeated(wire_values, field_values); }
287 
288 
289  // traverse schema (Descriptor)
290 
295  void field_max_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
300  void field_min_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
301 
307  void field_validate(bool* b, const google::protobuf::FieldDescriptor* field);
308 
313  void field_info(std::ostream* os, const google::protobuf::FieldDescriptor* field);
315 
316  protected:
317 
322  {
323  if(this_field())
324  return this_field()->options().GetExtension(dccl::field);
325  else
326  throw(Exception("Cannot call dccl_field on base message (has no *field* option extension"));
327 
328  }
329 
335  void require(bool b, const std::string& description)
336  {
337  if(!b)
338  {
339  if(this_field())
340  throw(Exception("Field " + this_field()->name() + " failed validation: " + description));
341  else
342  throw(Exception("Message " + this_descriptor()->name() + " failed validation: " + description));
343  }
344 
345  }
346 
349  {
350  const google::protobuf::FieldDescriptor* field = this_field();
351  if(!field)
352  return true;
353  else if(codec_version() > 2) // use required for both repeated and required fields
354  return field->is_required() || field->is_repeated();
355  else // use required only for required fields
356  return field->is_required();
357  }
358 
359 
360  //
361  // VIRTUAL
362  //
363 
364  // contain boost::any
369  virtual void any_encode(Bitset* bits, const boost::any& wire_value) = 0;
370 
375  virtual void any_decode(Bitset* bits, boost::any* wire_value) = 0;
376 
381  virtual void any_pre_encode(boost::any* wire_value,
382  const boost::any& field_value)
383  { *wire_value = field_value; }
384 
389  virtual void any_post_decode(const boost::any& wire_value,
390  boost::any* field_value)
391  { *field_value = wire_value; }
392 
397  virtual unsigned any_size(const boost::any& wire_value) = 0;
398 
399  // no boost::any
401  virtual void validate() { }
402 
406  virtual std::string info();
407 
411  virtual unsigned max_size() = 0;
412 
416  virtual unsigned min_size() = 0;
417 
418  virtual void any_encode_repeated(Bitset* bits, const std::vector<boost::any>& wire_values);
419  virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* field_values);
420 
421  virtual void any_pre_encode_repeated(std::vector<boost::any>* wire_values,
422  const std::vector<boost::any>& field_values);
423 
424  virtual void any_post_decode_repeated(const std::vector<boost::any>& wire_values,
425  std::vector<boost::any>* field_values);
426 
427  virtual unsigned any_size_repeated(const std::vector<boost::any>& wire_values);
428  virtual unsigned max_size_repeated();
429  virtual unsigned min_size_repeated();
430 
431  friend class FieldCodecManager;
432  private:
433  // codec information
434  void set_name(const std::string& name)
435  { name_ = name; }
436  void set_field_type(google::protobuf::FieldDescriptor::Type type)
437  { field_type_ = type; }
438  void set_wire_type(google::protobuf::FieldDescriptor::CppType type)
439  { wire_type_ = type; }
440 
441  bool variable_size()
442  {
443  if(this_field() && this_field()->is_repeated())
444  return max_size_repeated() != min_size_repeated();
445  else
446  return max_size() != min_size();
447  }
448 
449  int repeated_vector_field_size(int max_repeat)
450  { return dccl::ceil_log2(max_repeat+1); }
451 
452  void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size = -1);
453 
454 
455  private:
456  // sets global statics relating the current message begin processed
457  // and unsets them on destruction
458  struct BaseRAII
459  {
460  BaseRAII(MessagePart part,
461  const google::protobuf::Descriptor* root_descriptor,
462  bool strict = false)
463  {
464  FieldCodecBase::part_ = part;
465  FieldCodecBase::strict_ = strict;
466  FieldCodecBase::root_message_ = 0;
467  FieldCodecBase::root_descriptor_ = root_descriptor;
468  }
469 
470  BaseRAII(MessagePart part,
471  const google::protobuf::Message* root_message,
472  bool strict = false)
473  {
474  FieldCodecBase::part_ = part;
475  FieldCodecBase::strict_ = strict;
476  FieldCodecBase::root_message_ = root_message;
477  FieldCodecBase::root_descriptor_ = root_message->GetDescriptor();
478  }
479  ~BaseRAII()
480  {
481  FieldCodecBase::part_ = dccl::UNKNOWN;
482  FieldCodecBase::strict_ = false;
483  FieldCodecBase::root_message_ = 0;
484  FieldCodecBase::root_descriptor_ = 0;
485  }
486  };
487 
488 
489  static MessagePart part_;
490  static bool strict_;
491  static const google::protobuf::Message* root_message_;
492  static const google::protobuf::Descriptor* root_descriptor_;
493 
494  std::string name_;
495  google::protobuf::FieldDescriptor::Type field_type_;
496  google::protobuf::FieldDescriptor::CppType wire_type_;
497 
498  };
499 
500  inline std::ostream& operator<<(std::ostream& os, const FieldCodecBase& field_codec )
501  {
502  using google::protobuf::FieldDescriptor;
503  using internal::TypeHelper;
504  return os << "[FieldCodec '" << field_codec.name() << "']: field type: "
505  << TypeHelper::find(field_codec.field_type())->as_str()
506  << " (" << TypeHelper::find(FieldDescriptor::TypeToCppType(field_codec.field_type()))->as_str()
507  << ") | wire type: " << TypeHelper::find(field_codec.wire_type())->as_str();
508  }
509 
510  inline Exception type_error(const std::string& action,
511  const std::type_info& expected,
512  const std::type_info& got)
513  {
514  std::string e = "error " + action + ", expected: ";
515  e += expected.name();
516  e += ", got ";
517  e += got.name();
518  return Exception(e);
519  }
520 
521 
522 }
523 
524 
525 #endif
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:214
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
void field_validate(bool *b, const google::protobuf::FieldDescriptor *field)
Validate this field, checking that all required option extensions are set (e.g. (dccl.field).max and (dccl.field).min for arithmetic codecs)
dccl::DCCLFieldOptions dccl_field_options() const
Get the DCCL field option extension value for the current field.
Definition: field_codec.h:321
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:381
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:207
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec.h:401
void field_decode_repeated(Bitset *bits, std::vector< boost::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
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:389
void field_min_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the lower bound on this field&#39;s size (in bits)
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
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
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
Definition: field_codec.h:75
virtual unsigned min_size()=0
Calculate minimum size of the field in bits.
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)
void require(bool b, const std::string &description)
Essentially an assertion to be used in the validate() virtual method.
Definition: field_codec.h:335
void field_decode(Bitset *bits, boost::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
void field_size(unsigned *bit_size, const boost::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
virtual void any_decode(Bitset *bits, boost::any *wire_value)=0
Virtual method used to decode.
unsigned ceil_log2(dccl::uint64 v)
Definition: binary.h:180
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
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
Provides FromProtoTypeBase and FromProtoCppTypeBase type identification helper classes for various re...
Definition: type_helper.h:39
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)
A class for managing the various field codecs. Here you can add and remove field codecs. The DCCL Codec and DefaultMessageCodec use the find() methods to locate the appropriate field codec.
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:284
static const google::protobuf::Descriptor * this_descriptor()
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
Definition: field_codec.h:91
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
virtual unsigned max_size()=0
Calculate maximum size of the field in bits.
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.
Dynamic Compact Control Language namespace.
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:277
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition: field_codec.h:47
void field_size_repeated(unsigned *bit_size, const std::vector< boost::any > &wire_values, const google::protobuf::FieldDescriptor *field)
Calculate the size of a repeated field.
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
virtual unsigned any_size(const boost::any &wire_value)=0
Virtual method for calculating the size of a field (in bits).
std::string name() const
the name of the codec used to identifier it in the .proto custom option extension ...
Definition: field_codec.h:60
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...
void base_validate(const google::protobuf::Descriptor *desc, MessagePart part)
Validate this part of the message to make sure all required extensions are set.
static MessagePart part()
the part of the message currently being encoded (head or body).
Definition: field_codec.h:118
Exception class for DCCL.
Definition: exception.h:31
virtual void any_encode(Bitset *bits, const boost::any &wire_value)=0
Virtual method used to 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
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy...
Definition: bitset.h:38
bool use_required()
Whether to use the required or optional encoding.
Definition: field_codec.h:348
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field&#39;s size (in bits)