DCCL v4
Loading...
Searching...
No Matches
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
31void 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
39unsigned 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
47void 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
128unsigned dccl::v2::DefaultMessageCodec::max_size()
129{
130 unsigned u = 0;
131 traverse_descriptor<MaxSize>(&u);
132 return u;
133}
134
135unsigned dccl::v2::DefaultMessageCodec::min_size()
136{
137 unsigned u = 0;
138 traverse_descriptor<MinSize>(&u);
139 return u;
140}
141
142void 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
154std::string dccl::v2::DefaultMessageCodec::info()
155{
156 std::stringstream ss;
157 traverse_descriptor<Info>(&ss);
158 return ss.str();
159}
160
161std::size_t dccl::v2::DefaultMessageCodec::hash()
162{
163 std::size_t hash = 0;
164 traverse_descriptor<Hash>(&hash);
165 return hash;
166}
167
168bool 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}
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.