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