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