DCCL v4
field_codec_default_message.cpp
1 // Copyright 2011-2023:
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 // File authors:
6 // Toby Schneider <toby@gobysoft.org>
7 //
8 //
9 // This file is part of the Dynamic Compact Control Language Library
10 // ("DCCL").
11 //
12 // DCCL is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU Lesser General Public License as published by
14 // the Free Software Foundation, either version 2.1 of the License, or
15 // (at your option) any later version.
16 //
17 // DCCL is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public License
23 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
24 #include "field_codec_default_message.h"
25 #include "../codec.h"
26 
27 //
28 // DefaultMessageCodec
29 //
30 
31 void dccl::v2::DefaultMessageCodec::any_encode(Bitset* bits, const dccl::any& wire_value)
32 {
33  if (is_empty(wire_value))
34  *bits = Bitset(min_size());
35  else
36  *bits = traverse_const_message<Encoder, Bitset>(wire_value);
37 }
38 
39 unsigned dccl::v2::DefaultMessageCodec::any_size(const dccl::any& wire_value)
40 {
41  if (is_empty(wire_value))
42  return min_size();
43  else
44  return traverse_const_message<Size, unsigned>(wire_value);
45 }
46 
47 void dccl::v2::DefaultMessageCodec::any_decode(Bitset* bits, dccl::any* wire_value)
48 {
49  try
50  {
51  auto* msg = dccl::any_cast<google::protobuf::Message*>(*wire_value);
52 
53  const google::protobuf::Descriptor* desc = msg->GetDescriptor();
54  const google::protobuf::Reflection* refl = msg->GetReflection();
55 
56  for (int i = 0, n = desc->field_count(); i < n; ++i)
57  {
58  const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
59 
60  if (!check_field(field_desc))
61  continue;
62 
63  std::shared_ptr<FieldCodecBase> codec = find(field_desc);
64  std::shared_ptr<internal::FromProtoCppTypeBase> helper =
65  manager().type_helper().find(field_desc);
66 
67  if (field_desc->is_repeated())
68  {
69  std::vector<dccl::any> wire_values;
70  if (field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
71  {
72  for (unsigned j = 0,
73  m = field_desc->options().GetExtension(dccl::field).max_repeat();
74  j < m; ++j)
75  wire_values.emplace_back(refl->AddMessage(msg, field_desc));
76 
77  codec->field_decode_repeated(bits, &wire_values, field_desc);
78 
79  for (auto& wire_value : wire_values)
80  {
81  if (is_empty(wire_value))
82  refl->RemoveLast(msg, field_desc);
83  }
84  }
85  else
86  {
87  // for primitive types
88  codec->field_decode_repeated(bits, &wire_values, field_desc);
89  for (auto& wire_value : wire_values)
90  helper->add_value(field_desc, msg, wire_value);
91  }
92  }
93  else
94  {
95  dccl::any wire_value;
96  if (field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
97  {
98  // allows us to propagate pointers instead of making many copies of entire messages
99  wire_value = refl->MutableMessage(msg, field_desc);
100  codec->field_decode(bits, &wire_value, field_desc);
101  if (is_empty(wire_value))
102  refl->ClearField(msg, field_desc);
103  }
104  else
105  {
106  // for primitive types
107  codec->field_decode(bits, &wire_value, field_desc);
108  helper->set_value(field_desc, msg, wire_value);
109  }
110  }
111  }
112 
113  std::vector<const google::protobuf::FieldDescriptor*> set_fields;
114  refl->ListFields(*msg, &set_fields);
115  if (set_fields.empty() && this_field())
116  *wire_value = dccl::any();
117  else
118  *wire_value = msg;
119  }
120  catch (dccl::bad_any_cast& e)
121  {
122  throw(Exception(
123  "Bad type given to traverse mutable, expecting google::protobuf::Message*, got " +
124  std::string(wire_value->type().name())));
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 void dccl::v2::DefaultMessageCodec::validate()
143 {
144  bool b = false;
145 
146  const google::protobuf::Descriptor* desc = FieldCodecBase::this_descriptor();
147 
148  if (desc->oneof_decl_count() != 0)
149  throw(Exception("DCCL Codec Version 2 does not support 'oneof' declarations"), desc);
150 
151  traverse_descriptor<Validate>(&b);
152 }
153 
154 std::string dccl::v2::DefaultMessageCodec::info()
155 {
156  std::stringstream ss;
157  traverse_descriptor<Info>(&ss);
158  return ss.str();
159 }
160 
161 std::size_t dccl::v2::DefaultMessageCodec::hash()
162 {
163  std::size_t hash = 0;
164  traverse_descriptor<Hash>(&hash);
165  return hash;
166 }
167 
168 bool dccl::v2::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field)
169 {
170  if (!field)
171  {
172  return true;
173  }
174  else
175  {
176  dccl::DCCLFieldOptions dccl_field_options = field->options().GetExtension(dccl::field);
177  if (dccl_field_options.omit()) // omit
178  {
179  return false;
180  }
181  else if (message_data().current_part() == UNKNOWN) // part not yet explicitly specified
182  {
183  if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
184  find(field)->name() ==
185  Codec::default_codec_name()) // default message codec will expand
186  return true;
187  else if ((part() == HEAD && !dccl_field_options.in_head()) ||
188  (part() == BODY && dccl_field_options.in_head()))
189  return false;
190  else
191  return true;
192  }
193  else if (message_data().current_part() != part()) // part specified and doesn't match
194  return false;
195  else
196  return true;
197  }
198 }
dccl::FieldCodecBase::this_descriptor
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
Definition: field_codec.cpp:657
dccl::DCCLFieldOptions
Definition: option_extensions.pb.h:476