DCCL v4
Loading...
Searching...
No Matches
field_codec_message_stack.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_message_stack.h"
25#include "../field_codec.h"
26
27// MessageStack
28//
29
30void dccl::internal::MessageStack::push(const google::protobuf::Descriptor* desc)
31
32{
33 data_.desc.push_back(desc);
34 ++descriptors_pushed_;
35}
36
37void dccl::internal::MessageStack::push(const google::protobuf::FieldDescriptor* field)
38{
39 data_.field.push_back(field);
40 ++fields_pushed_;
41}
42
43void dccl::internal::MessageStack::push(MessagePart part)
44{
45 data_.parts.push_back(part);
46 ++parts_pushed_;
47}
48
49void dccl::internal::MessageStack::__pop_desc()
50{
51 if (!data_.desc.empty())
52 data_.desc.pop_back();
53 --descriptors_pushed_;
54}
55
56void dccl::internal::MessageStack::__pop_field()
57{
58 if (!data_.field.empty())
59 data_.field.pop_back();
60 --fields_pushed_;
61}
62
63void dccl::internal::MessageStack::__pop_parts()
64{
65 if (!data_.parts.empty())
66 data_.parts.pop_back();
67 --parts_pushed_;
68}
69
70void dccl::internal::MessageStack::__pop_messages()
71{
72 if (!data_.messages.empty())
73 data_.messages.pop_back();
74 --messages_pushed_;
75}
76
77dccl::internal::MessageStack::MessageStack(const google::protobuf::Message* root_message,
78 MessageStackData& data,
79 const google::protobuf::FieldDescriptor* field)
80 : data_(data), descriptors_pushed_(0), fields_pushed_(0), parts_pushed_(0), messages_pushed_(0)
81{
82 if (field)
83 {
84 if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
85 {
86 MessagePart part = UNKNOWN;
87 if (field->options().GetExtension(dccl::field).has_in_head())
88 {
89 // if explicitly set, set part (HEAD or BODY) of message for all children of this message
90 part = field->options().GetExtension(dccl::field).in_head() ? HEAD : BODY;
91 }
92 else
93 {
94 // use the parent's current part
95 part = current_part();
96 }
97 push(part);
98 push(field->message_type());
99 }
100 push_message(root_message, field);
101 push(field);
102 }
103}
104
105void dccl::internal::MessageStack::update_index(const google::protobuf::Message* root_message,
106 const google::protobuf::FieldDescriptor* field,
107 int index)
108{
109 push_message(root_message, field, index);
110}
111
112void dccl::internal::MessageStack::push_message(const google::protobuf::Message* root_message,
113 const google::protobuf::FieldDescriptor* field,
114 int index)
115{
116 if (data_.messages.empty() && root_message)
117 {
118 data_.messages.push_back({root_message, nullptr});
119 ++messages_pushed_;
120 }
121
122 if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
123 {
124 // replace if the previous push was the same field
125 if (!data_.messages.empty() && field == data_.messages.back().field &&
126 !data_.messages.empty())
127 {
128 data_.messages.pop_back();
129 --messages_pushed_;
130 }
131
132 // add the new message + field if possible
133 if (data_.messages.size() &&
134 data_.messages.back().msg->GetDescriptor() == field->containing_type())
135 {
136 const auto* refl = data_.messages.back().msg->GetReflection();
137 if (field->is_repeated())
138 {
139 if (index >= 0 && index < refl->FieldSize(*data_.messages.back().msg, field))
140 {
141 data_.messages.push_back(
142 {&refl->GetRepeatedMessage(*data_.messages.back().msg, field, index),
143 field});
144 ++messages_pushed_;
145 }
146 }
147 else
148 {
149 data_.messages.push_back(
150 {&refl->GetMessage(*data_.messages.back().msg, field), field});
151 ++messages_pushed_;
152 }
153 }
154 }
155}
156
157dccl::internal::MessageStack::~MessageStack()
158{
159 while (fields_pushed_ > 0) __pop_field();
160 while (descriptors_pushed_ > 0) __pop_desc();
161 while (parts_pushed_ > 0) __pop_parts();
162 while (messages_pushed_ > 0) __pop_messages();
163}