source: finroc_plugins_network_transport/runtime_info/tRemoteType.cpp @ 59:05a17c743d44

17.03
Last change on this file since 59:05a17c743d44 was 59:05a17c743d44, checked in by Max Reichardt <mreichardt@…>, 15 months ago

Makes serialization of auto-named data types include custom names assigned via rrlib_rtti - when connected to development tools

File size: 12.3 KB
Line 
1//
2// You received this file as part of Finroc
3// A framework for intelligent robot control
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    plugins/network_transport/runtime_info/tRemoteType.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2017-02-26
27 *
28 */
29//----------------------------------------------------------------------
30#include "plugins/network_transport/runtime_info/tRemoteType.h"
31
32//----------------------------------------------------------------------
33// External includes (system with <>, local with "")
34//----------------------------------------------------------------------
35
36//----------------------------------------------------------------------
37// Internal includes with ""
38//----------------------------------------------------------------------
39#include "plugins/network_transport/runtime_info/definitions.h"
40
41//----------------------------------------------------------------------
42// Debugging
43//----------------------------------------------------------------------
44#include <cassert>
45
46//----------------------------------------------------------------------
47// Namespace usage
48//----------------------------------------------------------------------
49
50//----------------------------------------------------------------------
51// Namespace declaration
52//----------------------------------------------------------------------
53namespace finroc
54{
55namespace network_transport
56{
57namespace runtime_info
58{
59
60//----------------------------------------------------------------------
61// Forward declarations / typedefs / enums
62//----------------------------------------------------------------------
63
64//----------------------------------------------------------------------
65// Const values
66//----------------------------------------------------------------------
67
68//----------------------------------------------------------------------
69// Implementation
70//----------------------------------------------------------------------
71
72namespace
73{
74
75// Type name generation copied/adapter from rrlib/rtti/tType.cpp
76
77template <typename T>
78inline void StreamChars(std::ostream& stream, const T chars)
79{
80  stream << chars;
81}
82
83template <typename TStream>
84void StreamType(TStream& stream, const tRemoteType& type)
85{
86  switch (type.GetTypeClassification())
87  {
88  case rrlib::rtti::tTypeClassification::RPC_TYPE:
89  case rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE:
90  case rrlib::rtti::tTypeClassification::OTHER_DATA_TYPE:
91  case rrlib::rtti::tTypeClassification::INTEGRAL:
92  case rrlib::rtti::tTypeClassification::NULL_TYPE:
93    StreamChars(stream, type.GetName());
94    break;
95  case rrlib::rtti::tTypeClassification::ARRAY:
96    StreamChars(stream, "Array<");
97    StreamType(stream, type.GetElementType());
98    StreamChars(stream, ", ");
99    char buffer[100];
100    sprintf(buffer, "%zu", type.GetArraySize());
101    StreamChars(stream, buffer);
102    StreamChars(stream, '>');
103    break;
104  case rrlib::rtti::tTypeClassification::LIST:
105    StreamChars(stream, "List<");
106    StreamType(stream, type.GetElementType());
107    StreamChars(stream, '>');
108    break;
109  case rrlib::rtti::tTypeClassification::ENUM_BASED_FLAGS:
110    StreamChars(stream, "EnumFlags<");
111    StreamType(stream, type.GetElementType());
112    StreamChars(stream, '>');
113    break;
114  case rrlib::rtti::tTypeClassification::PAIR:
115    StreamChars(stream, "Pair<");
116    StreamType(stream, type.GetTupleElementType(0));
117    StreamChars(stream, ", ");
118    StreamType(stream, type.GetTupleElementType(1));
119    StreamChars(stream, '>');
120    break;
121  default:
122    break;
123  case rrlib::rtti::tTypeClassification::TUPLE:
124    size_t tuple_size = type.GetTupleElementCount();
125    StreamChars(stream, "Tuple<");
126    for (size_t i = 0; i < tuple_size; i++)
127    {
128      StreamType(stream, type.GetTupleElementType(i));
129      StreamChars(stream, i == tuple_size - 1 ? ">" : ", ");
130    }
131    break;
132  }
133}
134
135rrlib::thread::tRecursiveMutex mutables_mutex("Remote Type Resolve Mutex");
136}
137
138void tRemoteType::DeserializeRegisterEntry(rrlib::serialization::tInputStream& stream)
139{
140  *this = tRemoteType(); // Reset this object
141  const bool legacy_procotol = stream.GetSourceInfo().revision == 0;
142  type_register = rrlib::serialization::PublishedRegisters::GetRemoteRegister<tRemoteType>(stream);
143
144  if (legacy_procotol)
145  {
146    enum { cLEGACY_ENUM_FLAG = 1 << 3 };
147
148    stream.ReadShort(); // Default update time
149    stream.ReadByte(); // Type classification
150
151    name = stream.ReadString();
152    types_checked = rrlib::rtti::tType::GetTypeCount();
153    local_data_type = rrlib::rtti::tType::FindType(name);
154
155    // read additional data we do not need in C++ (remote type traits and enum constant names)
156    int8_t traits = stream.ReadByte(); // type traits
157    if (traits & cLEGACY_ENUM_FLAG)
158    {
159      short n = stream.ReadShort();
160      for (short i = 0; i < n; i++)
161      {
162        stream.SkipString();
163      }
164    }
165  }
166  else
167  {
168    type_traits = stream.ReadShort() << 8;
169    underlying_type = (type_traits & rrlib::rtti::trait_flags::cHAS_UNDERLYING_TYPE) ? stream.ReadShort() : 0;
170    switch (GetTypeClassification())
171    {
172    case rrlib::rtti::tTypeClassification::LIST:
173    case rrlib::rtti::tTypeClassification::ENUM_BASED_FLAGS:
174      element_type = stream.ReadShort();
175      break;
176    case rrlib::rtti::tTypeClassification::ARRAY:
177      element_type = stream.ReadShort();
178      array_size = stream.ReadInt();
179      break;
180    case rrlib::rtti::tTypeClassification::RPC_TYPE:
181    case rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE:
182    case rrlib::rtti::tTypeClassification::INTEGRAL:
183    case rrlib::rtti::tTypeClassification::OTHER_DATA_TYPE:
184      name = stream.ReadString();
185      types_checked = rrlib::rtti::tType::GetTypeCount();
186      local_data_type = rrlib::rtti::tType::FindType(name);
187      break;
188    case rrlib::rtti::tTypeClassification::PAIR:
189    case rrlib::rtti::tTypeClassification::TUPLE:
190    {
191      uint tuple_element_count = GetTypeClassification() == rrlib::rtti::tTypeClassification::TUPLE ? stream.ReadShort() : 2;
192      tuple_elements.reserve(tuple_element_count);
193      for (uint i = 0; i < tuple_element_count; i++)
194      {
195        tuple_elements.push_back(stream.ReadShort());
196      }
197    }
198    break;
199    case rrlib::rtti::tTypeClassification::NULL_TYPE:
200      local_data_type = rrlib::rtti::tType();
201      name = local_data_type.GetName();
202      types_checked = rrlib::rtti::tType::GetTypeCount();
203      break;
204    default:
205      throw std::runtime_error("Received erroneous type traits (invalid type classification)");
206    }
207  }
208}
209
210rrlib::rtti::tType tRemoteType::GetLocalDataType() const
211{
212  if (local_data_type)
213  {
214    return local_data_type;
215  }
216  rrlib::thread::tLock lock(mutables_mutex);
217  if (local_data_type)
218  {
219    return local_data_type;
220  }
221  if (name.length() == 0)
222  {
223    GetName();
224  }
225  if (name.length() && types_checked < rrlib::rtti::tType::GetTypeCount())
226  {
227    types_checked = rrlib::rtti::tType::GetTypeCount();
228    local_data_type = rrlib::rtti::tType::FindType(GetName());  // TODO: lookup by element types or tuple element types could also be done
229  }
230  return local_data_type;
231}
232
233const std::string& tRemoteType::GetName() const
234{
235  rrlib::thread::tLock lock(mutables_mutex);
236  if (name.length() == 0)
237  {
238    std::stringstream stream;
239    StreamType(stream, *this);
240    name = stream.str();
241  }
242  return name;
243}
244
245
246void tRemoteType::SerializeRegisterEntry(rrlib::serialization::tOutputStream& stream, const rrlib::rtti::tType& type)
247{
248  const bool legacy_procotol = stream.GetTargetInfo().revision == 0;
249
250  if (legacy_procotol)
251  {
252    stream.WriteShort(type.GetHandle());
253    stream.WriteShort(-1); // Default update time (legacy, unused in C++)
254    stream.WriteByte(0); // Type classification (legacy, unused in C++)
255    stream.WriteString(type.GetName());
256    stream.WriteByte(0); // type traits (legacy, unused in C++)
257  }
258  else
259  {
260    const bool java_client = stream.GetTargetInfo().custom_info & tSerializationInfoFlags::cJAVA_CLIENT;
261    const bool send_custom_names_for_auto_named_types = java_client && stream.GetTargetInfo().revision >= 2003;
262    const bool send_custom_name_for_this_type = send_custom_names_for_auto_named_types && type.GetTypeClassification() <= rrlib::rtti::tTypeClassification::AUTO_NAMED && type.GetPlainTypeName();
263    const auto cCUSTOM_NAME_FLAG = rrlib::rtti::trait_flags::cIS_ENUM;  // Flag is irrelevant/unused for auto-named types
264    const auto extra_flag = send_custom_name_for_this_type ? cCUSTOM_NAME_FLAG : 0;
265
266    stream.WriteShort(static_cast<uint16_t>(((type.GetTypeTraits() | extra_flag) >> 8) & 0xFFFF));
267    if (type.GetTypeTraits() & rrlib::rtti::trait_flags::cHAS_UNDERLYING_TYPE)
268    {
269      stream.WriteShort(type.GetUnderlyingType().GetHandle());
270    }
271
272    if (send_custom_name_for_this_type)
273    {
274      stream.WriteString(type.GetPlainTypeName());
275    }
276
277    switch (type.GetTypeClassification())
278    {
279    case rrlib::rtti::tTypeClassification::LIST:
280    case rrlib::rtti::tTypeClassification::ARRAY:
281    case rrlib::rtti::tTypeClassification::ENUM_BASED_FLAGS:
282      stream.WriteShort(type.GetElementType().GetHandle());
283      if (type.IsArray())
284      {
285        stream.WriteInt(type.GetArraySize());
286      }
287      break;
288
289    case rrlib::rtti::tTypeClassification::PAIR:
290    case rrlib::rtti::tTypeClassification::TUPLE:
291    {
292      if (java_client)
293      {
294        stream.WriteInt(type.GetSize());
295      }
296      auto tuple_info = type.GetTupleTypes();
297      if (type.GetTypeClassification() != rrlib::rtti::tTypeClassification::PAIR)
298      {
299        stream.WriteShort(tuple_info.second);
300      }
301      for (uint i = 0; i < tuple_info.second; i++)
302      {
303        stream.WriteShort(rrlib::rtti::tType(tuple_info.first[i].type_info).GetHandle());
304      }
305    }
306    break;
307
308    case rrlib::rtti::tTypeClassification::RPC_TYPE:
309    case rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE:
310      stream.WriteString(type.GetPlainTypeName());
311      break;
312
313    case rrlib::rtti::tTypeClassification::INTEGRAL:
314    case rrlib::rtti::tTypeClassification::OTHER_DATA_TYPE:
315      stream.WriteString(type.GetPlainTypeName());
316      if (java_client)
317      {
318        stream.WriteInt(type.GetSize());
319        if (type.GetTypeTraits() & rrlib::rtti::trait_flags::cIS_ENUM)
320        {
321          const make_builder::internal::tEnumStrings* enum_strings = type.GetEnumStringsData();
322          assert(enum_strings->size <= std::numeric_limits<short>::max() + 1); // more values would be quite ridiculous
323          stream.WriteShort(static_cast<uint16_t>(enum_strings->size));
324          bool send_values = enum_strings->non_standard_values;
325          rrlib::rtti::tType underlying_type = type.GetUnderlyingType();
326          const char* value_pointer = static_cast<const char*>(enum_strings->non_standard_values);
327          stream.WriteByte(send_values ? underlying_type.GetSize() : 0); // Note that send_values is no type trait (flag) as it not a compile-time constant (at least not straight-forward)
328          for (size_t j = 0; j < enum_strings->size; j++)
329          {
330            const char* enum_string = enum_strings->strings[static_cast<size_t>(make_builder::tEnumStringsFormat::NATURAL)][j];
331            stream.WriteString(enum_string);
332            if (send_values)
333            {
334              rrlib::rtti::tTypedConstPointer value(value_pointer, underlying_type);
335              value.Serialize(stream);
336              value_pointer += underlying_type.GetSize();
337            }
338          }
339        }
340      }
341      break;
342    case rrlib::rtti::tTypeClassification::NULL_TYPE:
343      break;
344    }
345  }
346}
347
348//----------------------------------------------------------------------
349// End of namespace declaration
350//----------------------------------------------------------------------
351}
352}
353}
Note: See TracBrowser for help on using the repository browser.