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 
121 
132 
133 
139  void base_encode(Bitset* bits,
140  const google::protobuf::Message& msg,
141  MessagePart part);
142 
148  void base_size(unsigned* bit_size, const google::protobuf::Message& msg, MessagePart part);
149 
155  void base_decode(Bitset* bits,
157  MessagePart part);
158 
164  void base_max_size(unsigned* bit_size, const google::protobuf::Descriptor* desc, MessagePart part);
165 
171  void base_min_size(unsigned* bit_size, const google::protobuf::Descriptor* desc, MessagePart part);
172 
177  void base_validate(const google::protobuf::Descriptor* desc, MessagePart part);
178 
184  void base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessagePart part);
186 
188  //
197 
198 
203  void field_pre_encode(boost::any* wire_value, const boost::any& field_value)
204  { any_pre_encode(wire_value, field_value); }
205 
210  void field_pre_encode_repeated(std::vector<boost::any>* wire_values,
211  const std::vector<boost::any>& field_values)
212  { any_pre_encode_repeated(wire_values, field_values); }
213 
214  // traverse const
215 
221  void field_encode(Bitset* bits,
222  const boost::any& field_value,
223  const google::protobuf::FieldDescriptor* field);
224 
230  void field_encode_repeated(Bitset* bits,
231  const std::vector<boost::any>& field_values,
232  const google::protobuf::FieldDescriptor* field);
233 
239  void field_size(unsigned* bit_size, const boost::any& field_value,
240  const google::protobuf::FieldDescriptor* field);
241 
247  void field_size_repeated(unsigned* bit_size, const std::vector<boost::any>& wire_values,
248  const google::protobuf::FieldDescriptor* field);
249 
250  // traverse mutable
256  void field_decode(Bitset* bits,
257  boost::any* field_value,
258  const google::protobuf::FieldDescriptor* field);
259 
265  void field_decode_repeated(Bitset* bits,
266  std::vector<boost::any>* field_values,
267  const google::protobuf::FieldDescriptor* field);
268 
273  void field_post_decode(const boost::any& wire_value, boost::any* field_value)
274  { any_post_decode(wire_value, field_value); }
275 
280  void field_post_decode_repeated(const std::vector<boost::any>& wire_values,
281  std::vector<boost::any>* field_values)
282  { any_post_decode_repeated(wire_values, field_values); }
283 
284 
285  // traverse schema (Descriptor)
286 
291  void field_max_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
296  void field_min_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
297 
303  void field_validate(bool* b, const google::protobuf::FieldDescriptor* field);
304 
309  void field_info(std::ostream* os, const google::protobuf::FieldDescriptor* field);
311 
312  protected:
313 
318  {
319  if(this_field())
320  return this_field()->options().GetExtension(dccl::field);
321  else
322  throw(Exception("Cannot call dccl_field on base message (has no *field* option extension"));
323 
324  }
325 
331  void require(bool b, const std::string& description)
332  {
333  if(!b)
334  {
335  if(this_field())
336  throw(Exception("Field " + this_field()->name() + " failed validation: " + description));
337  else
338  throw(Exception("Message " + this_descriptor()->name() + " failed validation: " + description));
339  }
340 
341  }
342 
345  {
346  const google::protobuf::FieldDescriptor* field = this_field();
347  if(!field)
348  return true;
349  else if(codec_version() > 2) // use required for both repeated and required fields
350  return field->is_required() || field->is_repeated();
351  else // use required only for required fields
352  return field->is_required();
353  }
354 
355 
356  //
357  // VIRTUAL
358  //
359 
360  // contain boost::any
365  virtual void any_encode(Bitset* bits, const boost::any& wire_value) = 0;
366 
371  virtual void any_decode(Bitset* bits, boost::any* wire_value) = 0;
372 
377  virtual void any_pre_encode(boost::any* wire_value,
378  const boost::any& field_value)
379  { *wire_value = field_value; }
380 
385  virtual void any_post_decode(const boost::any& wire_value,
386  boost::any* field_value)
387  { *field_value = wire_value; }
388 
393  virtual unsigned any_size(const boost::any& wire_value) = 0;
394 
395  // no boost::any
397  virtual void validate() { }
398 
402  virtual std::string info();
403 
407  virtual unsigned max_size() = 0;
408 
412  virtual unsigned min_size() = 0;
413 
414  virtual void any_encode_repeated(Bitset* bits, const std::vector<boost::any>& wire_values);
415  virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* field_values);
416 
417  virtual void any_pre_encode_repeated(std::vector<boost::any>* wire_values,
418  const std::vector<boost::any>& field_values);
419 
420  virtual void any_post_decode_repeated(const std::vector<boost::any>& wire_values,
421  std::vector<boost::any>* field_values);
422 
423  virtual unsigned any_size_repeated(const std::vector<boost::any>& wire_values);
424  virtual unsigned max_size_repeated();
425  virtual unsigned min_size_repeated();
426 
427  friend class FieldCodecManager;
428  private:
429  // codec information
430  void set_name(const std::string& name)
431  { name_ = name; }
432  void set_field_type(google::protobuf::FieldDescriptor::Type type)
433  { field_type_ = type; }
434  void set_wire_type(google::protobuf::FieldDescriptor::CppType type)
435  { wire_type_ = type; }
436 
437  bool variable_size()
438  {
439  if(this_field() && this_field()->is_repeated())
440  return max_size_repeated() != min_size_repeated();
441  else
442  return max_size() != min_size();
443  }
444 
445  int repeated_vector_field_size(int max_repeat)
446  { return dccl::ceil_log2(max_repeat+1); }
447 
448  void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size = -1);
449 
450 
451  private:
452  // sets global statics relating the current message begin processed
453  // and unsets them on destruction
454  struct BaseRAII
455  {
456  BaseRAII(MessagePart part,
457  const google::protobuf::Descriptor* root_descriptor)
458  {
459  FieldCodecBase::part_ = part;
460  FieldCodecBase::root_message_ = 0;
461  FieldCodecBase::root_descriptor_ = root_descriptor;
462  }
463 
464  BaseRAII(MessagePart part,
465  const google::protobuf::Message* root_message)
466  {
467  FieldCodecBase::part_ = part;
468  FieldCodecBase::root_message_ = root_message;
469  FieldCodecBase::root_descriptor_ = root_message->GetDescriptor();
470  }
471  ~BaseRAII()
472  {
473  FieldCodecBase::part_ = dccl::UNKNOWN;
474  FieldCodecBase::root_message_ = 0;
475  FieldCodecBase::root_descriptor_ = 0;
476  }
477  };
478 
479 
480  static MessagePart part_;
481  static const google::protobuf::Message* root_message_;
482  static const google::protobuf::Descriptor* root_descriptor_;
483 
484  std::string name_;
485  google::protobuf::FieldDescriptor::Type field_type_;
486  google::protobuf::FieldDescriptor::CppType wire_type_;
487 
488  };
489 
490  inline std::ostream& operator<<(std::ostream& os, const FieldCodecBase& field_codec )
491  {
492  using google::protobuf::FieldDescriptor;
493  using internal::TypeHelper;
494  return os << "[FieldCodec '" << field_codec.name() << "']: field type: "
495  << TypeHelper::find(field_codec.field_type())->as_str()
496  << " (" << TypeHelper::find(FieldDescriptor::TypeToCppType(field_codec.field_type()))->as_str()
497  << ") | wire type: " << TypeHelper::find(field_codec.wire_type())->as_str();
498  }
499 
500  inline Exception type_error(const std::string& action,
501  const std::type_info& expected,
502  const std::type_info& got)
503  {
504  std::string e = "error " + action + ", expected: ";
505  e += expected.name();
506  e += ", got ";
507  e += got.name();
508  return Exception(e);
509  }
510 
511 
512 }
513 
514 
515 #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:210
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:317
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:377
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:203
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec.h:397
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:385
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_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:90
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_encode(Bitset *bits, const google::protobuf::Message &msg, MessagePart part)
Encode this part (body or head) of the base message.
Definition: field_codec.cpp:42
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:331
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:178
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:74
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:280
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:273
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:30
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:56
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:344
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field&#39;s size (in bits)