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