DCCL v3
field_codec_default_message.cpp
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 #include "dccl/codec.h"
23 #include "field_codec_default_message.h"
24 
25 using dccl::dlog;
26 
27 //
28 // DefaultMessageCodec
29 //
30 
31 void dccl::v2::DefaultMessageCodec::any_encode(Bitset* bits, const boost::any& wire_value)
32 {
33  if(wire_value.empty())
34  *bits = Bitset(min_size());
35  else
36  *bits = traverse_const_message<Encoder, Bitset>(wire_value);
37 }
38 
39 
40 
41 unsigned dccl::v2::DefaultMessageCodec::any_size(const boost::any& wire_value)
42 {
43  if(wire_value.empty())
44  return min_size();
45  else
46  return traverse_const_message<Size, unsigned>(wire_value);
47 }
48 
49 
50 void dccl::v2::DefaultMessageCodec::any_decode(Bitset* bits, boost::any* wire_value)
51 {
52  try
53  {
54 
55  google::protobuf::Message* msg = boost::any_cast<google::protobuf::Message* >(*wire_value);
56 
57  const google::protobuf::Descriptor* desc = msg->GetDescriptor();
58  const google::protobuf::Reflection* refl = msg->GetReflection();
59 
60  for(int i = 0, n = desc->field_count(); i < n; ++i)
61  {
62 
63  const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
64 
65  if(!check_field(field_desc))
66  continue;
67 
68 
69  boost::shared_ptr<FieldCodecBase> codec = find(field_desc);
70  boost::shared_ptr<internal::FromProtoCppTypeBase> helper =
71  internal::TypeHelper::find(field_desc);
72 
73  if(field_desc->is_repeated())
74  {
75  std::vector<boost::any> wire_values;
76  if(field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
77  {
78  for(unsigned j = 0, m = field_desc->options().GetExtension(dccl::field).max_repeat(); j < m; ++j)
79  wire_values.push_back(refl->AddMessage(msg, field_desc));
80 
81  codec->field_decode_repeated(bits, &wire_values, field_desc);
82 
83  for(int j = 0, m = wire_values.size(); j < m; ++j)
84  {
85  if(wire_values[j].empty()) refl->RemoveLast(msg, field_desc);
86  }
87  }
88  else
89  {
90  // for primitive types
91  codec->field_decode_repeated(bits, &wire_values, field_desc);
92  for(int j = 0, m = wire_values.size(); j < m; ++j)
93  helper->add_value(field_desc, msg, wire_values[j]);
94  }
95  }
96  else
97  {
98  boost::any wire_value;
99  if(field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
100  {
101  // allows us to propagate pointers instead of making many copies of entire messages
102  wire_value = refl->MutableMessage(msg, field_desc);
103  codec->field_decode(bits, &wire_value, field_desc);
104  if(wire_value.empty()) refl->ClearField(msg, field_desc);
105  }
106  else
107  {
108  // for primitive types
109  codec->field_decode(bits, &wire_value, field_desc);
110  helper->set_value(field_desc, msg, wire_value);
111  }
112  }
113  }
114 
115  std::vector< const google::protobuf::FieldDescriptor* > set_fields;
116  refl->ListFields(*msg, &set_fields);
117  if(set_fields.empty() && this_field()) *wire_value = boost::any();
118  else *wire_value = msg;
119  }
120  catch(boost::bad_any_cast& e)
121  {
122  throw(Exception("Bad type given to traverse mutable, expecting google::protobuf::Message*, got " + std::string(wire_value->type().name())));
123  }
124 
125 }
126 
127 
128 unsigned dccl::v2::DefaultMessageCodec::max_size()
129 {
130  unsigned u = 0;
131  traverse_descriptor<MaxSize>(&u);
132  return u;
133 }
134 
135 unsigned dccl::v2::DefaultMessageCodec::min_size()
136 {
137  unsigned u = 0;
138  traverse_descriptor<MinSize>(&u);
139  return u;
140 }
141 
142 
143 void dccl::v2::DefaultMessageCodec::validate()
144 {
145  bool b = false;
146  traverse_descriptor<Validate>(&b);
147 }
148 
149 std::string dccl::v2::DefaultMessageCodec::info()
150 {
151  std::stringstream ss;
152  traverse_descriptor<Info>(&ss);
153  return ss.str();
154 }
155 
156 bool dccl::v2::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field)
157 {
158  if(!field)
159  {
160  return true;
161  }
162  else
163  {
164  dccl::DCCLFieldOptions dccl_field_options = field->options().GetExtension(dccl::field);
165  if(dccl_field_options.omit()) // omit
166  {
167  return false;
168  }
169  else if(internal::MessageStack::current_part() == UNKNOWN) // part not yet explicitly specified
170  {
171  if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
172  find(field)->name() == Codec::default_codec_name()) // default message codec will expand
173  return true;
174  else if((part() == HEAD && !dccl_field_options.in_head())
175  || (part() == BODY && dccl_field_options.in_head()))
176  return false;
177  else
178  return true;
179  }
180  else if(internal::MessageStack::current_part() != part()) // part specified and doesn't match
181  return false;
182  else
183  return true;
184  }
185 }
186 
187 
dccl::DCCLFieldOptions
Definition: option_extensions.pb.h:278
Message