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