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
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
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:326
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
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
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec.h:409
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:397
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:340
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:289
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:282
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition: field_codec.h:47
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
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.
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:353
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
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field&#39;s size (in bits)