source: finroc_plugins_composite_ports/tInterfaceBase.cpp @ 36:ea39cd84ad73

Last change on this file since 36:ea39cd84ad73 was 36:ea39cd84ad73, checked in by Max Reichardt <max.reichardt@…>, 2 years ago

Adds and integrates rrlib_rtti conversion operations for possibly customized connecting of port composite interfaces

File size: 45.4 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/composite_ports/tInterfaceBase.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2020-01-14
27 *
28 */
29//----------------------------------------------------------------------
30#include "plugins/composite_ports/tInterfaceBase.h"
31
32//----------------------------------------------------------------------
33// External includes (system with <>, local with "")
34//----------------------------------------------------------------------
35#include "core/tFrameworkElementTags.h"
36#include "core/tRuntimeEnvironment.h"
37#include "rrlib/util/string.h"
38#include "rrlib/rtti_conversion/tStaticCastOperation.h"
39
40//----------------------------------------------------------------------
41// Internal includes with ""
42//----------------------------------------------------------------------
43#include "plugins/composite_ports/internal/tInterfaceTypeInfo.h"
44#include "plugins/composite_ports/internal/type_traits.h"
45#include "plugins/composite_ports/defined_conversions.h"
46#include "plugins/composite_ports/tInterfaceModifier.h"
47#include "plugins/composite_ports/interface_types.h"
48#include "plugins/composite_ports/internal/tPortSelectConversionOperation.h"
49#include "plugins/composite_ports/utils/tPortSelector.h"
50
51//----------------------------------------------------------------------
52// Debugging
53//----------------------------------------------------------------------
54#include <cassert>
55
56//----------------------------------------------------------------------
57// Namespace usage
58//----------------------------------------------------------------------
59
60//----------------------------------------------------------------------
61// Namespace declaration
62//----------------------------------------------------------------------
63namespace finroc
64{
65namespace composite_ports
66{
67
68//----------------------------------------------------------------------
69// Forward declarations / typedefs / enums
70//----------------------------------------------------------------------
71typedef core::tFrameworkElementFlag tFlag;
72
73//----------------------------------------------------------------------
74// Const values
75//----------------------------------------------------------------------
76const std::string cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION = "finroc.composite_ports.single_backend_instantiation";
77
78//----------------------------------------------------------------------
79// Implementation
80//----------------------------------------------------------------------
81
82namespace
83{
84
85const tInterfaceModifier::tImplementation cMODIFIER_DEFAULT_IMPLEMENTATION;
86
87const core::tFrameworkElement* GetAggregator(const core::tFrameworkElement& element, core::tFrameworkElementFlags* extend_with_default_ports_flags = nullptr)
88{
89  if (element.GetFlag(tFlag::EDGE_AGGREGATOR) && (!element.IsPort()))
90  {
91    if (element.GetFlag(tFlag::INTERFACE) && extend_with_default_ports_flags)
92    {
93      (*extend_with_default_ports_flags) |= static_cast<const core::tPortGroup&>(element).GetDefaultPortFlags();
94      if (element.GetFlag(tFlag::SENSOR_DATA))
95      {
96        (*extend_with_default_ports_flags) |= tFlag::SENSOR_DATA;
97      }
98      if (element.GetFlag(tFlag::CONTROLLER_DATA))
99      {
100        (*extend_with_default_ports_flags) |= tFlag::CONTROLLER_DATA;
101      }
102      if (element.GetFlag(tFlag::INTERFACE_FOR_INPUTS) || element.GetFlag(tFlag::PARAMETER_INTERFACE))
103      {
104        (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_INPUT_PORT_FLAGS;
105      }
106      if (element.GetFlag(tFlag::INTERFACE_FOR_OUTPUTS))
107      {
108        (*extend_with_default_ports_flags) |= data_ports::cDEFAULT_OUTPUT_PORT_FLAGS;
109      }
110      if (element.GetFlag(tFlag::PROXY_INTERFACE))
111      {
112        (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA;
113      }
114      if (element.GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
115      {
116        (*extend_with_default_ports_flags) |= tFlag::EMITS_DATA | tFlag::ACCEPTS_DATA;
117      }
118    }
119    return &element;
120  }
121  return element.GetParent() ? GetAggregator(*element.GetParent(), extend_with_default_ports_flags) : nullptr;
122}
123
124tInterfaceModifier* GetModifier(const core::tFrameworkElement& any_element)
125{
126  auto current_element = &any_element;
127  do
128  {
129    auto annotation = current_element->GetAnnotation<tInterfaceModifier>();
130    if (annotation)
131    {
132      return annotation;
133    }
134    current_element = current_element->GetParent();
135  }
136  while (current_element);
137  return nullptr;
138}
139
140tInterfaceBase::tPrimaryPortType ModifierDefinesPartialInterface(const core::tFrameworkElement& parent, const rrlib::rtti::tType& interface_type)
141{
142  tInterfaceModifier* modifier = GetModifier(parent);
143  if (modifier)
144  {
145    return modifier->Implementation().PartialInterface(interface_type);
146  }
147  return tInterfaceBase::tPrimaryPortType::ANY;
148}
149
150core::tAbstractPortCreationInfo MakeCreationInfo(const rrlib::rtti::tType& interface_type, const std::string& name, core::tFrameworkElement& parent_interface, bool partial_interface, bool shared)
151{
152  core::tAbstractPortCreationInfo result;
153  result.data_type = interface_type;
154  if (partial_interface)
155  {
156    auto partial_type = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo()).GetPartialType();
157    result.data_type = partial_type ? partial_type : result.data_type;
158  }
159  result.parent = &parent_interface;
160  result.flags |= tFlag::INTERFACE;
161  GetAggregator(parent_interface, &result.flags);
162  result.name = name;
163  assert(result.flags.Get(tFlag::EMITS_DATA) || result.flags.Get(tFlag::ACCEPTS_DATA));
164  if (shared)
165  {
166    result.flags |= tFlag::SHARED_PORT;
167  }
168  return result;
169}
170
171void FindInterfacesBelowImplementation(std::vector<tInterfaceBase>& result, core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces)
172{
173  for (auto it = parent.ChildrenBegin(); it != parent.ChildrenEnd(); ++it)
174  {
175    bool is_backend = typeid(*it) == typeid(tInterfaceBase::tBackend);
176    if (is_backend)
177    {
178      tInterfaceBase::tBackend& candidate = static_cast<tInterfaceBase::tBackend&>(*it);
179      if (candidate.IsPrimaryBackend() && (candidate.GetDataType() == type || ((!skip_derived_interfaces) && rrlib::rtti::conversion::tStaticCastOperation::IsImplicitlyConvertibleTo(candidate.GetDataType(), type))))
180      {
181        result.emplace_back(&candidate);
182        continue;
183      }
184    }
185    if ((!it->IsPort()) || is_backend)
186    {
187      FindInterfacesBelowImplementation(result, *it, type, skip_derived_interfaces);
188    }
189  }
190}
191
192//! Connector with operations for custom connecting attached
193class tConversionConnector : public core::tConnector
194{
195
196//----------------------------------------------------------------------
197// Public methods and typedefs
198//----------------------------------------------------------------------
199public:
200
201  tConversionConnector(core::tAbstractPort& source_port, core::tAbstractPort& destination_port, const core::tConnectOptions& connect_options) :
202    tConnector(source_port, destination_port, connect_options, this->connect_options.conversion_operations),
203    connect_options(connect_options),
204    original_flags(connect_options.flags)
205  {}
206
207  const core::tConnectOptions& ConnectOptions() const
208  {
209    connect_options.flags = original_flags;
210    return connect_options;
211  }
212
213  const core::tConnectOptions& ConnectOptions(const core::tConnectionFlag direction_flag) const
214  {
215    connect_options.flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, direction_flag == core::tConnectionFlag::DIRECTION_TO_SOURCE);
216    connect_options.flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, direction_flag == core::tConnectionFlag::DIRECTION_TO_DESTINATION);
217    return connect_options;
218  }
219
220//----------------------------------------------------------------------
221// Private fields and methods
222//----------------------------------------------------------------------
223private:
224
225  /*!
226   * Applied connect operations
227   * Notably, the flags are only accessed within this file (with runtime structure lock).
228   * Therefore, they can be temporarily modified (avoiding all the overhead for copying options)
229   */
230  mutable core::tConnectOptions connect_options;
231  const core::tConnectionFlags original_flags;
232
233};
234
235bool CompiledConnectOptions(const rrlib::rtti::conversion::tConversionOperationSequence& options)
236{
237  bool raw = (options.Size() >= 1 && ((!options[0].second) || (options[0].second->Parameter() && options.GetParameterValue(0).GetType() != options[0].second->Parameter().GetType()))) ||
238             (options.Size() >= 2 && ((!options[1].second) || (options[1].second->Parameter() && options.GetParameterValue(1).GetType() != options[1].second->Parameter().GetType())));
239  return !raw;
240}
241
242}
243
244void tInterfaceBase::operator()(core::tAbstractPortCreationInfo& creation_info) const
245{
246  if ((!Backend()) || (Backend() && Backend()->convenience_port_type))
247  {
248    creation_info.flags |= tFlag::READY; // tComponent::cNO_PORT_NAME_BUILDER;
249  }
250  if (!Backend())
251  {
252    creation_info.flags |= tFlag::DELETED;
253    return;
254  }
255
256  creation_info.parent = &Backend()->primary_backend;
257
258  auto aggregator = GetAggregator(*creation_info.parent);
259  if (aggregator && aggregator->GetFlag(tFlag::INTERFACE))
260  {
261    creation_info.flags |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags();
262  }
263  const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw();
264  creation_info.flags |= core::tFrameworkElementFlags(creation_info.parent->GetAllFlags().Raw() & cRELEVANT_FLAGS);
265
266  if (Backend()->primary_backend.IsPartialInterface() && Backend()->primary_backend.PrimaryPortType() != tPrimaryPortType::ANY && Backend()->primary_backend.relation_backend_mapping.front().second == nullptr)
267  {
268    creation_info.flags |= tFlag::DELETED;
269  }
270  else if (creation_info.parent)
271  {
272    auto modifier = GetModifier(*creation_info.parent);
273    if (modifier)
274    {
275      modifier->Implementation().AdjustPortCreationInfo(creation_info);
276    }
277  }
278
279  return;
280}
281
282core::tConnector* tInterfaceBase::ConnectTo(const tInterfaceBase& partner, const core::tConnectOptions& connect_options)
283{
284  if (Backend() && partner.Backend())
285  {
286    for (auto this_backend : Backend()->relation_backend_mapping)
287    {
288      for (auto other_backend : partner.Backend()->primary_backend.relation_backend_mapping)
289      {
290        if (this_backend.second && other_backend.second && this_backend.first - Backend()->primary_relation_id == other_backend.first - partner.Backend()->primary_relation_id)
291        {
292          return this_backend.second->ConnectTo(*other_backend.second, connect_options);
293        }
294      }
295    }
296  }
297  return nullptr;
298}
299
300tInterfaceBase::tBackend* tInterfaceBase::CreateBackend(rrlib::rtti::tType interface_type, tInterfaceBase* parent, const std::string& name, tPrimaryPortType primary_port_type, const tConnectFunction& custom_connect_function, int primary_relation_id, bool convience_port_type)
301{
302  assert(parent);
303  if (parent->Backend() == nullptr)
304  {
305    return nullptr;
306  }
307  tBackend* parent_backend = parent->Backend()->GetBackend(primary_relation_id);
308  bool partial_interface = false;
309  assert(parent_backend || parent->Backend()->IsPartialInterface());
310  if (!parent_backend)
311  {
312    const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo());
313    interface_type = info.GetPartialType();
314    partial_interface = interface_type && primary_port_type != tPrimaryPortType::ANY;
315    if (partial_interface)
316    {
317      parent_backend = parent->Backend();
318    }
319  }
320  return parent_backend ? new tInterfaceBase::tBackend(interface_type, convience_port_type ? parent->ParentComponent() : parent->Backend(), parent_backend, primary_relation_id, name, convience_port_type, custom_connect_function, nullptr, parent->Backend()->PrimaryPortType(), partial_interface) : nullptr;
321}
322
323tInterfaceBase::tBackend* tInterfaceBase::CreateBackend(rrlib::rtti::tType interface_type, tInterfaceBase::tBackend* parent, const std::string& name, tPrimaryPortType primary_port_type, const tConnectFunction& custom_connect_function, int primary_relation_id, bool convience_port_type)
324{
325  const internal::tInterfaceTypeInfo& info = static_cast<const internal::tInterfaceTypeInfo&>(interface_type.SharedTypeInfo());
326  return parent ? new tInterfaceBase::tBackend(info.GetPartialType(), convience_port_type ? parent->parent_component : parent, parent, primary_relation_id, name, convience_port_type, custom_connect_function, nullptr, parent->PrimaryPortType(), true) : nullptr;
327}
328
329void tInterfaceBase::SetConfigEntry(const rrlib::uri::tPath& config_entry)
330{
331  uint interface_count = 0;
332  auto primary_backend = this->Backend();
333  if (primary_backend)
334  {
335    for (auto backend : primary_backend->primary_backend.all_backends)
336    {
337      auto aggregator = GetAggregator(*backend);
338      if (aggregator && (!aggregator->IsPort()) && aggregator->GetFlag(tFlag::INTERFACE) && aggregator->GetFlag(tFlag::PARAMETER_INTERFACE))
339      {
340        auto parameter_info = backend->GetAnnotation<parameters::internal::tParameterInfo>();
341        if (!parameter_info)
342        {
343          parameter_info = &backend->EmplaceAnnotation<parameters::internal::tParameterInfo>();
344        }
345        std::stringstream temp;  // Temporary solution until tParameterInfo class accepts paths
346        temp << config_entry;
347        parameter_info->SetConfigEntry(temp.str(), false);
348        interface_count++;
349      }
350    }
351    if (!interface_count)
352    {
353      FINROC_LOG_PRINT(WARNING, "No parameters backend in interface ", *primary_backend);
354    }
355  }
356  else
357  {
358    FINROC_LOG_PRINT(WARNING, "Called on empty interface wrapper");
359  }
360}
361
362
363tInterfaceBase::tBackend::tBackend(const rrlib::rtti::tType& interface_type, core::tFrameworkElement* parent_component, core::tFrameworkElement* parent, int primary_relation_id, const std::string& name, bool convenience_port_type, const tConnectFunction& custom_connect_function, tCreateMissingComponentInterfaceFunction create_missing_component_interface_function, tPrimaryPortType primary_port_type, bool partial_interface) :
364  tAbstractPort(MakeCreationInfo(interface_type, name, *parent, partial_interface || tScopedExtraConstructorParameters::Get()->partial_interface || ModifierDefinesPartialInterface(*parent, interface_type), tScopedExtraConstructorParameters::Get()->shared)),
365  parent_component(parent_component),
366  primary_backend(*this),
367  custom_connect_function(custom_connect_function),
368  convenience_port_type(convenience_port_type),
369  primary_relation_id(primary_relation_id),
370  create_missing_component_interface_function(create_missing_component_interface_function),
371  primary_port_type(primary_port_type),
372  partial_interface(static_cast<const internal::tInterfaceTypeInfo&>(GetDataType().SharedTypeInfo()).GetFullType() != GetDataType()),
373  partial_interface_primary_port_type(true)
374{
375  all_backends.emplace_back(this);
376  tBackend* primary_relation_backend = this;
377  if (this->partial_interface && primary_port_type != tPrimaryPortType::ANY)
378  {
379    auto aggregator = GetAggregator(*this);
380    auto partial_definition = ModifierDefinesPartialInterface(*aggregator, interface_type);
381    if (partial_definition != tPrimaryPortType::ANY)
382    {
383      this->partial_interface_primary_port_type = partial_definition == primary_port_type;
384    }
385    else
386    {
387      bool sensor_parent = (aggregator && (aggregator->GetFlag(tFlag::SENSOR_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::SENSOR_PORT));
388      bool controller_parent = (aggregator && (aggregator->GetFlag(tFlag::CONTROLLER_DATA) || partial_definition == tInterfaceBase::tPrimaryPortType::CONTROLLER_PORT));
389      if ((sensor_parent && primary_port_type == tPrimaryPortType::CONTROLLER_PORT) || (controller_parent && primary_port_type == tPrimaryPortType::SENSOR_PORT))
390      {
391        this->partial_interface_primary_port_type = false;
392      }
393    }
394    if (!this->partial_interface_primary_port_type)
395    {
396      primary_relation_backend = nullptr;
397    }
398  }
399  relation_backend_mapping.emplace_back(primary_relation_id, primary_relation_backend);
400}
401
402tInterfaceBase::tBackend::tBackend(core::tAbstractPortCreationInfo& creation_info, tBackend& primary) :
403  tAbstractPort(creation_info),
404  parent_component(primary.parent_component),
405  primary_backend(primary),
406  custom_connect_function(primary.custom_connect_function),
407  convenience_port_type(false),
408  primary_relation_id(primary.primary_relation_id),
409  create_missing_component_interface_function(nullptr),
410  primary_port_type(primary.primary_port_type),
411  partial_interface(primary.partial_interface),
412  partial_interface_primary_port_type(primary.partial_interface_primary_port_type)
413{
414}
415
416void tInterfaceBase::tBackend::ConnectChildPortsByName(tBackend& destination, const core::tConnectOptions& connect_options)
417{
418  if (!CompiledConnectOptions(connect_options.conversion_operations))
419  {
420    throw std::runtime_error("This function requires compiled connect options");
421  }
422
423  struct tPerSelectOperation
424  {
425    const internal::tPortSelectConversionOperation* operation = nullptr;
426    const utils::tPortSelector* selector = nullptr;
427  } select_operations[2];
428  size_t select_operation_count = 0;
429  bool nested_connect_options_differ = false;
430
431  struct tNestedOperation
432  {
433    const rrlib::rtti::conversion::tRegisteredConversionOperation* operation = nullptr;
434    size_t index = 0;
435  };
436  struct tNestedOperations
437  {
438    tNestedOperation operations[2];
439    size_t count = 0;
440
441    void Add(const tNestedOperation& op)
442    {
443      operations[count] = op;
444      count++;
445    }
446
447  } nested_operations_non_convertible, nested_operations_convertible;
448
449  for (size_t i = 0; i < connect_options.conversion_operations.Size(); i++)
450  {
451    tNestedOperation nested_operation;
452    nested_operation.operation = connect_options.conversion_operations[i].second;
453    nested_operation.index = i;
454    bool nested_operation_valid = true;
455    if (typeid(*connect_options.conversion_operations[i].second) == typeid(internal::tPortSelectConversionOperation))
456    {
457      tPerSelectOperation data;
458      data.operation = static_cast<const internal::tPortSelectConversionOperation*>(connect_options.conversion_operations[i].second);
459      data.selector = connect_options.conversion_operations.GetParameterValue(i).Get<utils::tPortSelector>();
460      select_operations[select_operation_count] = data;
461      select_operation_count++;
462
463      nested_connect_options_differ = data.operation->NestedVariant() != data.operation;
464      nested_operation_valid = data.operation->NestedVariant();
465    }
466    if (nested_operation_valid)
467    {
468      nested_operations_non_convertible.Add(nested_operation);
469      if (connect_options.conversion_operations[i].second != &cCONNECT_BY_NAME_OPERATION)
470      {
471        nested_operations_convertible.Add(nested_operation);
472      }
473    }
474  }
475
476  for (auto port = this->ChildPortsBegin(); port != this->ChildPortsEnd(); ++port)
477  {
478    auto other_port_element = destination.GetChild(port->GetName());
479    if (other_port_element && other_port_element->IsPort())
480    {
481      auto& other_port = static_cast<core::tAbstractPort&>(*other_port_element);
482
483      // Check whether to include port
484      bool skip = false;
485      for (size_t i = 0; i < select_operation_count; i++)
486      {
487        const tPerSelectOperation& data = select_operations[i];
488        if (!data.operation->NestedOnly())
489        {
490          if (data.operation->ExcludeOperation())
491          {
492            skip |= data.selector->Accepts(*port) || data.selector->Accepts(other_port);
493          }
494          else
495          {
496            skip |= (!data.selector->Accepts(*port)) && (!data.selector->Accepts(other_port));
497          }
498        }
499      }
500      if (skip)
501      {
502        continue;
503      }
504
505
506      if (port->GetDataType().GetTypeClassification() == rrlib::rtti::tTypeClassification::RPC_TYPE)
507      {
508        auto option_flags = connect_options.flags;
509        option_flags.Set(core::tConnectionFlag::DIRECTION_TO_SOURCE, false);
510        option_flags.Set(core::tConnectionFlag::DIRECTION_TO_DESTINATION, false);
511        port->ConnectTo(other_port, option_flags);
512      }
513      else
514      {
515        if (IsInterfaceType(port->GetDataType()))
516        {
517          bool convertible = port->GetDataType() == other_port.GetDataType() || IsDerivedFrom(port->GetDataType(), other_port.GetDataType()) || IsDerivedFrom(other_port.GetDataType(), port->GetDataType());
518          const tNestedOperations& operations = convertible ? nested_operations_convertible : nested_operations_non_convertible;
519          if ((!nested_connect_options_differ) && operations.count == connect_options.conversion_operations.Size())
520          {
521            port->ConnectTo(other_port, connect_options);
522          }
523          else
524          {
525            core::tConnectOptions nested_options(connect_options.flags);
526            if (operations.count)
527            {
528              nested_options.conversion_operations = operations.count == 1 ? rrlib::rtti::conversion::tConversionOperationSequence(*operations.operations[0].operation) : rrlib::rtti::conversion::tConversionOperationSequence(*operations.operations[0].operation, *operations.operations[1].operation);
529            }
530            for (size_t i = 0; i < operations.count; i++)
531            {
532              if (nested_options.conversion_operations[i].second->Parameter() && connect_options.conversion_operations.GetParameterValue(operations.operations[i].index))
533              {
534                nested_options.conversion_operations.SetParameterValue(i, connect_options.conversion_operations.GetParameterValue(operations.operations[i].index));
535              }
536            }
537            port->ConnectTo(other_port, nested_options);
538          }
539        }
540        else
541        {
542          port->ConnectTo(other_port, connect_options.flags);
543        }
544      }
545    }
546  }
547}
548
549core::tConnector* tInterfaceBase::tBackend::CreateConnector(core::tAbstractPort& destination, const core::tConnectOptions& connect_options)
550{
551  if (!(CompiledConnectOptions(connect_options.conversion_operations)))
552  {
553    assert(connect_options.conversion_operations.Size() >= 1);
554    const rrlib::rtti::conversion::tRegisteredConversionOperation* operations[2] = { nullptr, nullptr };
555
556    // Resolve ambiguous operations
557    for (size_t i = 0; i < connect_options.conversion_operations.Size(); i++)
558    {
559      auto operation = connect_options.conversion_operations[i];
560      if (operation.second)
561      {
562        operations[i] = operation.second;
563      }
564      else
565      {
566        auto& registered_operations = rrlib::rtti::conversion::tRegisteredConversionOperation::GetRegisteredOperations();
567        for (auto it = registered_operations.operations.Begin(); it != registered_operations.operations.End(); ++it)
568        {
569          if (strcmp((*it)->Name(), operation.first) == 0)
570          {
571            operations[i] = *it;
572            break;
573          }
574        }
575      }
576
577      if (!operations[i])
578      {
579        throw std::runtime_error(std::string("Operation lookup failed: ") + operation.first);
580      }
581    }
582
583    rrlib::rtti::conversion::tConversionOperationSequence conversion = connect_options.conversion_operations.Size() == 1 ? rrlib::rtti::conversion::tConversionOperationSequence(*operations[0]) : rrlib::rtti::conversion::tConversionOperationSequence(*operations[0], *operations[1], connect_options.conversion_operations.IntermediateType() ? connect_options.conversion_operations.IntermediateType() : destination.GetDataType());
584
585    // ############
586    // Convert any parameters provided as strings to their required types (see tConversionOperationSequence.cpp)
587    // ############
588    for (size_t i = 0; i < 2; i++)
589    {
590      const rrlib::rtti::conversion::tRegisteredConversionOperation* operation = operations[i];
591      if (operation && operation->Parameter() && connect_options.conversion_operations.GetParameterValue(i))
592      {
593        const rrlib::rtti::tTypedConstPointer& value = connect_options.conversion_operations.GetParameterValue(i);
594        if (value.GetType() == operation->Parameter().GetType())
595        {
596          conversion.SetParameterValue(i, value);
597        }
598        else if (value.GetType() == rrlib::rtti::tDataType<std::string>())
599        {
600          rrlib::serialization::tStringInputStream stream(*value.Get<std::string>());
601          auto buffer = operation->Parameter().GetType().CreateGenericObject();
602          buffer->Deserialize(stream);
603          conversion.SetParameterValue(i, *buffer);
604        }
605        else
606        {
607          throw std::runtime_error(std::string("Parameter ") + operation->Parameter().GetName() + " has invalid type");
608        }
609      }
610    }
611
612    return new tConversionConnector(*this, destination, core::tConnectOptions(conversion, connect_options.flags));
613  }
614  return new tConversionConnector(*this, destination, connect_options);
615}
616
617bool tInterfaceBase::tBackend::CreateOutputPort(int primary_relation_id)
618{
619  auto backend = GetBackend(primary_relation_id);
620  if (!backend)
621  {
622    return false;
623  }
624  auto component_interface = GetAggregator(*backend);
625  if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
626  {
627    return false;
628  }
629  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
630  {
631    int last_relation = primary_relation_id & 0xFF;
632    bool derived_from_backend_is_output = CreateOutputPort(primary_relation_id >> 8);
633    if (last_relation == internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT)
634    {
635      return !derived_from_backend_is_output;
636    }
637    else if (last_relation == internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT)
638    {
639      return derived_from_backend_is_output;
640    }
641  }
642  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS))
643  {
644    return true;
645  }
646  if (component_interface->GetFlag(tFlag::INTERFACE_FOR_INPUTS) || component_interface->GetFlag(tFlag::PARAMETER_INTERFACE))
647  {
648    return false;
649  }
650  throw std::runtime_error("Unspecified port direction");
651}
652
653core::tAbstractPort* tInterfaceBase::tBackend::CreatePort(const core::tAbstractPortCreationInfo& creation_info, int primary_relation_id) const
654{
655  auto modifier = GetModifier(*creation_info.parent);
656  return (modifier ? modifier->Implementation() : cMODIFIER_DEFAULT_IMPLEMENTATION).CreatePort(creation_info, primary_relation_id);
657}
658
659std::vector<tInterfaceBase> tInterfaceBase::FindInterfacesBelow(core::tFrameworkElement& parent, const rrlib::rtti::tType& type, bool skip_derived_interfaces)
660{
661  std::vector<tInterfaceBase> result;
662  if (type.GetTypeClassification() == rrlib::rtti::tTypeClassification::PORT_COMPOSITE_INTERFACE)
663  {
664    FindInterfacesBelowImplementation(result, parent, type, skip_derived_interfaces);
665  }
666  return result;
667}
668
669tInterfaceBase::tBackend* tInterfaceBase::tBackend::GetBackend(int primary_relation_id)
670{
671  if (&primary_backend != this)
672  {
673    return primary_backend.GetBackend(primary_relation_id);
674  }
675
676  for (auto & entry : relation_backend_mapping)
677  {
678    if (entry.first == primary_relation_id)
679    {
680      return entry.second;
681    }
682  }
683
684  core::tFrameworkElement* parent = nullptr;
685  bool do_not_create_primary_port_type = relation_backend_mapping.front().second == nullptr;
686  bool partial_interface_direction_is_output = GetAggregator(*this)->GetFlag(tFlag::INTERFACE_FOR_OUTPUTS);
687  bool partial_interface_primary_relation_direction_is_output = !partial_interface_direction_is_output;
688  bool backend_for_client_port = false;
689  if (GetParent() && typeid(*GetParent()).name() == typeid(tBackend).name())
690  {
691    parent = static_cast<tBackend&>(*GetParent()).GetBackend(primary_relation_id);
692  }
693  else if (core::tFrameworkElementTags::IsTagged(*this->GetParent(), cINTERFACE_TAG_SINGLE_BACKEND_INSTANTIATION))
694  {
695    parent = this->GetParent();
696  }
697  else if (this->partial_interface && (!IsPartOfPartialInstantiation(primary_relation_id, this->partial_interface_primary_port_type)))
698  {
699    parent = nullptr; // Skip
700  }
701  else
702  {
703    // Actually process relation
704    std::vector<int> relation_list;
705    tFrameworkElement* component_interface = this->GetParent();
706    int relation_id = primary_relation_id;
707    if ((!component_interface) || (!internal::IsComponent(component_interface->GetParent())))
708    {
709      FINROC_LOG_PRINT(WARNING, "Generic creation of port composite interfaces with multiple port types only works on components");
710      throw std::runtime_error("Generic creation of port composite interfaces with multiple port types only works on components");
711    }
712
713    const core::tFrameworkElementFlags relevant_flags = tFlag::SENSOR_DATA | tFlag::CONTROLLER_DATA | tFlag::INTERFACE_FOR_INPUTS | tFlag::INTERFACE_FOR_OUTPUTS | tFlag::PROXY_INTERFACE | tFlag::PARAMETER_INTERFACE;
714    tInterfaceModifier* interface_modifier = GetModifier(*component_interface);
715
716    // Compute opcode sequence
717    {
718      while (relation_id)
719      {
720        int opcode = relation_id & 0xFF;
721        relation_list.push_back(opcode);
722        relation_id = relation_id >> 8;
723      }
724      std::reverse(relation_list.begin(), relation_list.end());
725    }
726
727    tFrameworkElement* parent_candidate = do_not_create_primary_port_type ? nullptr : component_interface;
728    core::tFrameworkElementFlags use_these_original_flags;
729    if (do_not_create_primary_port_type)
730    {
731      assert(partial_interface && primary_port_type != tPrimaryPortType::ANY);
732      use_these_original_flags = tFlag::INTERFACE_FOR_DATA_PORTS | (primary_port_type == tPrimaryPortType::SENSOR_PORT ? tFlag::SENSOR_DATA : tFlag::CONTROLLER_DATA) | (partial_interface_primary_relation_direction_is_output ? tFlag::INTERFACE_FOR_OUTPUTS : tFlag::INTERFACE_FOR_INPUTS);
733      use_these_original_flags.Set(tFlag::PROXY_INTERFACE, component_interface->GetFlag(tFlag::PROXY_INTERFACE));
734    }
735
736    int remaining_relations = relation_list.size();
737    for (int opcode : relation_list)
738    {
739      remaining_relations--;
740      core::tFrameworkElementFlags original_flags = use_these_original_flags.Raw() ? use_these_original_flags : parent_candidate->GetAllFlags();
741      use_these_original_flags = core::tFrameworkElementFlags();
742      core::tFrameworkElementFlags target_set_flags = core::tFrameworkElementFlags(original_flags.Raw() & relevant_flags.Raw());
743      core::tFrameworkElementFlags target_unset_flags = core::tFrameworkElementFlags((~original_flags.Raw()) & relevant_flags.Raw());
744
745      typedef internal::tPortTypeRelation tOpCode;
746      switch (opcode)
747      {
748      case tOpCode::ePTR_COUNTER_PART:
749      case tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT:
750        if (original_flags.Get(tFlag::CONTROLLER_DATA) && (!original_flags.Get(tFlag::SENSOR_DATA)))
751        {
752          target_set_flags.Set(tFlag::SENSOR_DATA);
753          target_set_flags.Set(tFlag::CONTROLLER_DATA, false);
754          target_unset_flags.Set(tFlag::CONTROLLER_DATA);
755          target_unset_flags.Set(tFlag::SENSOR_DATA, false);
756        }
757        if (original_flags.Get(tFlag::SENSOR_DATA) && (!original_flags.Get(tFlag::CONTROLLER_DATA)))
758        {
759          target_set_flags.Set(tFlag::CONTROLLER_DATA);
760          target_set_flags.Set(tFlag::SENSOR_DATA, false);
761          target_unset_flags.Set(tFlag::SENSOR_DATA);
762          target_unset_flags.Set(tFlag::CONTROLLER_DATA, false);
763        }
764        if (original_flags.Get(tFlag::INTERFACE_FOR_INPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS)))
765        {
766          target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
767          target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
768          target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
769          target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
770          target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
771        }
772        if (original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS) && (!original_flags.Get(tFlag::INTERFACE_FOR_INPUTS)))
773        {
774          if (opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT)
775          {
776            target_set_flags = tFlag::PARAMETER_INTERFACE;
777            target_unset_flags = core::tFrameworkElementFlags();
778          }
779          else
780          {
781            target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
782            target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
783            target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
784            target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
785          }
786        }
787        break;
788      case internal::tPortTypeRelation::ePTR_INPUT:
789        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
790        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
791        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
792        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
793        break;
794      case internal::tPortTypeRelation::ePTR_OUTPUT:
795        target_set_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS);
796        target_set_flags.Set(tFlag::INTERFACE_FOR_INPUTS, false);
797        target_set_flags.Set(tFlag::PARAMETER_INTERFACE, false);
798        target_unset_flags.Set(tFlag::INTERFACE_FOR_INPUTS);
799        target_unset_flags.Set(tFlag::INTERFACE_FOR_OUTPUTS, false);
800        break;
801      case internal::tPortTypeRelation::ePTR_PARAMETER:
802        target_set_flags = tFlag::PARAMETER_INTERFACE;
803        target_unset_flags = core::tFrameworkElementFlags();
804        break;
805      case internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT:
806      case internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT:
807        backend_for_client_port = (remaining_relations == 0) && ((opcode == internal::tPortTypeRelation::ePTR_CLIENT_IF_INPUT && original_flags.Get(tFlag::INTERFACE_FOR_INPUTS)) || (opcode == internal::tPortTypeRelation::ePTR_SERVER_IF_INPUT && original_flags.Get(tFlag::INTERFACE_FOR_OUTPUTS)));
808        target_set_flags = tFlag::INTERFACE_FOR_RPC_PORTS;
809        target_unset_flags = (partial_interface && (!parent_candidate)) ? target_set_flags : core::tFrameworkElementFlags(); // With partially instantiated interfaces, create service ports if the port types they are derived from are also created
810        break;
811      default:
812        break;
813      }
814
815      core::tFrameworkElement* new_candidate = nullptr;
816      size_t candidate_name_length_difference = std::numeric_limits<size_t>::max();
817      auto component = component_interface->GetParent();
818      for (auto it = component->ChildrenBegin(); it != component->ChildrenEnd(); ++it)
819      {
820        if ((!it->IsPort()) && it->GetFlag(tFlag::INTERFACE) && (it->GetAllFlags().Raw() & target_set_flags.Raw()) == target_set_flags.Raw() && (it->GetAllFlags().Raw() & target_unset_flags.Raw()) == 0)
821        {
822          size_t name_length_difference = std::abs(static_cast<long>(component_interface->GetName().length()) - static_cast<long>(it->GetName().length()));
823          if (name_length_difference < candidate_name_length_difference)
824          {
825            new_candidate = &*it;
826            candidate_name_length_difference = name_length_difference;
827          }
828        }
829      }
830
831      if ((!new_candidate) && this->IsPartialInterface() && remaining_relations)
832      {
833        use_these_original_flags = target_set_flags;
834        parent_candidate = nullptr;
835        continue;
836      }
837
838      // Not-yet-created component interfaces - until there is a generic way to do this
839      if ((!new_candidate) && create_missing_component_interface_function)
840      {
841        new_candidate = (*create_missing_component_interface_function)(component_interface->GetParent(), target_set_flags);
842      }
843
844      if ((!new_candidate) && interface_modifier)
845      {
846        use_these_original_flags = target_set_flags;
847        parent_candidate = nullptr;
848        continue;
849      }
850
851      if (new_candidate)
852      {
853        component_interface = new_candidate;
854        parent_candidate = new_candidate;
855      }
856      else
857      {
858        std::stringstream message;
859        message << "Generic creation of port composite interface failed: No interface with relation " << make_builder::GetEnumString(static_cast<tOpCode>(opcode)) << " found below " << *component_interface->GetParent();
860        FINROC_LOG_PRINT(WARNING, message.str());
861        throw std::runtime_error(message.str());
862      }
863    }
864    assert(remaining_relations == 0);
865
866    parent = parent_candidate;
867    if (interface_modifier)
868    {
869      parent = interface_modifier->Implementation().GetComponentInterface(parent_candidate && parent_candidate->GetFlag(tFlag::INTERFACE) ? static_cast<core::tPortGroup*>(parent_candidate) : nullptr, primary_relation_id);
870    }
871  }
872
873  if (!parent)
874  {
875    relation_backend_mapping.emplace_back(primary_relation_id, nullptr);
876    return nullptr;
877  }
878
879  for (auto backend : all_backends)
880  {
881    if (backend->GetParent() == parent)
882    {
883      relation_backend_mapping.emplace_back(primary_relation_id, backend);
884      return backend;
885    }
886  }
887
888  // Create new backend below this parent
889  assert(parent != this->GetParent());
890  core::tAbstractPortCreationInfo secondary_creation_info;
891  secondary_creation_info.data_type = this->GetDataType();
892  secondary_creation_info.name = GetName();
893  secondary_creation_info.parent = parent;
894  secondary_creation_info.flags = core::tFrameworkElementFlags(tFlag::INTERFACE);
895  auto aggregator = GetAggregator(*parent, &secondary_creation_info.flags);
896  if (backend_for_client_port && aggregator->GetFlag(tFlag::INTERFACE_FOR_RPC_PORTS))
897  {
898    secondary_creation_info.flags.Set(tFlag::OUTPUT_PORT, backend_for_client_port);
899  }
900  if (this->GetFlag(tFlag::SHARED))
901  {
902    secondary_creation_info.flags |= tFlag::SHARED;
903  }
904  all_backends.push_back(new tBackend(secondary_creation_info, *this));
905  relation_backend_mapping.emplace_back(primary_relation_id, all_backends.back());
906  return all_backends.back();
907}
908
909core::tFrameworkElementFlags tInterfaceBase::tBackend::GetDefaultPortFlags(bool generic_port_backend) const
910{
911  core::tFrameworkElementFlags result;
912  if (generic_port_backend)
913  {
914    GetAggregator(*this, &result);
915  }
916  else
917  {
918    auto aggregator = GetAggregator(*this);
919    if (aggregator && aggregator->GetFlag(tFlag::INTERFACE))
920    {
921      if (aggregator->GetFlag(tFlag::PROXY_INTERFACE))
922      {
923        result |= (tFlag::ACCEPTS_DATA | tFlag::EMITS_DATA | tFlag::PUSH_STRATEGY);
924      }
925      result |= static_cast<const core::tPortGroup&>(*aggregator).GetDefaultPortFlags();
926    }
927  }
928  const int cRELEVANT_FLAGS = (tFlag::SHARED | tFlag::SENSOR_DATA_PORT | tFlag::CONTROLLER_DATA_PORT).Raw();
929  result |= core::tFrameworkElementFlags(this->GetAllFlags().Raw() & cRELEVANT_FLAGS);
930  return result;
931}
932
933bool tInterfaceBase::tBackend::IsPartOfPartialInstantiation(int primary_relation_id, bool partial_instantiation_variant_primary_port_type)
934{
935  typedef internal::tPortTypeRelation tOpCode;
936  int switch_count = 0;
937  while (primary_relation_id)
938  {
939    int opcode = primary_relation_id & 0xFF;
940    switch_count += ((opcode == tOpCode::ePTR_COUNTER_PART || opcode == tOpCode::ePTR_COUNTER_PART_PARAMETER_IF_INPUT) ? 1 : 0);
941    primary_relation_id = primary_relation_id >> 8;
942  }
943  bool primary_port_type_relation_id = (switch_count % 2) == 0;
944  return primary_port_type_relation_id == partial_instantiation_variant_primary_port_type;
945}
946
947void tInterfaceBase::tBackend::OnConnect(tAbstractPort& partner, bool partner_is_destination)
948{
949  if (primary_backend.operation_on_all_elements_pending)
950  {
951    return;
952  }
953
954  tBackend& other = static_cast<tBackend&>(partner);
955  bool connect_all_backends = this->IsPrimaryBackend() && other.IsPrimaryBackend();
956
957  // Are any conversion operations set?
958  const tConversionConnector* conversion_connector = nullptr;
959  {
960    if (partner_is_destination)
961    {
962      for (auto it = this->OutgoingConnectionsBegin(); it != this->OutgoingConnectionsEnd(); ++it)
963      {
964        if (&it->Destination() == &partner && typeid(*it) == typeid(tConversionConnector))
965        {
966          conversion_connector = &static_cast<const tConversionConnector&>(*it);
967          break;
968        }
969      }
970    }
971    else
972    {
973      for (auto it = this->IncomingConnectionsBegin(); it != this->IncomingConnectionsEnd(); ++it)
974      {
975        if (&it->Source() == &partner && typeid(*it) == typeid(tConversionConnector))
976        {
977          conversion_connector = &static_cast<const tConversionConnector&>(*it);
978          break;
979        }
980      }
981    }
982  }
983
984  primary_backend.operation_on_all_elements_pending = true;
985  try
986  {
987    if (!conversion_connector)
988    {
989      throw std::runtime_error("Invalid connector type");
990    }
991
992    if (primary_backend.custom_connect_function)
993    {
994      if (partner_is_destination)
995      {
996        primary_backend.custom_connect_function(*this, other, conversion_connector->ConnectOptions());
997      }
998      else
999      {
1000        primary_backend.custom_connect_function(other, *this, conversion_connector->ConnectOptions());
1001      }
1002      primary_backend.operation_on_all_elements_pending = false;
1003      return;
1004    }
1005
1006    // Connect all matching backends and ports
1007    for (auto this_backend : primary_backend.relation_backend_mapping)
1008    {
1009      for (auto other_backend : other.primary_backend.primary_backend.relation_backend_mapping)
1010      {
1011        if (this_backend.second && other_backend.second && this_backend.first - primary_backend.primary_relation_id == other_backend.first - other.primary_backend.primary_relation_id && (connect_all_backends || this_backend.second == this || other_backend.second == &other))
1012        {
1013          core::tConnectionFlag direction = (this->IsOutputPort() == this_backend.second->IsOutputPort() ? partner_is_destination : (!partner_is_destination)) ? core::tConnectionFlag::DIRECTION_TO_DESTINATION : core::tConnectionFlag::DIRECTION_TO_SOURCE;
1014          this_backend.second->ConnectTo(*other_backend.second, conversion_connector->ConnectOptions(direction));
1015          this_backend.second->ConnectChildPortsByName(*other_backend.second, conversion_connector->ConnectOptions(direction));
1016        }
1017      }
1018    }
1019  }
1020  catch (const std::exception& e)
1021  {
1022    FINROC_LOG_PRINT(WARNING, "Connecting failed: ", e);
1023  }
1024  primary_backend.operation_on_all_elements_pending = false;
1025}
1026
1027void tInterfaceBase::tBackend::OnDisconnect(tAbstractPort& partner, bool partner_is_destination)
1028{
1029  bool& pending = primary_backend.primary_backend.operation_on_all_elements_pending;
1030  tBackend& other = static_cast<tBackend&>(partner).primary_backend;
1031  if (pending || other.operation_on_all_elements_pending || partner_is_destination)
1032  {
1033    return;
1034  }
1035
1036  pending = true;
1037  try
1038  {
1039    // Update other backend connection info
1040    for (auto this_backend : this->primary_backend.all_backends)
1041    {
1042      for (auto other_backend : other.primary_backend.all_backends)
1043      {
1044        this_backend->DisconnectFrom(*other_backend);
1045      }
1046    }
1047
1048    // Disconnect all ports to partner backends (this should also cover cases with custom connect function)
1049    for (auto backend : primary_backend.all_backends)
1050    {
1051      for (auto port = backend->ChildPortsBegin(); port != backend->ChildPortsEnd(); ++port)
1052      {
1053        for (auto partner = port->IncomingConnectionsBegin(); partner != port->IncomingConnectionsEnd(); ++partner)
1054        {
1055          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Source().GetParent()))
1056          {
1057            port->DisconnectFrom(partner->Source());
1058          }
1059        }
1060        for (auto partner = port->OutgoingConnectionsBegin(); partner != port->OutgoingConnectionsEnd(); ++partner)
1061        {
1062          if (std::count(other.all_backends.begin(), other.all_backends.end(), partner->Destination().GetParent()))
1063          {
1064            port->DisconnectFrom(partner->Destination());
1065          }
1066        }
1067      }
1068    }
1069  }
1070  catch (const std::exception& e)
1071  {
1072    FINROC_LOG_PRINT(WARNING, "Disconnecting failed: ", e);
1073  }
1074  pending = false;
1075}
1076
1077void tInterfaceBase::tBackend::OnInitialization()
1078{
1079  bool& pending = primary_backend.operation_on_all_elements_pending;
1080  if (!pending)
1081  {
1082    pending = true;
1083    for (auto backend : primary_backend.all_backends)
1084    {
1085      if (backend != this)
1086      {
1087        backend->Init();
1088      }
1089    }
1090    pending = false;
1091  }
1092}
1093
1094void tInterfaceBase::tBackend::OnManagedDelete()
1095{
1096  rrlib::thread::tLock lock1(GetStructureMutex());
1097
1098  if (!core::tRuntimeEnvironment::ShuttingDown())
1099  {
1100    bool& pending = primary_backend.operation_on_all_elements_pending;
1101    if (!pending)
1102    {
1103      pending = true;
1104      for (auto backend : primary_backend.all_backends)
1105      {
1106        if (backend != this)
1107        {
1108          backend->ManagedDelete();
1109        }
1110      }
1111      pending = false;
1112    }
1113  }
1114
1115  tAbstractPort::OnManagedDelete();
1116}
1117
1118tInterfaceBase::tScopedExtraConstructorParameters tInterfaceBase::tScopedExtraConstructorParameters::Get()
1119{
1120  static tExtraConstructorParameters parameters;
1121  return tScopedExtraConstructorParameters(core::tRuntimeEnvironment::GetInstance().GetStructureMutex(), &parameters);  //
1122}
1123
1124void tInterfaceBase::tSecondaryPortModifier::operator()(core::tAbstractPortCreationInfo& creation_info) const
1125{
1126  creation_info.name = name;
1127  creation_info.parent = &backend;
1128  creation_info.flags |= backend.GetDefaultPortFlags(false);
1129
1130  {
1131    auto modifier = GetModifier(backend);
1132    if (modifier)
1133    {
1134      modifier->Implementation().AdjustPortCreationInfo(creation_info);
1135    }
1136  }
1137}
1138
1139//----------------------------------------------------------------------
1140// End of namespace declaration
1141//----------------------------------------------------------------------
1142}
1143}
Note: See TracBrowser for help on using the repository browser.